mirror of
https://github.com/github/codeql.git
synced 2026-04-25 08:45:14 +02:00
Merge branch 'main' into badfilter
This commit is contained in:
29
.github/workflows/check-implicit-this.yml
vendored
Normal file
29
.github/workflows/check-implicit-this.yml
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
name: "Check implicit this warnings"
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
pull_request:
|
||||
paths:
|
||||
- "**qlpack.yml"
|
||||
branches:
|
||||
- main
|
||||
- "rc/*"
|
||||
|
||||
jobs:
|
||||
check:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Check that implicit this warnings is enabled for all packs
|
||||
shell: bash
|
||||
run: |
|
||||
EXIT_CODE=0
|
||||
packs="$(find . -iname 'qlpack.yml')"
|
||||
for pack_file in ${packs}; do
|
||||
option="$(yq '.warnOnImplicitThis' ${pack_file})"
|
||||
if [ "${option}" != "true" ]; then
|
||||
echo "::error file=${pack_file}::warnOnImplicitThis property must be set to 'true' for pack ${pack_file}"
|
||||
EXIT_CODE=1
|
||||
fi
|
||||
done
|
||||
exit "${EXIT_CODE}"
|
||||
@@ -5,9 +5,9 @@ repos:
|
||||
rev: v3.2.0
|
||||
hooks:
|
||||
- id: trailing-whitespace
|
||||
exclude: /test/.*$(?<!\.ql)(?<!\.qll)(?<!\.qlref)
|
||||
exclude: /test/.*$(?<!\.ql)(?<!\.qll)(?<!\.qlref)|.*\.patch
|
||||
- id: end-of-file-fixer
|
||||
exclude: /test/.*$(?<!\.ql)(?<!\.qll)(?<!\.qlref)
|
||||
exclude: /test/.*$(?<!\.ql)(?<!\.qll)(?<!\.qlref)|.*\.patch
|
||||
|
||||
- repo: https://github.com/pre-commit/mirrors-clang-format
|
||||
rev: v13.0.1
|
||||
@@ -21,6 +21,11 @@ repos:
|
||||
- id: autopep8
|
||||
files: ^misc/codegen/.*\.py
|
||||
|
||||
- repo: https://github.com/warchant/pre-commit-buildifier
|
||||
rev: 0.0.2
|
||||
hooks:
|
||||
- id: buildifier
|
||||
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: codeql-format
|
||||
|
||||
@@ -14,14 +14,16 @@ If you have an idea for a query that you would like to share with other CodeQL u
|
||||
|
||||
1. **Directory structure**
|
||||
|
||||
There are six language-specific query directories in this repository:
|
||||
There are eight language-specific query directories in this repository:
|
||||
|
||||
* C/C++: `cpp/ql/src`
|
||||
* C#: `csharp/ql/src`
|
||||
* Java: `java/ql/src`
|
||||
* Go: `go/ql/src`
|
||||
* Java/Kotlin: `java/ql/src`
|
||||
* JavaScript: `javascript/ql/src`
|
||||
* Python: `python/ql/src`
|
||||
* Ruby: `ruby/ql/src`
|
||||
* Swift: `swift/ql/src`
|
||||
|
||||
Each language-specific directory contains further subdirectories that group queries based on their `@tags` or purpose.
|
||||
- Experimental queries and libraries are stored in the `experimental` subdirectory within each language-specific directory in the [CodeQL repository](https://github.com/github/codeql). For example, experimental Java queries and libraries are stored in `java/ql/src/experimental` and any corresponding tests in `java/ql/test/experimental`.
|
||||
|
||||
@@ -2,3 +2,4 @@ name: codeql/cpp-downgrades
|
||||
groups: cpp
|
||||
downgrades: .
|
||||
library: true
|
||||
warnOnImplicitThis: true
|
||||
|
||||
@@ -4,3 +4,4 @@ groups:
|
||||
- examples
|
||||
dependencies:
|
||||
codeql/cpp-all: ${workspace}
|
||||
warnOnImplicitThis: true
|
||||
|
||||
@@ -1,3 +1,17 @@
|
||||
## 0.8.0
|
||||
|
||||
### New Features
|
||||
|
||||
* The `ProductFlow::StateConfigSig` signature now includes default predicates for `isBarrier1`, `isBarrier2`, `isAdditionalFlowStep1`, and `isAdditionalFlowStep1`. Hence, it is no longer needed to provide `none()` implementations of these predicates if they are not needed.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Deleted the deprecated `getURL` predicate from the `Container`, `Folder`, and `File` classes. Use the `getLocation` predicate instead.
|
||||
|
||||
## 0.7.4
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.7.3
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Deleted the deprecated `getURL` predicate from the `Container`, `Folder`, and `File` classes. Use the `getLocation` predicate instead.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: deprecated
|
||||
---
|
||||
* The library `semmle.code.cpp.dataflow.DataFlow` has been deprecated. Please use `semmle.code.cpp.dataflow.new.DataFlow` instead.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The `IRGuards` library has improved handling of pointer addition and subtraction operations.
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
category: feature
|
||||
---
|
||||
* The `DataFlow::StateConfigSig` signature module has gained default implementations for `isBarrier/2` and `isAdditionalFlowStep/4`.
|
||||
Hence it is no longer needed to provide `none()` implementations of these predicates if they are not needed.
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Data flow configurations can now include a predicate `neverSkip(Node node)`
|
||||
in order to ensure inclusion of certain nodes in the path explanations. The
|
||||
predicate defaults to the end-points of the additional flow steps provided in
|
||||
the configuration, which means that such steps now always are visible by
|
||||
default in path explanations.
|
||||
3
cpp/ql/lib/change-notes/released/0.7.4.md
Normal file
3
cpp/ql/lib/change-notes/released/0.7.4.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.7.4
|
||||
|
||||
No user-facing changes.
|
||||
9
cpp/ql/lib/change-notes/released/0.8.0.md
Normal file
9
cpp/ql/lib/change-notes/released/0.8.0.md
Normal file
@@ -0,0 +1,9 @@
|
||||
## 0.8.0
|
||||
|
||||
### New Features
|
||||
|
||||
* The `ProductFlow::StateConfigSig` signature now includes default predicates for `isBarrier1`, `isBarrier2`, `isAdditionalFlowStep1`, and `isAdditionalFlowStep1`. Hence, it is no longer needed to provide `none()` implementations of these predicates if they are not needed.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Deleted the deprecated `getURL` predicate from the `Container`, `Folder`, and `File` classes. Use the `getLocation` predicate instead.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.7.3
|
||||
lastReleaseVersion: 0.8.0
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-all
|
||||
version: 0.7.4-dev
|
||||
version: 0.8.1-dev
|
||||
groups: cpp
|
||||
dbscheme: semmlecode.cpp.dbscheme
|
||||
extractor: cpp
|
||||
|
||||
@@ -741,6 +741,8 @@ private predicate namedExprChildPredicates(Expr expr, Element ele, string pred)
|
||||
or
|
||||
expr.(VariableAccess).getQualifier() = ele and pred = "getQualifier()"
|
||||
or
|
||||
expr.(FunctionAccess).getQualifier() = ele and pred = "getQualifier()"
|
||||
or
|
||||
exists(Field f |
|
||||
expr.(ClassAggregateLiteral).getAFieldExpr(f) = ele and
|
||||
pred = "getAFieldExpr(" + f.toString() + ")"
|
||||
|
||||
@@ -627,6 +627,20 @@ private predicate sub_lt(
|
||||
x = int_value(rhs.getRight()) and
|
||||
k = c - x
|
||||
)
|
||||
or
|
||||
exists(PointerSubInstruction lhs, int c, int x |
|
||||
compares_lt(cmp, lhs.getAUse(), right, c, isLt, testIsTrue) and
|
||||
left = lhs.getLeftOperand() and
|
||||
x = int_value(lhs.getRight()) and
|
||||
k = c + x
|
||||
)
|
||||
or
|
||||
exists(PointerSubInstruction rhs, int c, int x |
|
||||
compares_lt(cmp, left, rhs.getAUse(), c, isLt, testIsTrue) and
|
||||
right = rhs.getLeftOperand() and
|
||||
x = int_value(rhs.getRight()) and
|
||||
k = c - x
|
||||
)
|
||||
}
|
||||
|
||||
// left + x < right + c => left < right + (c-x)
|
||||
@@ -653,6 +667,26 @@ private predicate add_lt(
|
||||
) and
|
||||
k = c + x
|
||||
)
|
||||
or
|
||||
exists(PointerAddInstruction lhs, int c, int x |
|
||||
compares_lt(cmp, lhs.getAUse(), right, c, isLt, testIsTrue) and
|
||||
(
|
||||
left = lhs.getLeftOperand() and x = int_value(lhs.getRight())
|
||||
or
|
||||
left = lhs.getRightOperand() and x = int_value(lhs.getLeft())
|
||||
) and
|
||||
k = c - x
|
||||
)
|
||||
or
|
||||
exists(PointerAddInstruction rhs, int c, int x |
|
||||
compares_lt(cmp, left, rhs.getAUse(), c, isLt, testIsTrue) and
|
||||
(
|
||||
right = rhs.getLeftOperand() and x = int_value(rhs.getRight())
|
||||
or
|
||||
right = rhs.getRightOperand() and x = int_value(rhs.getLeft())
|
||||
) and
|
||||
k = c + x
|
||||
)
|
||||
}
|
||||
|
||||
// left - x == right + c => left == right + (c+x)
|
||||
@@ -673,6 +707,20 @@ private predicate sub_eq(
|
||||
x = int_value(rhs.getRight()) and
|
||||
k = c - x
|
||||
)
|
||||
or
|
||||
exists(PointerSubInstruction lhs, int c, int x |
|
||||
compares_eq(cmp, lhs.getAUse(), right, c, areEqual, testIsTrue) and
|
||||
left = lhs.getLeftOperand() and
|
||||
x = int_value(lhs.getRight()) and
|
||||
k = c + x
|
||||
)
|
||||
or
|
||||
exists(PointerSubInstruction rhs, int c, int x |
|
||||
compares_eq(cmp, left, rhs.getAUse(), c, areEqual, testIsTrue) and
|
||||
right = rhs.getLeftOperand() and
|
||||
x = int_value(rhs.getRight()) and
|
||||
k = c - x
|
||||
)
|
||||
}
|
||||
|
||||
// left + x == right + c => left == right + (c-x)
|
||||
@@ -699,6 +747,26 @@ private predicate add_eq(
|
||||
) and
|
||||
k = c + x
|
||||
)
|
||||
or
|
||||
exists(PointerAddInstruction lhs, int c, int x |
|
||||
compares_eq(cmp, lhs.getAUse(), right, c, areEqual, testIsTrue) and
|
||||
(
|
||||
left = lhs.getLeftOperand() and x = int_value(lhs.getRight())
|
||||
or
|
||||
left = lhs.getRightOperand() and x = int_value(lhs.getLeft())
|
||||
) and
|
||||
k = c - x
|
||||
)
|
||||
or
|
||||
exists(PointerAddInstruction rhs, int c, int x |
|
||||
compares_eq(cmp, left, rhs.getAUse(), c, areEqual, testIsTrue) and
|
||||
(
|
||||
right = rhs.getLeftOperand() and x = int_value(rhs.getRight())
|
||||
or
|
||||
right = rhs.getRightOperand() and x = int_value(rhs.getLeft())
|
||||
) and
|
||||
k = c + x
|
||||
)
|
||||
}
|
||||
|
||||
/** The int value of integer constant expression. */
|
||||
|
||||
@@ -20,10 +20,12 @@
|
||||
import cpp
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `semmle.code.cpp.dataflow.new.DataFlow` instead.
|
||||
*
|
||||
* Provides classes for performing local (intra-procedural) and
|
||||
* global (inter-procedural) data flow analyses.
|
||||
*/
|
||||
module DataFlow {
|
||||
deprecated module DataFlow {
|
||||
import semmle.code.cpp.dataflow.internal.DataFlow
|
||||
import semmle.code.cpp.dataflow.internal.DataFlowImpl1
|
||||
}
|
||||
|
||||
@@ -12,9 +12,11 @@
|
||||
import cpp
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `semmle.code.cpp.dataflow.new.DataFlow2` instead.
|
||||
*
|
||||
* Provides classes for performing local (intra-procedural) and
|
||||
* global (inter-procedural) data flow analyses.
|
||||
*/
|
||||
module DataFlow2 {
|
||||
deprecated module DataFlow2 {
|
||||
import semmle.code.cpp.dataflow.internal.DataFlowImpl2
|
||||
}
|
||||
|
||||
@@ -12,9 +12,11 @@
|
||||
import cpp
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `semmle.code.cpp.dataflow.new.DataFlow3` instead.
|
||||
*
|
||||
* Provides classes for performing local (intra-procedural) and
|
||||
* global (inter-procedural) data flow analyses.
|
||||
*/
|
||||
module DataFlow3 {
|
||||
deprecated module DataFlow3 {
|
||||
import semmle.code.cpp.dataflow.internal.DataFlowImpl3
|
||||
}
|
||||
|
||||
@@ -12,9 +12,11 @@
|
||||
import cpp
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `semmle.code.cpp.dataflow.new.DataFlow4` instead.
|
||||
*
|
||||
* Provides classes for performing local (intra-procedural) and
|
||||
* global (inter-procedural) data flow analyses.
|
||||
*/
|
||||
module DataFlow4 {
|
||||
deprecated module DataFlow4 {
|
||||
import semmle.code.cpp.dataflow.internal.DataFlowImpl4
|
||||
}
|
||||
|
||||
@@ -19,10 +19,12 @@ import semmle.code.cpp.dataflow.DataFlow
|
||||
import semmle.code.cpp.dataflow.DataFlow2
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `semmle.code.cpp.dataflow.new.TaintTracking` instead.
|
||||
*
|
||||
* Provides classes for performing local (intra-procedural) and
|
||||
* global (inter-procedural) taint-tracking analyses.
|
||||
*/
|
||||
module TaintTracking {
|
||||
deprecated module TaintTracking {
|
||||
import semmle.code.cpp.dataflow.internal.tainttracking1.TaintTracking
|
||||
import semmle.code.cpp.dataflow.internal.tainttracking1.TaintTrackingImpl
|
||||
}
|
||||
|
||||
@@ -12,9 +12,11 @@
|
||||
*/
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `semmle.code.cpp.dataflow.new.TaintTracking2` instead.
|
||||
*
|
||||
* Provides classes for performing local (intra-procedural) and
|
||||
* global (inter-procedural) taint-tracking analyses.
|
||||
*/
|
||||
module TaintTracking2 {
|
||||
deprecated module TaintTracking2 {
|
||||
import semmle.code.cpp.dataflow.internal.tainttracking2.TaintTrackingImpl
|
||||
}
|
||||
|
||||
@@ -46,6 +46,14 @@ signature module ConfigSig {
|
||||
*/
|
||||
default predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `node` should never be skipped over in the `PathGraph` and in path
|
||||
* explanations.
|
||||
*/
|
||||
default predicate neverSkip(Node node) {
|
||||
isAdditionalFlowStep(node, _) or isAdditionalFlowStep(_, node)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||
* This can be overridden to a smaller value to improve performance (a
|
||||
@@ -114,7 +122,7 @@ signature module StateConfigSig {
|
||||
* Holds if data flow through `node` is prohibited when the flow state is
|
||||
* `state`.
|
||||
*/
|
||||
predicate isBarrier(Node node, FlowState state);
|
||||
default predicate isBarrier(Node node, FlowState state) { none() }
|
||||
|
||||
/** Holds if data flow into `node` is prohibited. */
|
||||
default predicate isBarrierIn(Node node) { none() }
|
||||
@@ -131,7 +139,9 @@ signature module StateConfigSig {
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
||||
*/
|
||||
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2);
|
||||
default predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||
@@ -139,6 +149,17 @@ signature module StateConfigSig {
|
||||
*/
|
||||
default predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `node` should never be skipped over in the `PathGraph` and in path
|
||||
* explanations.
|
||||
*/
|
||||
default predicate neverSkip(Node node) {
|
||||
isAdditionalFlowStep(node, _) or
|
||||
isAdditionalFlowStep(_, node) or
|
||||
isAdditionalFlowStep(node, _, _, _) or
|
||||
isAdditionalFlowStep(_, _, node, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||
* This can be overridden to a smaller value to improve performance (a
|
||||
|
||||
@@ -66,6 +66,12 @@ signature module FullStateConfigSig {
|
||||
*/
|
||||
predicate allowImplicitRead(Node node, ContentSet c);
|
||||
|
||||
/**
|
||||
* Holds if `node` should never be skipped over in the `PathGraph` and in path
|
||||
* explanations.
|
||||
*/
|
||||
predicate neverSkip(Node node);
|
||||
|
||||
/**
|
||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||
* This can be overridden to a smaller value to improve performance (a
|
||||
@@ -254,6 +260,11 @@ module Impl<FullStateConfigSig Config> {
|
||||
not fullBarrier(node2)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate isUnreachableInCall1(NodeEx n, LocalCallContextSpecificCall cc) {
|
||||
isUnreachableInCallCached(n.asNode(), cc.getCall())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow in one local step from `node1` to `node2`.
|
||||
*/
|
||||
@@ -460,7 +471,6 @@ module Impl<FullStateConfigSig Config> {
|
||||
* The Boolean `cc` records whether the node is reached through an
|
||||
* argument in a call.
|
||||
*/
|
||||
pragma[assume_small_delta]
|
||||
private predicate fwdFlow(NodeEx node, Cc cc) {
|
||||
sourceNode(node, _) and
|
||||
if hasSourceCallCtx() then cc = true else cc = false
|
||||
@@ -570,7 +580,6 @@ module Impl<FullStateConfigSig Config> {
|
||||
/**
|
||||
* Holds if `c` is the target of a store in the flow covered by `fwdFlow`.
|
||||
*/
|
||||
pragma[assume_small_delta]
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowConsCand(Content c) {
|
||||
exists(NodeEx mid, NodeEx node |
|
||||
@@ -1216,7 +1225,6 @@ module Impl<FullStateConfigSig Config> {
|
||||
fwdFlow1(_, _, _, _, _, _, t0, t, ap, _) and t0 != t
|
||||
}
|
||||
|
||||
pragma[assume_small_delta]
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlow0(
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT,
|
||||
@@ -2022,7 +2030,8 @@ module Impl<FullStateConfigSig Config> {
|
||||
castNode(this.asNode()) or
|
||||
clearsContentCached(this.asNode(), _) or
|
||||
expectsContentCached(this.asNode(), _) or
|
||||
neverSkipInPathGraph(this.asNode())
|
||||
neverSkipInPathGraph(this.asNode()) or
|
||||
Config::neverSkip(this.asNode())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2111,7 +2120,7 @@ module Impl<FullStateConfigSig Config> {
|
||||
NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t,
|
||||
LocalCallContext cc
|
||||
) {
|
||||
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
not isUnreachableInCall1(node2, cc) and
|
||||
(
|
||||
localFlowEntry(node1, pragma[only_bind_into](state)) and
|
||||
(
|
||||
@@ -2126,7 +2135,7 @@ module Impl<FullStateConfigSig Config> {
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall())
|
||||
not isUnreachableInCall1(node1, cc)
|
||||
or
|
||||
exists(NodeEx mid |
|
||||
localFlowStepPlus(node1, pragma[only_bind_into](state), mid, preservesValue, t, cc) and
|
||||
@@ -2163,10 +2172,8 @@ module Impl<FullStateConfigSig Config> {
|
||||
preservesValue = false and
|
||||
t = node2.getDataFlowType() and
|
||||
callContext.relevantFor(node1.getEnclosingCallable()) and
|
||||
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
|
||||
isUnreachableInCallCached(node1.asNode(), call) or
|
||||
isUnreachableInCallCached(node2.asNode(), call)
|
||||
)
|
||||
not isUnreachableInCall1(node1, callContext) and
|
||||
not isUnreachableInCall1(node2, callContext)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2706,7 +2713,7 @@ module Impl<FullStateConfigSig Config> {
|
||||
|
||||
ParamNodeEx getParamNode() { result = p }
|
||||
|
||||
override string toString() { result = p + ": " + ap }
|
||||
override string toString() { result = p + concat(" : " + ppReprType(t)) + " " + ap }
|
||||
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
@@ -2758,12 +2765,21 @@ module Impl<FullStateConfigSig Config> {
|
||||
)
|
||||
}
|
||||
|
||||
private predicate forceUnfold(AccessPathApprox apa) {
|
||||
forceHighPrecision(apa.getHead())
|
||||
or
|
||||
exists(Content c2 |
|
||||
apa = TConsCons(_, _, c2, _) and
|
||||
forceHighPrecision(c2)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds with `unfold = false` if a precise head-tail representation of `apa` is
|
||||
* expected to be expensive. Holds with `unfold = true` otherwise.
|
||||
*/
|
||||
private predicate evalUnfold(AccessPathApprox apa, boolean unfold) {
|
||||
if forceHighPrecision(apa.getHead())
|
||||
if forceUnfold(apa)
|
||||
then unfold = true
|
||||
else
|
||||
exists(int aps, int nodes, int apLimit, int tupleLimit |
|
||||
@@ -2777,7 +2793,6 @@ module Impl<FullStateConfigSig Config> {
|
||||
/**
|
||||
* Gets the number of `AccessPath`s that correspond to `apa`.
|
||||
*/
|
||||
pragma[assume_small_delta]
|
||||
private int countAps(AccessPathApprox apa) {
|
||||
evalUnfold(apa, false) and
|
||||
result = 1 and
|
||||
@@ -2796,7 +2811,6 @@ module Impl<FullStateConfigSig Config> {
|
||||
* that it is expanded to a precise head-tail representation.
|
||||
*/
|
||||
language[monotonicAggregates]
|
||||
pragma[assume_small_delta]
|
||||
private int countPotentialAps(AccessPathApprox apa) {
|
||||
apa instanceof AccessPathApproxNil and result = 1
|
||||
or
|
||||
@@ -2833,7 +2847,6 @@ module Impl<FullStateConfigSig Config> {
|
||||
}
|
||||
|
||||
private newtype TPathNode =
|
||||
pragma[assume_small_delta]
|
||||
TPathNodeMid(
|
||||
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, DataFlowType t, AccessPath ap
|
||||
) {
|
||||
@@ -2918,7 +2931,6 @@ module Impl<FullStateConfigSig Config> {
|
||||
|
||||
override AccessPathFrontHead getFront() { result = TFrontHead(head_) }
|
||||
|
||||
pragma[assume_small_delta]
|
||||
override AccessPathApproxCons getApprox() {
|
||||
result = TConsNil(head_, t) and tail_ = TAccessPathNil()
|
||||
or
|
||||
@@ -2927,7 +2939,6 @@ module Impl<FullStateConfigSig Config> {
|
||||
result = TCons1(head_, this.length())
|
||||
}
|
||||
|
||||
pragma[assume_small_delta]
|
||||
override int length() { result = 1 + tail_.length() }
|
||||
|
||||
private string toStringImpl(boolean needsSuffix) {
|
||||
@@ -3097,6 +3108,12 @@ module Impl<FullStateConfigSig Config> {
|
||||
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
|
||||
}
|
||||
|
||||
private string ppSummaryCtx() {
|
||||
this instanceof PathNodeSink and result = ""
|
||||
or
|
||||
result = " <" + this.(PathNodeMid).getSummaryCtx().toString() + ">"
|
||||
}
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { result = this.getNodeEx().toString() + this.ppType() + this.ppAp() }
|
||||
|
||||
@@ -3105,7 +3122,9 @@ module Impl<FullStateConfigSig Config> {
|
||||
* representation of the call context.
|
||||
*/
|
||||
string toStringWithContext() {
|
||||
result = this.getNodeEx().toString() + this.ppType() + this.ppAp() + this.ppCtx()
|
||||
result =
|
||||
this.getNodeEx().toString() + this.ppType() + this.ppAp() + this.ppCtx() +
|
||||
this.ppSummaryCtx()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3379,7 +3398,6 @@ module Impl<FullStateConfigSig Config> {
|
||||
* Holds if data may flow from `mid` to `node`. The last step in or out of
|
||||
* a callable is recorded by `cc`.
|
||||
*/
|
||||
pragma[assume_small_delta]
|
||||
pragma[nomagic]
|
||||
private predicate pathStep0(
|
||||
PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, DataFlowType t,
|
||||
@@ -3592,7 +3610,6 @@ module Impl<FullStateConfigSig Config> {
|
||||
)
|
||||
}
|
||||
|
||||
pragma[assume_small_delta]
|
||||
pragma[nomagic]
|
||||
private predicate pathThroughCallable0(
|
||||
DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, FlowState state, CallContext cc,
|
||||
|
||||
@@ -313,6 +313,8 @@ private module Config implements FullStateConfigSig {
|
||||
any(Configuration config).allowImplicitRead(node, c)
|
||||
}
|
||||
|
||||
predicate neverSkip(Node node) { none() }
|
||||
|
||||
int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) }
|
||||
|
||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
||||
|
||||
@@ -313,6 +313,8 @@ private module Config implements FullStateConfigSig {
|
||||
any(Configuration config).allowImplicitRead(node, c)
|
||||
}
|
||||
|
||||
predicate neverSkip(Node node) { none() }
|
||||
|
||||
int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) }
|
||||
|
||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
||||
|
||||
@@ -313,6 +313,8 @@ private module Config implements FullStateConfigSig {
|
||||
any(Configuration config).allowImplicitRead(node, c)
|
||||
}
|
||||
|
||||
predicate neverSkip(Node node) { none() }
|
||||
|
||||
int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) }
|
||||
|
||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
||||
|
||||
@@ -313,6 +313,8 @@ private module Config implements FullStateConfigSig {
|
||||
any(Configuration config).allowImplicitRead(node, c)
|
||||
}
|
||||
|
||||
predicate neverSkip(Node node) { none() }
|
||||
|
||||
int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) }
|
||||
|
||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
||||
|
||||
@@ -187,7 +187,6 @@ private module LambdaFlow {
|
||||
else any()
|
||||
}
|
||||
|
||||
pragma[assume_small_delta]
|
||||
pragma[nomagic]
|
||||
predicate revLambdaFlow0(
|
||||
DataFlowCall lambdaCall, LambdaCallKind kind, Node node, DataFlowType t, boolean toReturn,
|
||||
@@ -274,7 +273,6 @@ private module LambdaFlow {
|
||||
)
|
||||
}
|
||||
|
||||
pragma[assume_small_delta]
|
||||
pragma[nomagic]
|
||||
predicate revLambdaFlowOut(
|
||||
DataFlowCall lambdaCall, LambdaCallKind kind, TReturnPositionSimple pos, DataFlowType t,
|
||||
|
||||
@@ -313,6 +313,8 @@ private module Config implements FullStateConfigSig {
|
||||
any(Configuration config).allowImplicitRead(node, c)
|
||||
}
|
||||
|
||||
predicate neverSkip(Node node) { none() }
|
||||
|
||||
int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) }
|
||||
|
||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
||||
|
||||
@@ -368,6 +368,11 @@ class FunctionAccess extends Access, @routineexpr {
|
||||
/** Gets the accessed function. */
|
||||
override Function getTarget() { funbind(underlyingElement(this), unresolveElement(result)) }
|
||||
|
||||
/**
|
||||
* Gets the expression generating the function being accessed.
|
||||
*/
|
||||
Expr getQualifier() { this.getChild(-1) = result }
|
||||
|
||||
/** Gets a textual representation of this function access. */
|
||||
override string toString() {
|
||||
if exists(this.getTarget())
|
||||
|
||||
@@ -46,6 +46,14 @@ signature module ConfigSig {
|
||||
*/
|
||||
default predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `node` should never be skipped over in the `PathGraph` and in path
|
||||
* explanations.
|
||||
*/
|
||||
default predicate neverSkip(Node node) {
|
||||
isAdditionalFlowStep(node, _) or isAdditionalFlowStep(_, node)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||
* This can be overridden to a smaller value to improve performance (a
|
||||
@@ -114,7 +122,7 @@ signature module StateConfigSig {
|
||||
* Holds if data flow through `node` is prohibited when the flow state is
|
||||
* `state`.
|
||||
*/
|
||||
predicate isBarrier(Node node, FlowState state);
|
||||
default predicate isBarrier(Node node, FlowState state) { none() }
|
||||
|
||||
/** Holds if data flow into `node` is prohibited. */
|
||||
default predicate isBarrierIn(Node node) { none() }
|
||||
@@ -131,7 +139,9 @@ signature module StateConfigSig {
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
||||
*/
|
||||
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2);
|
||||
default predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if an arbitrary number of implicit read steps of content `c` may be
|
||||
@@ -139,6 +149,17 @@ signature module StateConfigSig {
|
||||
*/
|
||||
default predicate allowImplicitRead(Node node, ContentSet c) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `node` should never be skipped over in the `PathGraph` and in path
|
||||
* explanations.
|
||||
*/
|
||||
default predicate neverSkip(Node node) {
|
||||
isAdditionalFlowStep(node, _) or
|
||||
isAdditionalFlowStep(_, node) or
|
||||
isAdditionalFlowStep(node, _, _, _) or
|
||||
isAdditionalFlowStep(_, _, node, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||
* This can be overridden to a smaller value to improve performance (a
|
||||
|
||||
@@ -66,6 +66,12 @@ signature module FullStateConfigSig {
|
||||
*/
|
||||
predicate allowImplicitRead(Node node, ContentSet c);
|
||||
|
||||
/**
|
||||
* Holds if `node` should never be skipped over in the `PathGraph` and in path
|
||||
* explanations.
|
||||
*/
|
||||
predicate neverSkip(Node node);
|
||||
|
||||
/**
|
||||
* Gets the virtual dispatch branching limit when calculating field flow.
|
||||
* This can be overridden to a smaller value to improve performance (a
|
||||
@@ -254,6 +260,11 @@ module Impl<FullStateConfigSig Config> {
|
||||
not fullBarrier(node2)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate isUnreachableInCall1(NodeEx n, LocalCallContextSpecificCall cc) {
|
||||
isUnreachableInCallCached(n.asNode(), cc.getCall())
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow in one local step from `node1` to `node2`.
|
||||
*/
|
||||
@@ -460,7 +471,6 @@ module Impl<FullStateConfigSig Config> {
|
||||
* The Boolean `cc` records whether the node is reached through an
|
||||
* argument in a call.
|
||||
*/
|
||||
pragma[assume_small_delta]
|
||||
private predicate fwdFlow(NodeEx node, Cc cc) {
|
||||
sourceNode(node, _) and
|
||||
if hasSourceCallCtx() then cc = true else cc = false
|
||||
@@ -570,7 +580,6 @@ module Impl<FullStateConfigSig Config> {
|
||||
/**
|
||||
* Holds if `c` is the target of a store in the flow covered by `fwdFlow`.
|
||||
*/
|
||||
pragma[assume_small_delta]
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlowConsCand(Content c) {
|
||||
exists(NodeEx mid, NodeEx node |
|
||||
@@ -1216,7 +1225,6 @@ module Impl<FullStateConfigSig Config> {
|
||||
fwdFlow1(_, _, _, _, _, _, t0, t, ap, _) and t0 != t
|
||||
}
|
||||
|
||||
pragma[assume_small_delta]
|
||||
pragma[nomagic]
|
||||
private predicate fwdFlow0(
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT,
|
||||
@@ -2022,7 +2030,8 @@ module Impl<FullStateConfigSig Config> {
|
||||
castNode(this.asNode()) or
|
||||
clearsContentCached(this.asNode(), _) or
|
||||
expectsContentCached(this.asNode(), _) or
|
||||
neverSkipInPathGraph(this.asNode())
|
||||
neverSkipInPathGraph(this.asNode()) or
|
||||
Config::neverSkip(this.asNode())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2111,7 +2120,7 @@ module Impl<FullStateConfigSig Config> {
|
||||
NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t,
|
||||
LocalCallContext cc
|
||||
) {
|
||||
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
|
||||
not isUnreachableInCall1(node2, cc) and
|
||||
(
|
||||
localFlowEntry(node1, pragma[only_bind_into](state)) and
|
||||
(
|
||||
@@ -2126,7 +2135,7 @@ module Impl<FullStateConfigSig Config> {
|
||||
) and
|
||||
node1 != node2 and
|
||||
cc.relevantFor(node1.getEnclosingCallable()) and
|
||||
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall())
|
||||
not isUnreachableInCall1(node1, cc)
|
||||
or
|
||||
exists(NodeEx mid |
|
||||
localFlowStepPlus(node1, pragma[only_bind_into](state), mid, preservesValue, t, cc) and
|
||||
@@ -2163,10 +2172,8 @@ module Impl<FullStateConfigSig Config> {
|
||||
preservesValue = false and
|
||||
t = node2.getDataFlowType() and
|
||||
callContext.relevantFor(node1.getEnclosingCallable()) and
|
||||
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
|
||||
isUnreachableInCallCached(node1.asNode(), call) or
|
||||
isUnreachableInCallCached(node2.asNode(), call)
|
||||
)
|
||||
not isUnreachableInCall1(node1, callContext) and
|
||||
not isUnreachableInCall1(node2, callContext)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2706,7 +2713,7 @@ module Impl<FullStateConfigSig Config> {
|
||||
|
||||
ParamNodeEx getParamNode() { result = p }
|
||||
|
||||
override string toString() { result = p + ": " + ap }
|
||||
override string toString() { result = p + concat(" : " + ppReprType(t)) + " " + ap }
|
||||
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
@@ -2758,12 +2765,21 @@ module Impl<FullStateConfigSig Config> {
|
||||
)
|
||||
}
|
||||
|
||||
private predicate forceUnfold(AccessPathApprox apa) {
|
||||
forceHighPrecision(apa.getHead())
|
||||
or
|
||||
exists(Content c2 |
|
||||
apa = TConsCons(_, _, c2, _) and
|
||||
forceHighPrecision(c2)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds with `unfold = false` if a precise head-tail representation of `apa` is
|
||||
* expected to be expensive. Holds with `unfold = true` otherwise.
|
||||
*/
|
||||
private predicate evalUnfold(AccessPathApprox apa, boolean unfold) {
|
||||
if forceHighPrecision(apa.getHead())
|
||||
if forceUnfold(apa)
|
||||
then unfold = true
|
||||
else
|
||||
exists(int aps, int nodes, int apLimit, int tupleLimit |
|
||||
@@ -2777,7 +2793,6 @@ module Impl<FullStateConfigSig Config> {
|
||||
/**
|
||||
* Gets the number of `AccessPath`s that correspond to `apa`.
|
||||
*/
|
||||
pragma[assume_small_delta]
|
||||
private int countAps(AccessPathApprox apa) {
|
||||
evalUnfold(apa, false) and
|
||||
result = 1 and
|
||||
@@ -2796,7 +2811,6 @@ module Impl<FullStateConfigSig Config> {
|
||||
* that it is expanded to a precise head-tail representation.
|
||||
*/
|
||||
language[monotonicAggregates]
|
||||
pragma[assume_small_delta]
|
||||
private int countPotentialAps(AccessPathApprox apa) {
|
||||
apa instanceof AccessPathApproxNil and result = 1
|
||||
or
|
||||
@@ -2833,7 +2847,6 @@ module Impl<FullStateConfigSig Config> {
|
||||
}
|
||||
|
||||
private newtype TPathNode =
|
||||
pragma[assume_small_delta]
|
||||
TPathNodeMid(
|
||||
NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, DataFlowType t, AccessPath ap
|
||||
) {
|
||||
@@ -2918,7 +2931,6 @@ module Impl<FullStateConfigSig Config> {
|
||||
|
||||
override AccessPathFrontHead getFront() { result = TFrontHead(head_) }
|
||||
|
||||
pragma[assume_small_delta]
|
||||
override AccessPathApproxCons getApprox() {
|
||||
result = TConsNil(head_, t) and tail_ = TAccessPathNil()
|
||||
or
|
||||
@@ -2927,7 +2939,6 @@ module Impl<FullStateConfigSig Config> {
|
||||
result = TCons1(head_, this.length())
|
||||
}
|
||||
|
||||
pragma[assume_small_delta]
|
||||
override int length() { result = 1 + tail_.length() }
|
||||
|
||||
private string toStringImpl(boolean needsSuffix) {
|
||||
@@ -3097,6 +3108,12 @@ module Impl<FullStateConfigSig Config> {
|
||||
result = " <" + this.(PathNodeMid).getCallContext().toString() + ">"
|
||||
}
|
||||
|
||||
private string ppSummaryCtx() {
|
||||
this instanceof PathNodeSink and result = ""
|
||||
or
|
||||
result = " <" + this.(PathNodeMid).getSummaryCtx().toString() + ">"
|
||||
}
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { result = this.getNodeEx().toString() + this.ppType() + this.ppAp() }
|
||||
|
||||
@@ -3105,7 +3122,9 @@ module Impl<FullStateConfigSig Config> {
|
||||
* representation of the call context.
|
||||
*/
|
||||
string toStringWithContext() {
|
||||
result = this.getNodeEx().toString() + this.ppType() + this.ppAp() + this.ppCtx()
|
||||
result =
|
||||
this.getNodeEx().toString() + this.ppType() + this.ppAp() + this.ppCtx() +
|
||||
this.ppSummaryCtx()
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -3379,7 +3398,6 @@ module Impl<FullStateConfigSig Config> {
|
||||
* Holds if data may flow from `mid` to `node`. The last step in or out of
|
||||
* a callable is recorded by `cc`.
|
||||
*/
|
||||
pragma[assume_small_delta]
|
||||
pragma[nomagic]
|
||||
private predicate pathStep0(
|
||||
PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, DataFlowType t,
|
||||
@@ -3592,7 +3610,6 @@ module Impl<FullStateConfigSig Config> {
|
||||
)
|
||||
}
|
||||
|
||||
pragma[assume_small_delta]
|
||||
pragma[nomagic]
|
||||
private predicate pathThroughCallable0(
|
||||
DataFlowCall call, PathNodeMid mid, ReturnKindExt kind, FlowState state, CallContext cc,
|
||||
|
||||
@@ -313,6 +313,8 @@ private module Config implements FullStateConfigSig {
|
||||
any(Configuration config).allowImplicitRead(node, c)
|
||||
}
|
||||
|
||||
predicate neverSkip(Node node) { none() }
|
||||
|
||||
int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) }
|
||||
|
||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
||||
|
||||
@@ -313,6 +313,8 @@ private module Config implements FullStateConfigSig {
|
||||
any(Configuration config).allowImplicitRead(node, c)
|
||||
}
|
||||
|
||||
predicate neverSkip(Node node) { none() }
|
||||
|
||||
int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) }
|
||||
|
||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
||||
|
||||
@@ -313,6 +313,8 @@ private module Config implements FullStateConfigSig {
|
||||
any(Configuration config).allowImplicitRead(node, c)
|
||||
}
|
||||
|
||||
predicate neverSkip(Node node) { none() }
|
||||
|
||||
int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) }
|
||||
|
||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
||||
|
||||
@@ -313,6 +313,8 @@ private module Config implements FullStateConfigSig {
|
||||
any(Configuration config).allowImplicitRead(node, c)
|
||||
}
|
||||
|
||||
predicate neverSkip(Node node) { none() }
|
||||
|
||||
int fieldFlowBranchLimit() { result = min(any(Configuration config).fieldFlowBranchLimit()) }
|
||||
|
||||
FlowFeature getAFeature() { result = any(Configuration config).getAFeature() }
|
||||
|
||||
@@ -187,7 +187,6 @@ private module LambdaFlow {
|
||||
else any()
|
||||
}
|
||||
|
||||
pragma[assume_small_delta]
|
||||
pragma[nomagic]
|
||||
predicate revLambdaFlow0(
|
||||
DataFlowCall lambdaCall, LambdaCallKind kind, Node node, DataFlowType t, boolean toReturn,
|
||||
@@ -274,7 +273,6 @@ private module LambdaFlow {
|
||||
)
|
||||
}
|
||||
|
||||
pragma[assume_small_delta]
|
||||
pragma[nomagic]
|
||||
predicate revLambdaFlowOut(
|
||||
DataFlowCall lambdaCall, LambdaCallKind kind, TReturnPositionSimple pos, DataFlowType t,
|
||||
|
||||
@@ -321,9 +321,11 @@ private class PrimaryArgumentNode extends ArgumentNode, OperandNode {
|
||||
|
||||
private class SideEffectArgumentNode extends ArgumentNode, SideEffectOperandNode {
|
||||
override predicate argumentOf(DataFlowCall dfCall, ArgumentPosition pos) {
|
||||
this.getCallInstruction() = dfCall and
|
||||
pos.(IndirectionPosition).getArgumentIndex() = this.getArgumentIndex() and
|
||||
super.hasAddressOperandAndIndirectionIndex(_, pos.(IndirectionPosition).getIndirectionIndex())
|
||||
exists(int indirectionIndex |
|
||||
pos = TIndirectionPosition(argumentIndex, pragma[only_bind_into](indirectionIndex)) and
|
||||
this.getCallInstruction() = dfCall and
|
||||
super.hasAddressOperandAndIndirectionIndex(_, pragma[only_bind_into](indirectionIndex))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -651,13 +653,16 @@ predicate jumpStep(Node n1, Node n2) {
|
||||
* Holds if data can flow from `node1` to `node2` via an assignment to `f`.
|
||||
* Thus, `node2` references an object with a field `f` that contains the
|
||||
* value of `node1`.
|
||||
*
|
||||
* The boolean `certain` is true if the destination address does not involve
|
||||
* any pointer arithmetic, and false otherwise.
|
||||
*/
|
||||
predicate storeStep(Node node1, Content c, PostFieldUpdateNode node2) {
|
||||
predicate storeStepImpl(Node node1, Content c, PostFieldUpdateNode node2, boolean certain) {
|
||||
exists(int indirectionIndex1, int numberOfLoads, StoreInstruction store |
|
||||
nodeHasInstruction(node1, store, pragma[only_bind_into](indirectionIndex1)) and
|
||||
node2.getIndirectionIndex() = 1 and
|
||||
numberOfLoadsFromOperand(node2.getFieldAddress(), store.getDestinationAddressOperand(),
|
||||
numberOfLoads)
|
||||
numberOfLoads, certain)
|
||||
|
|
||||
exists(FieldContent fc | fc = c |
|
||||
fc.getField() = node2.getUpdatedField() and
|
||||
@@ -671,21 +676,34 @@ predicate storeStep(Node node1, Content c, PostFieldUpdateNode node2) {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data can flow from `node1` to `node2` via an assignment to `f`.
|
||||
* Thus, `node2` references an object with a field `f` that contains the
|
||||
* value of `node1`.
|
||||
*/
|
||||
predicate storeStep(Node node1, Content c, PostFieldUpdateNode node2) {
|
||||
storeStepImpl(node1, c, node2, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `operandFrom` flows to `operandTo` using a sequence of conversion-like
|
||||
* operations and exactly `n` `LoadInstruction` operations.
|
||||
*/
|
||||
private predicate numberOfLoadsFromOperandRec(Operand operandFrom, Operand operandTo, int ind) {
|
||||
private predicate numberOfLoadsFromOperandRec(
|
||||
Operand operandFrom, Operand operandTo, int ind, boolean certain
|
||||
) {
|
||||
exists(Instruction load | Ssa::isDereference(load, operandFrom) |
|
||||
operandTo = operandFrom and ind = 0
|
||||
operandTo = operandFrom and ind = 0 and certain = true
|
||||
or
|
||||
numberOfLoadsFromOperand(load.getAUse(), operandTo, ind - 1)
|
||||
numberOfLoadsFromOperand(load.getAUse(), operandTo, ind - 1, certain)
|
||||
)
|
||||
or
|
||||
exists(Operand op, Instruction instr |
|
||||
exists(Operand op, Instruction instr, boolean isPointerArith, boolean certain0 |
|
||||
instr = op.getDef() and
|
||||
conversionFlow(operandFrom, instr, _, _) and
|
||||
numberOfLoadsFromOperand(op, operandTo, ind)
|
||||
conversionFlow(operandFrom, instr, isPointerArith, _) and
|
||||
numberOfLoadsFromOperand(op, operandTo, ind, certain0)
|
||||
|
|
||||
if isPointerArith = true then certain = false else certain = certain0
|
||||
)
|
||||
}
|
||||
|
||||
@@ -693,13 +711,16 @@ private predicate numberOfLoadsFromOperandRec(Operand operandFrom, Operand opera
|
||||
* Holds if `operandFrom` flows to `operandTo` using a sequence of conversion-like
|
||||
* operations and exactly `n` `LoadInstruction` operations.
|
||||
*/
|
||||
private predicate numberOfLoadsFromOperand(Operand operandFrom, Operand operandTo, int n) {
|
||||
numberOfLoadsFromOperandRec(operandFrom, operandTo, n)
|
||||
private predicate numberOfLoadsFromOperand(
|
||||
Operand operandFrom, Operand operandTo, int n, boolean certain
|
||||
) {
|
||||
numberOfLoadsFromOperandRec(operandFrom, operandTo, n, certain)
|
||||
or
|
||||
not Ssa::isDereference(_, operandFrom) and
|
||||
not conversionFlow(operandFrom, _, _, _) and
|
||||
operandFrom = operandTo and
|
||||
n = 0
|
||||
n = 0 and
|
||||
certain = true
|
||||
}
|
||||
|
||||
// Needed to join on both an operand and an index at the same time.
|
||||
@@ -729,7 +750,7 @@ predicate readStep(Node node1, Content c, Node node2) {
|
||||
// The `1` here matches the `node2.getIndirectionIndex() = 1` conjunct
|
||||
// in `storeStep`.
|
||||
nodeHasOperand(node1, fa1.getObjectAddressOperand(), 1) and
|
||||
numberOfLoadsFromOperand(fa1, operand, numberOfLoads)
|
||||
numberOfLoadsFromOperand(fa1, operand, numberOfLoads, _)
|
||||
|
|
||||
exists(FieldContent fc | fc = c |
|
||||
fc.getField() = fa1.getField() and
|
||||
@@ -747,7 +768,33 @@ predicate readStep(Node node1, Content c, Node node2) {
|
||||
* Holds if values stored inside content `c` are cleared at node `n`.
|
||||
*/
|
||||
predicate clearsContent(Node n, Content c) {
|
||||
none() // stub implementation
|
||||
n =
|
||||
any(PostUpdateNode pun, Content d | d.impliesClearOf(c) and storeStepImpl(_, d, pun, true) | pun)
|
||||
.getPreUpdateNode() and
|
||||
(
|
||||
// The crement operations and pointer addition and subtraction self-assign. We do not
|
||||
// want to clear the contents if it is indirectly pointed at by any of these operations,
|
||||
// as part of the contents might still be accessible afterwards. If there is no such
|
||||
// indirection clearing the contents is safe.
|
||||
not exists(Operand op, Cpp::Operation p |
|
||||
n.(IndirectOperand).hasOperandAndIndirectionIndex(op, _) and
|
||||
(
|
||||
p instanceof Cpp::AssignPointerAddExpr or
|
||||
p instanceof Cpp::AssignPointerSubExpr or
|
||||
p instanceof Cpp::CrementOperation
|
||||
)
|
||||
|
|
||||
p.getAnOperand() = op.getUse().getAst()
|
||||
)
|
||||
or
|
||||
forex(PostUpdateNode pun, Content d |
|
||||
pragma[only_bind_into](d).impliesClearOf(pragma[only_bind_into](c)) and
|
||||
storeStepImpl(_, d, pun, true) and
|
||||
pun.getPreUpdateNode() = n
|
||||
|
|
||||
c.getIndirectionIndex() = d.getIndirectionIndex()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -809,7 +856,73 @@ class DataFlowCall extends CallInstruction {
|
||||
Function getEnclosingCallable() { result = this.getEnclosingFunction() }
|
||||
}
|
||||
|
||||
predicate isUnreachableInCall(Node n, DataFlowCall call) { none() } // stub implementation
|
||||
module IsUnreachableInCall {
|
||||
private import semmle.code.cpp.ir.ValueNumbering
|
||||
private import semmle.code.cpp.controlflow.IRGuards as G
|
||||
|
||||
private class ConstantIntegralTypeArgumentNode extends PrimaryArgumentNode {
|
||||
int value;
|
||||
|
||||
ConstantIntegralTypeArgumentNode() {
|
||||
value = op.getDef().(IntegerConstantInstruction).getValue().toInt()
|
||||
}
|
||||
|
||||
int getValue() { result = value }
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate ensuresEq(Operand left, Operand right, int k, IRBlock block, boolean areEqual) {
|
||||
any(G::IRGuardCondition guard).ensuresEq(left, right, k, block, areEqual)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate ensuresLt(Operand left, Operand right, int k, IRBlock block, boolean areEqual) {
|
||||
any(G::IRGuardCondition guard).ensuresLt(left, right, k, block, areEqual)
|
||||
}
|
||||
|
||||
predicate isUnreachableInCall(Node n, DataFlowCall call) {
|
||||
exists(
|
||||
DirectParameterNode paramNode, ConstantIntegralTypeArgumentNode arg,
|
||||
IntegerConstantInstruction constant, int k, Operand left, Operand right, IRBlock block
|
||||
|
|
||||
// arg flows into `paramNode`
|
||||
DataFlowImplCommon::viableParamArg(call, paramNode, arg) and
|
||||
left = constant.getAUse() and
|
||||
right = valueNumber(paramNode.getInstruction()).getAUse() and
|
||||
block = n.getBasicBlock()
|
||||
|
|
||||
// and there's a guard condition which ensures that the result of `left == right + k` is `areEqual`
|
||||
exists(boolean areEqual |
|
||||
ensuresEq(pragma[only_bind_into](left), pragma[only_bind_into](right),
|
||||
pragma[only_bind_into](k), pragma[only_bind_into](block), areEqual)
|
||||
|
|
||||
// this block ensures that left = right + k, but it holds that `left != right + k`
|
||||
areEqual = true and
|
||||
constant.getValue().toInt() != arg.getValue() + k
|
||||
or
|
||||
// this block ensures that or `left != right + k`, but it holds that `left = right + k`
|
||||
areEqual = false and
|
||||
constant.getValue().toInt() = arg.getValue() + k
|
||||
)
|
||||
or
|
||||
// or there's a guard condition which ensures that the result of `left < right + k` is `isLessThan`
|
||||
exists(boolean isLessThan |
|
||||
ensuresLt(pragma[only_bind_into](left), pragma[only_bind_into](right),
|
||||
pragma[only_bind_into](k), pragma[only_bind_into](block), isLessThan)
|
||||
|
|
||||
isLessThan = true and
|
||||
// this block ensures that `left < right + k`, but it holds that `left >= right + k`
|
||||
constant.getValue().toInt() >= arg.getValue() + k
|
||||
or
|
||||
// this block ensures that `left >= right + k`, but it holds that `left < right + k`
|
||||
isLessThan = false and
|
||||
constant.getValue().toInt() < arg.getValue() + k
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
import IsUnreachableInCall
|
||||
|
||||
int accessPathLimit() { result = 5 }
|
||||
|
||||
|
||||
@@ -1832,6 +1832,20 @@ class Content extends TContent {
|
||||
predicate hasLocationInfo(string path, int sl, int sc, int el, int ec) {
|
||||
path = "" and sl = 0 and sc = 0 and el = 0 and ec = 0
|
||||
}
|
||||
|
||||
/** Gets the indirection index of this `Content`. */
|
||||
abstract int getIndirectionIndex();
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*
|
||||
* Holds if a write to this `Content` implies that `c` is
|
||||
* also cleared.
|
||||
*
|
||||
* For example, a write to a field `f` implies that any content of
|
||||
* the form `*f` is also cleared.
|
||||
*/
|
||||
abstract predicate impliesClearOf(Content c);
|
||||
}
|
||||
|
||||
/** A reference through a non-union instance field. */
|
||||
@@ -1849,10 +1863,21 @@ class FieldContent extends Content, TFieldContent {
|
||||
|
||||
Field getField() { result = f }
|
||||
|
||||
/** Gets the indirection index of this `FieldContent`. */
|
||||
pragma[inline]
|
||||
int getIndirectionIndex() {
|
||||
override int getIndirectionIndex() {
|
||||
pragma[only_bind_into](result) = pragma[only_bind_out](indirectionIndex)
|
||||
}
|
||||
|
||||
override predicate impliesClearOf(Content c) {
|
||||
exists(FieldContent fc |
|
||||
fc = c and
|
||||
fc.getField() = f and
|
||||
// If `this` is `f` then `c` is cleared if it's of the
|
||||
// form `*f`, `**f`, etc.
|
||||
fc.getIndirectionIndex() >= indirectionIndex
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** A reference through an instance field of a union. */
|
||||
@@ -1877,9 +1902,21 @@ class UnionContent extends Content, TUnionContent {
|
||||
|
||||
/** Gets the indirection index of this `UnionContent`. */
|
||||
pragma[inline]
|
||||
int getIndirectionIndex() {
|
||||
override int getIndirectionIndex() {
|
||||
pragma[only_bind_into](result) = pragma[only_bind_out](indirectionIndex)
|
||||
}
|
||||
|
||||
override predicate impliesClearOf(Content c) {
|
||||
exists(UnionContent uc |
|
||||
uc = c and
|
||||
uc.getUnion() = u and
|
||||
// If `this` is `u` then `c` is cleared if it's of the
|
||||
// form `*u`, `**u`, etc. (and we ignore `bytes` because
|
||||
// we know the entire union is overwritten because it's a
|
||||
// union).
|
||||
uc.getIndirectionIndex() >= indirectionIndex
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -448,6 +448,8 @@ module TaintedWithPath {
|
||||
}
|
||||
|
||||
predicate isBarrierIn(DataFlow::Node node) { nodeIsBarrierIn(node) }
|
||||
|
||||
predicate neverSkip(Node node) { none() }
|
||||
}
|
||||
|
||||
private module AdjustedFlow = TaintTracking::Global<AdjustedConfig>;
|
||||
|
||||
@@ -192,13 +192,13 @@ module ProductFlow {
|
||||
* Holds if data flow through `node` is prohibited through the first projection of the product
|
||||
* dataflow graph when the flow state is `state`.
|
||||
*/
|
||||
predicate isBarrier1(DataFlow::Node node, FlowState1 state);
|
||||
default predicate isBarrier1(DataFlow::Node node, FlowState1 state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited through the second projection of the product
|
||||
* dataflow graph when the flow state is `state`.
|
||||
*/
|
||||
predicate isBarrier2(DataFlow::Node node, FlowState2 state);
|
||||
default predicate isBarrier2(DataFlow::Node node, FlowState2 state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if data flow through `node` is prohibited through the first projection of the product
|
||||
@@ -237,9 +237,11 @@ module ProductFlow {
|
||||
*
|
||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
||||
*/
|
||||
predicate isAdditionalFlowStep1(
|
||||
default predicate isAdditionalFlowStep1(
|
||||
DataFlow::Node node1, FlowState1 state1, DataFlow::Node node2, FlowState1 state2
|
||||
);
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps in
|
||||
@@ -253,9 +255,11 @@ module ProductFlow {
|
||||
*
|
||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
||||
*/
|
||||
predicate isAdditionalFlowStep2(
|
||||
default predicate isAdditionalFlowStep2(
|
||||
DataFlow::Node node1, FlowState2 state1, DataFlow::Node node2, FlowState2 state2
|
||||
);
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data flow into `node` is prohibited in the first projection of the product
|
||||
@@ -293,6 +297,22 @@ module ProductFlow {
|
||||
reachable(source1, source2, sink1, sink2)
|
||||
}
|
||||
|
||||
/** Holds if data can flow from `(source1, source2)` to `(sink1, sink2)`. */
|
||||
predicate flow(
|
||||
DataFlow::Node source1, DataFlow::Node source2, DataFlow::Node sink1, DataFlow::Node sink2
|
||||
) {
|
||||
exists(
|
||||
Flow1::PathNode pSource1, Flow2::PathNode pSource2, Flow1::PathNode pSink1,
|
||||
Flow2::PathNode pSink2
|
||||
|
|
||||
pSource1.getNode() = source1 and
|
||||
pSource2.getNode() = source2 and
|
||||
pSink1.getNode() = sink1 and
|
||||
pSink2.getNode() = sink2 and
|
||||
flowPath(pSource1, pSource2, pSink1, pSink2)
|
||||
)
|
||||
}
|
||||
|
||||
private module Config1 implements DataFlow::StateConfigSig {
|
||||
class FlowState = FlowState1;
|
||||
|
||||
@@ -359,7 +379,6 @@ module ProductFlow {
|
||||
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)
|
||||
@@ -396,7 +415,6 @@ module ProductFlow {
|
||||
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
|
||||
) {
|
||||
@@ -406,7 +424,6 @@ module ProductFlow {
|
||||
)
|
||||
}
|
||||
|
||||
pragma[assume_small_delta]
|
||||
pragma[nomagic]
|
||||
private predicate revReachableInterprocEntry(Flow1::PathNode node1, Flow2::PathNode node2) {
|
||||
fwdReachableInterprocEntry(node1, node2) and
|
||||
|
||||
@@ -117,6 +117,16 @@ private int countIndirections(Type t) {
|
||||
else (
|
||||
result = any(Indirection ind | ind.getType() = t).getNumberOfIndirections()
|
||||
or
|
||||
// If there is an indirection for the type, but we cannot count the number of indirections
|
||||
// it means we couldn't reach a non-indirection type by stripping off indirections. This
|
||||
// can occur if an iterator specifies itself as the value type. In this case we default to
|
||||
// 1 indirection fore the type.
|
||||
exists(Indirection ind |
|
||||
ind.getType() = t and
|
||||
not exists(ind.getNumberOfIndirections()) and
|
||||
result = 1
|
||||
)
|
||||
or
|
||||
not exists(Indirection ind | ind.getType() = t) and
|
||||
result = 0
|
||||
)
|
||||
@@ -578,7 +588,6 @@ private module Cached {
|
||||
)
|
||||
}
|
||||
|
||||
pragma[assume_small_delta]
|
||||
private predicate convertsIntoArgumentRev(Instruction instr) {
|
||||
convertsIntoArgumentFwd(instr) and
|
||||
(
|
||||
|
||||
@@ -176,7 +176,6 @@ private predicate binaryValueNumber0(
|
||||
)
|
||||
}
|
||||
|
||||
pragma[assume_small_delta]
|
||||
private predicate binaryValueNumber(
|
||||
BinaryInstruction instr, IRFunction irFunc, Opcode opcode, TValueNumber leftOperand,
|
||||
TValueNumber rightOperand
|
||||
@@ -202,7 +201,6 @@ private predicate pointerArithmeticValueNumber0(
|
||||
)
|
||||
}
|
||||
|
||||
pragma[assume_small_delta]
|
||||
private predicate pointerArithmeticValueNumber(
|
||||
PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, int elementSize,
|
||||
TValueNumber leftOperand, TValueNumber rightOperand
|
||||
@@ -249,7 +247,6 @@ private predicate loadTotalOverlapValueNumber0(
|
||||
)
|
||||
}
|
||||
|
||||
pragma[assume_small_delta]
|
||||
private predicate loadTotalOverlapValueNumber(
|
||||
LoadTotalOverlapInstruction instr, IRFunction irFunc, IRType type, TValueNumber memOperand,
|
||||
TValueNumber operand
|
||||
|
||||
@@ -176,7 +176,6 @@ private predicate binaryValueNumber0(
|
||||
)
|
||||
}
|
||||
|
||||
pragma[assume_small_delta]
|
||||
private predicate binaryValueNumber(
|
||||
BinaryInstruction instr, IRFunction irFunc, Opcode opcode, TValueNumber leftOperand,
|
||||
TValueNumber rightOperand
|
||||
@@ -202,7 +201,6 @@ private predicate pointerArithmeticValueNumber0(
|
||||
)
|
||||
}
|
||||
|
||||
pragma[assume_small_delta]
|
||||
private predicate pointerArithmeticValueNumber(
|
||||
PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, int elementSize,
|
||||
TValueNumber leftOperand, TValueNumber rightOperand
|
||||
@@ -249,7 +247,6 @@ private predicate loadTotalOverlapValueNumber0(
|
||||
)
|
||||
}
|
||||
|
||||
pragma[assume_small_delta]
|
||||
private predicate loadTotalOverlapValueNumber(
|
||||
LoadTotalOverlapInstruction instr, IRFunction irFunc, IRType type, TValueNumber memOperand,
|
||||
TValueNumber operand
|
||||
|
||||
@@ -991,9 +991,19 @@ class TranslatedStructuredBindingVariableAccess extends TranslatedNonConstantExp
|
||||
class TranslatedFunctionAccess extends TranslatedNonConstantExpr {
|
||||
override FunctionAccess expr;
|
||||
|
||||
override TranslatedElement getChild(int id) { none() }
|
||||
override TranslatedElement getChild(int id) {
|
||||
id = 0 and result = this.getQualifier() // Might not exist
|
||||
}
|
||||
|
||||
override Instruction getFirstInstruction() { result = this.getInstruction(OnlyInstructionTag()) }
|
||||
final TranslatedExpr getQualifier() {
|
||||
result = getTranslatedExpr(expr.getQualifier().getFullyConverted())
|
||||
}
|
||||
|
||||
override Instruction getFirstInstruction() {
|
||||
if exists(this.getQualifier())
|
||||
then result = this.getQualifier().getFirstInstruction()
|
||||
else result = this.getInstruction(OnlyInstructionTag())
|
||||
}
|
||||
|
||||
override Instruction getResult() { result = this.getInstruction(OnlyInstructionTag()) }
|
||||
|
||||
@@ -1014,7 +1024,9 @@ class TranslatedFunctionAccess extends TranslatedNonConstantExpr {
|
||||
result = expr.getTarget()
|
||||
}
|
||||
|
||||
override Instruction getChildSuccessor(TranslatedElement child) { none() }
|
||||
override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
child = this.getQualifier() and result = this.getInstruction(OnlyInstructionTag())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -176,7 +176,6 @@ private predicate binaryValueNumber0(
|
||||
)
|
||||
}
|
||||
|
||||
pragma[assume_small_delta]
|
||||
private predicate binaryValueNumber(
|
||||
BinaryInstruction instr, IRFunction irFunc, Opcode opcode, TValueNumber leftOperand,
|
||||
TValueNumber rightOperand
|
||||
@@ -202,7 +201,6 @@ private predicate pointerArithmeticValueNumber0(
|
||||
)
|
||||
}
|
||||
|
||||
pragma[assume_small_delta]
|
||||
private predicate pointerArithmeticValueNumber(
|
||||
PointerArithmeticInstruction instr, IRFunction irFunc, Opcode opcode, int elementSize,
|
||||
TValueNumber leftOperand, TValueNumber rightOperand
|
||||
@@ -249,7 +247,6 @@ private predicate loadTotalOverlapValueNumber0(
|
||||
)
|
||||
}
|
||||
|
||||
pragma[assume_small_delta]
|
||||
private predicate loadTotalOverlapValueNumber(
|
||||
LoadTotalOverlapInstruction instr, IRFunction irFunc, IRType type, TValueNumber memOperand,
|
||||
TValueNumber operand
|
||||
|
||||
@@ -188,6 +188,9 @@ module SemanticExprConfig {
|
||||
none()
|
||||
}
|
||||
|
||||
/** Holds if no range analysis should be performed on the phi edges in `f`. */
|
||||
private predicate excludeFunction(Cpp::Function f) { count(f.getEntryPoint()) > 1 }
|
||||
|
||||
SemType getUnknownExprType(Expr expr) { result = getSemanticType(expr.getResultIRType()) }
|
||||
|
||||
class BasicBlock = IR::IRBlock;
|
||||
@@ -270,7 +273,13 @@ module SemanticExprConfig {
|
||||
getSemanticExpr(v.asInstruction()) = sourceExpr
|
||||
}
|
||||
|
||||
predicate phi(SsaVariable v) { v.asInstruction() instanceof IR::PhiInstruction }
|
||||
predicate phi(SsaVariable v) {
|
||||
exists(IR::PhiInstruction phi, Cpp::Function f |
|
||||
phi = v.asInstruction() and
|
||||
f = phi.getEnclosingFunction() and
|
||||
not excludeFunction(f)
|
||||
)
|
||||
}
|
||||
|
||||
SsaVariable getAPhiInput(SsaVariable v) {
|
||||
exists(IR::PhiInstruction instr | v.asInstruction() = instr |
|
||||
|
||||
@@ -70,6 +70,27 @@ predicate semBackEdge(SemSsaPhiNode phi, SemSsaVariable inp, SemSsaReadPositionP
|
||||
// Conservatively assume that every edge is a back edge if we don't have dominance information.
|
||||
(
|
||||
phi.getBasicBlock().bbDominates(edge.getOrigBlock()) or
|
||||
irreducibleSccEdge(edge.getOrigBlock(), phi.getBasicBlock()) or
|
||||
not edge.getOrigBlock().hasDominanceInformation()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the edge from b1 to b2 is part of a multiple-entry cycle in an irreducible control flow
|
||||
* graph.
|
||||
*
|
||||
* An ireducible control flow graph is one where the usual dominance-based back edge detection does
|
||||
* not work, because there is a cycle with multiple entry points, meaning there are
|
||||
* mutually-reachable basic blocks where neither dominates the other. For such a graph, we first
|
||||
* remove all detectable back-edges using the normal condition that the predecessor block is
|
||||
* dominated by the successor block, then mark all edges in a cycle in the resulting graph as back
|
||||
* edges.
|
||||
*/
|
||||
private predicate irreducibleSccEdge(SemBasicBlock b1, SemBasicBlock b2) {
|
||||
trimmedEdge(b1, b2) and trimmedEdge+(b2, b1)
|
||||
}
|
||||
|
||||
private predicate trimmedEdge(SemBasicBlock pred, SemBasicBlock succ) {
|
||||
pred.getASuccessor() = succ and
|
||||
not succ.bbDominates(pred)
|
||||
}
|
||||
|
||||
@@ -877,7 +877,6 @@ module RangeStage<
|
||||
)
|
||||
}
|
||||
|
||||
pragma[assume_small_delta]
|
||||
pragma[nomagic]
|
||||
private predicate boundedPhiRankStep(
|
||||
SemSsaPhiNode phi, SemBound b, D::Delta delta, boolean upper, boolean fromBackEdge,
|
||||
|
||||
@@ -0,0 +1,256 @@
|
||||
/**
|
||||
* This file provides the first phase of the `cpp/invalid-pointer-deref` query that identifies flow
|
||||
* from an allocation to a pointer-arithmetic instruction that constructs a pointer that is out of bounds.
|
||||
*/
|
||||
|
||||
private import cpp
|
||||
private import semmle.code.cpp.ir.dataflow.internal.ProductFlow
|
||||
private import semmle.code.cpp.ir.ValueNumbering
|
||||
private import semmle.code.cpp.controlflow.IRGuards
|
||||
private import codeql.util.Unit
|
||||
private import RangeAnalysisUtil
|
||||
|
||||
private VariableAccess getAVariableAccess(Expr e) { e.getAChild*() = result }
|
||||
|
||||
/**
|
||||
* Holds if the `(n, state)` pair represents the source of flow for the size
|
||||
* expression associated with `alloc`.
|
||||
*/
|
||||
predicate hasSize(HeuristicAllocationExpr alloc, DataFlow::Node n, int state) {
|
||||
exists(VariableAccess va, Expr size, int delta |
|
||||
size = alloc.getSizeExpr() and
|
||||
// Get the unique variable in a size expression like `x` in `malloc(x + 1)`.
|
||||
va = unique( | | getAVariableAccess(size)) and
|
||||
// Compute `delta` as the constant difference between `x` and `x + 1`.
|
||||
bounded1(any(Instruction instr | instr.getUnconvertedResultExpression() = size),
|
||||
any(LoadInstruction load | load.getUnconvertedResultExpression() = va), delta) and
|
||||
n.asConvertedExpr() = va.getFullyConverted() and
|
||||
state = delta
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A module that encapsulates a barrier guard to remove false positives from flow like:
|
||||
* ```cpp
|
||||
* char *p = new char[size];
|
||||
* // ...
|
||||
* unsigned n = size;
|
||||
* // ...
|
||||
* if(n < size) {
|
||||
* use(*p[n]);
|
||||
* }
|
||||
* ```
|
||||
* In this case, the sink pair identified by the product flow library (without any additional barriers)
|
||||
* would be `(p, n)` (where `n` is the `n` in `p[n]`), because there exists a pointer-arithmetic
|
||||
* instruction `pai` such that:
|
||||
* 1. The left-hand of `pai` flows from the allocation, and
|
||||
* 2. The right-hand of `pai` is non-strictly upper bounded by `n` (where `n` is the `n` in `p[n]`)
|
||||
* but because there's a strict comparison that compares `n` against the size of the allocation this
|
||||
* snippet is fine.
|
||||
*/
|
||||
module Barrier2 {
|
||||
private class FlowState2 = int;
|
||||
|
||||
private module BarrierConfig2 implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
// The sources is the same as in the sources for the second
|
||||
// projection in the `AllocToInvalidPointerConfig` module.
|
||||
hasSize(_, source, _)
|
||||
}
|
||||
|
||||
additional predicate isSink(
|
||||
DataFlow::Node left, DataFlow::Node right, IRGuardCondition g, FlowState2 state,
|
||||
boolean testIsTrue
|
||||
) {
|
||||
// The sink is any "large" side of a relational comparison.
|
||||
g.comparesLt(left.asOperand(), right.asOperand(), state, true, testIsTrue)
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { isSink(_, sink, _, _, _) }
|
||||
}
|
||||
|
||||
private import DataFlow::Global<BarrierConfig2>
|
||||
|
||||
private FlowState2 getAFlowStateForNode(DataFlow::Node node) {
|
||||
exists(DataFlow::Node source |
|
||||
flow(source, node) and
|
||||
hasSize(_, source, result)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate operandGuardChecks(
|
||||
IRGuardCondition g, Operand left, Operand right, FlowState2 state, boolean edge
|
||||
) {
|
||||
exists(DataFlow::Node nLeft, DataFlow::Node nRight, FlowState2 state0 |
|
||||
nRight.asOperand() = right and
|
||||
nLeft.asOperand() = left and
|
||||
BarrierConfig2::isSink(nLeft, nRight, g, state0, edge) and
|
||||
state = getAFlowStateForNode(nRight) and
|
||||
state0 <= state
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an instruction that is guarded by a guard condition which ensures that
|
||||
* the value of the instruction is upper-bounded by size of some allocation.
|
||||
*/
|
||||
Instruction getABarrierInstruction(FlowState2 state) {
|
||||
exists(IRGuardCondition g, ValueNumber value, Operand use, boolean edge |
|
||||
use = value.getAUse() and
|
||||
operandGuardChecks(pragma[only_bind_into](g), pragma[only_bind_into](use), _,
|
||||
pragma[only_bind_into](state), pragma[only_bind_into](edge)) and
|
||||
result = value.getAnInstruction() and
|
||||
g.controls(result.getBlock(), edge)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a `DataFlow::Node` that is guarded by a guard condition which ensures that
|
||||
* the value of the node is upper-bounded by size of some allocation.
|
||||
*/
|
||||
DataFlow::Node getABarrierNode(FlowState2 state) {
|
||||
result.asOperand() = getABarrierInstruction(state).getAUse()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the block of a node that is guarded (see `getABarrierInstruction` or
|
||||
* `getABarrierNode` for the definition of what it means to be guarded).
|
||||
*/
|
||||
IRBlock getABarrierBlock(FlowState2 state) {
|
||||
result.getAnInstruction() = getABarrierInstruction(state)
|
||||
}
|
||||
}
|
||||
|
||||
private module InterestingPointerAddInstruction {
|
||||
private module PointerAddInstructionConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
// The sources is the same as in the sources for the second
|
||||
// projection in the `AllocToInvalidPointerConfig` module.
|
||||
hasSize(source.asConvertedExpr(), _, _)
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
sink.asInstruction() = any(PointerAddInstruction pai).getLeft()
|
||||
}
|
||||
}
|
||||
|
||||
private import DataFlow::Global<PointerAddInstructionConfig>
|
||||
|
||||
/**
|
||||
* Holds if `pai` is a pointer-arithmetic instruction such that the
|
||||
* result of an allocation flows to the left-hand side of `pai`.
|
||||
*
|
||||
* This predicate is used to reduce the set of tuples in `isSinkPair`.
|
||||
*/
|
||||
predicate isInteresting(PointerAddInstruction pai) {
|
||||
exists(DataFlow::Node n |
|
||||
n.asInstruction() = pai.getLeft() and
|
||||
flowTo(n)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A product-flow configuration for flow from an (allocation, size) pair to a
|
||||
* pointer-arithmetic operation that is non-strictly upper-bounded by `allocation + size`.
|
||||
*
|
||||
* The goal of this query is to find patterns such as:
|
||||
* ```cpp
|
||||
* 1. char* begin = (char*)malloc(size);
|
||||
* 2. char* end = begin + size;
|
||||
* 3. for(int *p = begin; p <= end; p++) {
|
||||
* 4. use(*p);
|
||||
* 5. }
|
||||
* ```
|
||||
*
|
||||
* We do this by splitting the task up into two configurations:
|
||||
* 1. `AllocToInvalidPointerConfig` find flow from `malloc(size)` to `begin + size`, and
|
||||
* 2. `InvalidPointerToDerefConfig` finds flow from `begin + size` to an `end` (on line 3).
|
||||
*
|
||||
* 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`).
|
||||
*/
|
||||
private module Config implements ProductFlow::StateConfigSig {
|
||||
class FlowState1 = Unit;
|
||||
|
||||
class FlowState2 = int;
|
||||
|
||||
predicate isSourcePair(
|
||||
DataFlow::Node source1, FlowState1 state1, DataFlow::Node source2, FlowState2 state2
|
||||
) {
|
||||
// In the case of an allocation like
|
||||
// ```cpp
|
||||
// malloc(size + 1);
|
||||
// ```
|
||||
// we use `state2` to remember that there was an offset (in this case an offset of `1`) added
|
||||
// to the size of the allocation. This state is then checked in `isSinkPair`.
|
||||
exists(state1) and
|
||||
hasSize(source1.asConvertedExpr(), source2, state2)
|
||||
}
|
||||
|
||||
predicate isSinkPair(
|
||||
DataFlow::Node sink1, FlowState1 state1, DataFlow::Node sink2, FlowState2 state2
|
||||
) {
|
||||
exists(state1) and
|
||||
// We check that the delta computed by the range analysis matches the
|
||||
// state value that we set in `isSourcePair`.
|
||||
pointerAddInstructionHasBounds0(_, sink1, sink2, state2)
|
||||
}
|
||||
|
||||
predicate isBarrier2(DataFlow::Node node, FlowState2 state) {
|
||||
node = Barrier2::getABarrierNode(state)
|
||||
}
|
||||
|
||||
predicate isBarrierIn1(DataFlow::Node node) { isSourcePair(node, _, _, _) }
|
||||
|
||||
predicate isBarrierOut2(DataFlow::Node node) {
|
||||
node = any(DataFlow::SsaPhiNode phi).getAnInput(true)
|
||||
}
|
||||
}
|
||||
|
||||
private module AllocToInvalidPointerFlow = ProductFlow::GlobalWithState<Config>;
|
||||
|
||||
/**
|
||||
* Holds if `pai` is non-strictly upper bounded by `sink2 + delta` and `sink1` is the
|
||||
* left operand of the pointer-arithmetic operation.
|
||||
*
|
||||
* For example in,
|
||||
* ```cpp
|
||||
* char* end = p + (size + 1);
|
||||
* ```
|
||||
* We will have:
|
||||
* - `pai` is `p + (size + 1)`,
|
||||
* - `sink1` is `p`
|
||||
* - `sink2` is `size`
|
||||
* - `delta` is `1`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate pointerAddInstructionHasBounds0(
|
||||
PointerAddInstruction pai, DataFlow::Node sink1, DataFlow::Node sink2, int delta
|
||||
) {
|
||||
InterestingPointerAddInstruction::isInteresting(pragma[only_bind_into](pai)) and
|
||||
exists(Instruction right, Instruction instr2 |
|
||||
pai.getRight() = right and
|
||||
pai.getLeft() = sink1.asInstruction() and
|
||||
instr2 = sink2.asInstruction() and
|
||||
// pai.getRight() <= sink2 + delta
|
||||
bounded1(right, instr2, delta) and
|
||||
not right = Barrier2::getABarrierInstruction(delta) and
|
||||
not instr2 = Barrier2::getABarrierInstruction(delta)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `allocation` flows to `sink1` and `sink1` represents the left-hand
|
||||
* side of the pointer-arithmetic instruction `pai`, and the right-hand side of `pai`
|
||||
* is non-strictly upper bounded by the size of `alllocation` + `delta`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate pointerAddInstructionHasBounds(
|
||||
DataFlow::Node allocation, PointerAddInstruction pai, DataFlow::Node sink1, int delta
|
||||
) {
|
||||
exists(DataFlow::Node sink2 |
|
||||
AllocToInvalidPointerFlow::flow(allocation, _, sink1, sink2) and
|
||||
pointerAddInstructionHasBounds0(pai, sink1, sink2, delta)
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,196 @@
|
||||
/**
|
||||
* This file provides the second phase of the `cpp/invalid-pointer-deref` query that identifies flow
|
||||
* from the out-of-bounds pointer identified by the `AllocationToInvalidPointer.qll` library to
|
||||
* a dereference of the out-of-bounds pointer.
|
||||
*/
|
||||
|
||||
private import cpp
|
||||
private import semmle.code.cpp.dataflow.new.DataFlow
|
||||
private import semmle.code.cpp.ir.ValueNumbering
|
||||
private import semmle.code.cpp.controlflow.IRGuards
|
||||
private import AllocationToInvalidPointer as AllocToInvalidPointer
|
||||
private import RangeAnalysisUtil
|
||||
|
||||
private module InvalidPointerToDerefBarrier {
|
||||
private module BarrierConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
// The sources is the same as in the sources for `InvalidPointerToDerefConfig`.
|
||||
invalidPointerToDerefSource(_, _, source, _)
|
||||
}
|
||||
|
||||
additional predicate isSink(
|
||||
DataFlow::Node left, DataFlow::Node right, IRGuardCondition g, int state, boolean testIsTrue
|
||||
) {
|
||||
// The sink is any "large" side of a relational comparison.
|
||||
g.comparesLt(left.asOperand(), right.asOperand(), state, true, testIsTrue)
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { isSink(_, sink, _, _, _) }
|
||||
}
|
||||
|
||||
private module BarrierFlow = DataFlow::Global<BarrierConfig>;
|
||||
|
||||
private int getInvalidPointerToDerefSourceDelta(DataFlow::Node node) {
|
||||
exists(DataFlow::Node source |
|
||||
BarrierFlow::flow(source, node) and
|
||||
invalidPointerToDerefSource(_, _, source, result)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate operandGuardChecks(
|
||||
IRGuardCondition g, Operand left, Operand right, int state, boolean edge
|
||||
) {
|
||||
exists(DataFlow::Node nLeft, DataFlow::Node nRight, int state0 |
|
||||
nRight.asOperand() = right and
|
||||
nLeft.asOperand() = left and
|
||||
BarrierConfig::isSink(nLeft, nRight, g, state0, edge) and
|
||||
state = getInvalidPointerToDerefSourceDelta(nRight) and
|
||||
state0 <= state
|
||||
)
|
||||
}
|
||||
|
||||
Instruction getABarrierInstruction(int state) {
|
||||
exists(IRGuardCondition g, ValueNumber value, Operand use, boolean edge |
|
||||
use = value.getAUse() and
|
||||
operandGuardChecks(pragma[only_bind_into](g), pragma[only_bind_into](use), _, state,
|
||||
pragma[only_bind_into](edge)) and
|
||||
result = value.getAnInstruction() and
|
||||
g.controls(result.getBlock(), edge)
|
||||
)
|
||||
}
|
||||
|
||||
DataFlow::Node getABarrierNode() { result.asOperand() = getABarrierInstruction(_).getAUse() }
|
||||
|
||||
pragma[nomagic]
|
||||
IRBlock getABarrierBlock(int state) { result.getAnInstruction() = getABarrierInstruction(state) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A configuration to track flow from a pointer-arithmetic operation found
|
||||
* by `AllocToInvalidPointerConfig` to a dereference of the pointer.
|
||||
*/
|
||||
private module InvalidPointerToDerefConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { invalidPointerToDerefSource(_, _, source, _) }
|
||||
|
||||
pragma[inline]
|
||||
predicate isSink(DataFlow::Node sink) { isInvalidPointerDerefSink(sink, _, _, _) }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
node = any(DataFlow::SsaPhiNode phi | not phi.isPhiRead()).getAnInput(true)
|
||||
or
|
||||
node = InvalidPointerToDerefBarrier::getABarrierNode()
|
||||
}
|
||||
}
|
||||
|
||||
private import DataFlow::Global<InvalidPointerToDerefConfig>
|
||||
|
||||
/**
|
||||
* Holds if `source1` is dataflow node that represents an allocation that flows to the
|
||||
* left-hand side of the pointer-arithmetic `pai`, and `derefSource` is a dataflow node with
|
||||
* a pointer-value that is non-strictly upper bounded by `pai + delta`.
|
||||
*
|
||||
* For example, if `pai` is a pointer-arithmetic operation `p + size` in an expression such
|
||||
* as `(p + size) + 1` and `derefSource` is the node representing `(p + size) + 1`. In this
|
||||
* case `delta` is 1.
|
||||
*/
|
||||
private predicate invalidPointerToDerefSource(
|
||||
DataFlow::Node source1, PointerArithmeticInstruction pai, DataFlow::Node derefSource, int delta
|
||||
) {
|
||||
exists(int delta0 |
|
||||
// Note that `delta` is not necessarily equal to `delta0`:
|
||||
// `delta0` is the constant offset added to the size of the allocation, and
|
||||
// delta is the constant difference between the pointer-arithmetic instruction
|
||||
// and the instruction computing the address for which we will search for a dereference.
|
||||
AllocToInvalidPointer::pointerAddInstructionHasBounds(source1, pai, _, delta0) and
|
||||
bounded2(derefSource.asInstruction(), pai, delta) and
|
||||
delta >= 0 and
|
||||
// TODO: This condition will go away once #13725 is merged, and then we can make `Barrier2`
|
||||
// private to `AllocationToInvalidPointer.qll`.
|
||||
not derefSource.getBasicBlock() = AllocToInvalidPointer::Barrier2::getABarrierBlock(delta0)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* 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]
|
||||
private predicate isInvalidPointerDerefSink(
|
||||
DataFlow::Node sink, Instruction i, string operation, int delta
|
||||
) {
|
||||
exists(AddressOperand addr, Instruction s, IRBlock b |
|
||||
s = sink.asInstruction() and
|
||||
bounded(addr.getDef(), s, delta) and
|
||||
delta >= 0 and
|
||||
i.getAnOperand() = addr and
|
||||
b = i.getBlock() and
|
||||
not b = InvalidPointerToDerefBarrier::getABarrierBlock(delta)
|
||||
|
|
||||
i instanceof StoreInstruction and
|
||||
operation = "write"
|
||||
or
|
||||
i instanceof LoadInstruction and
|
||||
operation = "read"
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Yields any instruction that is control-flow reachable from `instr`.
|
||||
*/
|
||||
bindingset[instr, result]
|
||||
pragma[inline_late]
|
||||
private Instruction getASuccessor(Instruction instr) {
|
||||
exists(IRBlock b, int instrIndex, int resultIndex |
|
||||
b.getInstruction(instrIndex) = instr and
|
||||
b.getInstruction(resultIndex) = result
|
||||
|
|
||||
resultIndex >= instrIndex
|
||||
)
|
||||
or
|
||||
instr.getBlock().getASuccessor+() = result.getBlock()
|
||||
}
|
||||
|
||||
private predicate paiForDereferenceSink(PointerArithmeticInstruction pai, DataFlow::Node derefSink) {
|
||||
exists(DataFlow::Node derefSource |
|
||||
invalidPointerToDerefSource(_, pai, derefSource, _) and
|
||||
flow(derefSource, derefSink)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `derefSink` is a dataflow node that represents an out-of-bounds address that is about to
|
||||
* be dereferenced by `operation` (which is either a `StoreInstruction` or `LoadInstruction`), and
|
||||
* `pai` is the pointer-arithmetic operation that caused the `derefSink` to be out-of-bounds.
|
||||
*/
|
||||
private predicate derefSinkToOperation(
|
||||
DataFlow::Node derefSink, PointerArithmeticInstruction pai, DataFlow::Node operation,
|
||||
string description, int delta
|
||||
) {
|
||||
exists(Instruction i |
|
||||
paiForDereferenceSink(pai, pragma[only_bind_into](derefSink)) and
|
||||
isInvalidPointerDerefSink(derefSink, i, description, delta) and
|
||||
i = getASuccessor(derefSink.asInstruction()) and
|
||||
operation.asInstruction() = i
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `allocation` is the result of an allocation that flows to the left-hand side of `pai`, and where
|
||||
* the right-hand side of `pai` is an offset such that the result of `pai` points to an out-of-bounds pointer.
|
||||
*
|
||||
* Furthermore, `derefSource` is at least as large as `pai` and flows to `derefSink` before being dereferenced
|
||||
* by `operation` (which is either a `StoreInstruction` or `LoadInstruction`). The result is that `operation`
|
||||
* dereferences a pointer that's "off by `delta`" number of elements.
|
||||
*/
|
||||
predicate operationIsOffBy(
|
||||
DataFlow::Node allocation, PointerArithmeticInstruction pai, DataFlow::Node derefSource,
|
||||
DataFlow::Node derefSink, string description, DataFlow::Node operation, int delta
|
||||
) {
|
||||
exists(int deltaDerefSourceAndPai, int deltaDerefSinkAndDerefAddress |
|
||||
invalidPointerToDerefSource(allocation, pai, derefSource, deltaDerefSourceAndPai) and
|
||||
flow(derefSource, derefSink) and
|
||||
derefSinkToOperation(derefSink, pai, operation, description, deltaDerefSinkAndDerefAddress) and
|
||||
delta = deltaDerefSourceAndPai + deltaDerefSinkAndDerefAddress
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* This file contains the range-analysis specific parts of the `cpp/invalid-pointer-deref` query
|
||||
* that is used by both `AllocationToInvalidPointer.qll` and `InvalidPointerToDereference.qll`.
|
||||
*/
|
||||
|
||||
private import cpp
|
||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysis
|
||||
private import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExprSpecific
|
||||
private import semmle.code.cpp.ir.IR
|
||||
|
||||
pragma[nomagic]
|
||||
private Instruction getABoundIn(SemBound b, IRFunction func) {
|
||||
getSemanticExpr(result) = b.getExpr(0) and
|
||||
result.getEnclosingIRFunction() = func
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `i <= b + delta`.
|
||||
*/
|
||||
pragma[inline]
|
||||
private predicate boundedImpl(Instruction i, Instruction b, int delta) {
|
||||
exists(SemBound bound, IRFunction func |
|
||||
semBounded(getSemanticExpr(i), bound, delta, true, _) and
|
||||
b = getABoundIn(bound, func) and
|
||||
i.getEnclosingIRFunction() = func
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `i <= b + delta`.
|
||||
*
|
||||
* This predicate enforces a join-order that ensures that `i` has already been bound.
|
||||
*/
|
||||
bindingset[i]
|
||||
pragma[inline_late]
|
||||
predicate bounded1(Instruction i, Instruction b, int delta) { boundedImpl(i, b, delta) }
|
||||
|
||||
/**
|
||||
* Holds if `i <= b + delta`.
|
||||
*
|
||||
* This predicate enforces a join-order that ensures that `b` has already been bound.
|
||||
*/
|
||||
bindingset[b]
|
||||
pragma[inline_late]
|
||||
predicate bounded2(Instruction i, Instruction b, int delta) { boundedImpl(i, b, delta) }
|
||||
|
||||
/** Holds if `i <= b + delta`. */
|
||||
predicate bounded = boundedImpl/3;
|
||||
@@ -1,3 +1,13 @@
|
||||
## 0.7.0
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The `cpp/comparison-with-wider-type` query now correctly handles relational operations on signed operators. As a result the query may find more results.
|
||||
|
||||
## 0.6.4
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.6.3
|
||||
|
||||
### New Queries
|
||||
|
||||
@@ -88,14 +88,6 @@ module FlowFromFree<isSinkSig/2 isASink, isExcludedSig/2 isExcluded> {
|
||||
e = any(StoreInstruction store).getDestinationAddress().getUnconvertedResultExpression()
|
||||
)
|
||||
}
|
||||
|
||||
predicate isBarrier(DataFlow::Node n, FlowState state) { none() }
|
||||
|
||||
predicate isAdditionalFlowStep(
|
||||
DataFlow::Node n1, FlowState state1, DataFlow::Node n2, FlowState state2
|
||||
) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
import DataFlow::GlobalWithState<FlowFromFreeConfig>
|
||||
|
||||
@@ -135,18 +135,24 @@ module ParameterSinks {
|
||||
}
|
||||
}
|
||||
|
||||
predicate isUse(DataFlow::Node n, Expr e) {
|
||||
isUse0(n, e)
|
||||
or
|
||||
exists(CallInstruction call, int i, InitializeParameterInstruction init |
|
||||
n.asOperand().getDef().getUnconvertedResultExpression() = e and
|
||||
init = ParameterSinks::getAnAlwaysDereferencedParameter() and
|
||||
call.getArgumentOperand(i) = n.asOperand() and
|
||||
init.hasIndex(i) and
|
||||
init.getEnclosingFunction() = call.getStaticCallTarget()
|
||||
)
|
||||
module IsUse {
|
||||
private import semmle.code.cpp.ir.dataflow.internal.DataFlowImplCommon
|
||||
|
||||
predicate isUse(DataFlow::Node n, Expr e) {
|
||||
isUse0(n, e)
|
||||
or
|
||||
exists(CallInstruction call, InitializeParameterInstruction init |
|
||||
n.asOperand().getDef().getUnconvertedResultExpression() = e and
|
||||
pragma[only_bind_into](init) = ParameterSinks::getAnAlwaysDereferencedParameter() and
|
||||
viableParamArg(call, DataFlow::instructionNode(init), n) and
|
||||
pragma[only_bind_out](init.getEnclosingFunction()) =
|
||||
pragma[only_bind_out](call.getStaticCallTarget())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
import IsUse
|
||||
|
||||
/**
|
||||
* `dealloc1` is a deallocation expression, `e` is an expression that dereferences a
|
||||
* pointer, and the `(dealloc1, e)` pair should be excluded by the `FlowFromFree` library.
|
||||
|
||||
@@ -44,14 +44,6 @@ module CastToPointerArithFlowConfig implements DataFlow::StateConfigSig {
|
||||
) and
|
||||
getFullyConvertedType(node) = state
|
||||
}
|
||||
|
||||
predicate isBarrier(DataFlow::Node node, FlowState state) { none() }
|
||||
|
||||
predicate isAdditionalFlowStep(
|
||||
DataFlow::Node node1, FlowState state1, DataFlow::Node node2, FlowState state2
|
||||
) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -72,6 +72,11 @@ VariableAccess commonException() {
|
||||
or
|
||||
result.getParent() instanceof BuiltInOperation
|
||||
or
|
||||
// Ignore any uninitialized use that is explicitly cast to void and
|
||||
// is an expression statement.
|
||||
result.getActualType() instanceof VoidType and
|
||||
result.getParent() instanceof ExprStmt
|
||||
or
|
||||
// Finally, exclude functions that contain assembly blocks. It's
|
||||
// anyone's guess what happens in those.
|
||||
containsInlineAssembly(result.getEnclosingFunction())
|
||||
|
||||
@@ -134,8 +134,6 @@ module ExecTaintConfig implements DataFlow::StateConfigSig {
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) { isBarrierImpl(node) }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node, FlowState state) { none() }
|
||||
|
||||
predicate isBarrierOut(DataFlow::Node node) {
|
||||
isSink(node, _) // Prevent duplicates along a call chain, since `shellCommand` will include wrappers
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* @kind path-problem
|
||||
* @problem.severity error
|
||||
* @security-severity 9.3
|
||||
* @precision low
|
||||
* @precision medium
|
||||
* @id cpp/overrun-write
|
||||
* @tags reliability
|
||||
* security
|
||||
@@ -118,8 +118,6 @@ module ValidState {
|
||||
state = [false, true]
|
||||
}
|
||||
|
||||
predicate isBarrier(DataFlow::Node node, FlowState state) { none() }
|
||||
|
||||
predicate isAdditionalFlowStep(
|
||||
DataFlow::Node node1, FlowState state1, DataFlow::Node node2, FlowState state2
|
||||
) {
|
||||
@@ -233,7 +231,8 @@ module StringSizeConfig implements ProductFlow::StateConfigSig {
|
||||
// we use `state2` to remember that there was an offset (in this case an offset of `1`) added
|
||||
// to the size of the allocation. This state is then checked in `isSinkPair`.
|
||||
exists(state1) and
|
||||
hasSize(bufSource.asConvertedExpr(), sizeSource, state2)
|
||||
hasSize(bufSource.asConvertedExpr(), sizeSource, state2) and
|
||||
validState(sizeSource, state2)
|
||||
}
|
||||
|
||||
predicate isSinkPair(
|
||||
@@ -247,20 +246,10 @@ module StringSizeConfig implements ProductFlow::StateConfigSig {
|
||||
)
|
||||
}
|
||||
|
||||
predicate isBarrier1(DataFlow::Node node, FlowState1 state) { none() }
|
||||
|
||||
predicate isBarrier2(DataFlow::Node node, FlowState2 state) { none() }
|
||||
|
||||
predicate isBarrierOut2(DataFlow::Node node) {
|
||||
node = any(DataFlow::SsaPhiNode phi).getAnInput(true)
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep1(
|
||||
DataFlow::Node node1, FlowState1 state1, DataFlow::Node node2, FlowState1 state2
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep2(
|
||||
DataFlow::Node node1, FlowState2 state1, DataFlow::Node node2, FlowState2 state2
|
||||
) {
|
||||
|
||||
@@ -45,13 +45,20 @@ Element friendlyLoc(Expr e) {
|
||||
not e instanceof Access and not e instanceof Call and result = e
|
||||
}
|
||||
|
||||
int getComparisonSizeAdjustment(Expr e) {
|
||||
if e.getType().(IntegralType).isSigned() then result = 1 else result = 0
|
||||
}
|
||||
|
||||
from Loop l, RelationalOperation rel, VariableAccess small, Expr large
|
||||
where
|
||||
small = rel.getLesserOperand() and
|
||||
large = rel.getGreaterOperand() and
|
||||
rel = l.getCondition().getAChild*() and
|
||||
forall(Expr conv | conv = large.getConversion*() |
|
||||
upperBound(conv).log2() > getComparisonSize(small) * 8
|
||||
// We adjust the comparison size in the case of a signed integer type.
|
||||
// This is to exclude the sign bit from the comparison that determines if the small type's size is sufficient to hold
|
||||
// the value of the larger type determined with range analysis.
|
||||
upperBound(conv).log2() > (getComparisonSize(small) * 8 - getComparisonSizeAdjustment(small))
|
||||
) and
|
||||
// Ignore cases where the smaller type is int or larger
|
||||
// These are still bugs, but you should need a very large string or array to
|
||||
|
||||
@@ -43,6 +43,8 @@ module XxeConfig implements DataFlow::StateConfigSig {
|
||||
// flowstate value.
|
||||
node.asIndirectExpr().(XxeFlowStateTransformer).transform(flowstate) != flowstate
|
||||
}
|
||||
|
||||
predicate neverSkip(DataFlow::Node node) { none() }
|
||||
}
|
||||
|
||||
module XxeFlow = DataFlow::GlobalWithState<XxeConfig>;
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The `cpp/uninitialized-local` query now excludes uninitialized uses that are explicitly cast to void and are expression statements. As a result, the query will report less false positives.
|
||||
3
cpp/ql/src/change-notes/released/0.6.4.md
Normal file
3
cpp/ql/src/change-notes/released/0.6.4.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.6.4
|
||||
|
||||
No user-facing changes.
|
||||
5
cpp/ql/src/change-notes/released/0.7.0.md
Normal file
5
cpp/ql/src/change-notes/released/0.7.0.md
Normal file
@@ -0,0 +1,5 @@
|
||||
## 0.7.0
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The `cpp/comparison-with-wider-type` query now correctly handles relational operations on signed operators. As a result the query may find more results.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.6.3
|
||||
lastReleaseVersion: 0.7.0
|
||||
|
||||
@@ -14,7 +14,7 @@ import semmle.code.cpp.rangeanalysis.new.internal.semantic.analysis.RangeAnalysi
|
||||
import semmle.code.cpp.rangeanalysis.new.internal.semantic.SemanticExprSpecific
|
||||
import semmle.code.cpp.ir.IR
|
||||
import semmle.code.cpp.ir.dataflow.DataFlow
|
||||
import FieldAddressToDerefFlow::PathGraph
|
||||
import ArrayAddressToDerefFlow::PathGraph
|
||||
|
||||
pragma[nomagic]
|
||||
Instruction getABoundIn(SemBound b, IRFunction func) {
|
||||
@@ -78,28 +78,45 @@ predicate isInvalidPointerDerefSink2(DataFlow::Node sink, Instruction i, string
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate arrayTypeHasSizes(ArrayType arr, int baseTypeSize, int arraySize) {
|
||||
arr.getBaseType().getSize() = baseTypeSize and
|
||||
arr.getArraySize() = arraySize
|
||||
predicate arrayTypeCand(ArrayType arrayType) {
|
||||
any(Variable v).getUnspecifiedType() = arrayType and
|
||||
exists(arrayType.getByteSize())
|
||||
}
|
||||
|
||||
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
|
||||
bindingset[baseTypeSize]
|
||||
pragma[inline_late]
|
||||
predicate arrayTypeHasSizes(ArrayType arr, int baseTypeSize, int size) {
|
||||
arrayTypeCand(arr) and
|
||||
arr.getByteSize() / baseTypeSize = size
|
||||
}
|
||||
|
||||
bindingset[pai]
|
||||
pragma[inline_late]
|
||||
predicate constantUpperBounded(PointerArithmeticInstruction pai, int delta) {
|
||||
semBounded(getSemanticExpr(pai.getRight()), any(SemZeroBound b), delta, true, _)
|
||||
}
|
||||
|
||||
bindingset[pai, size]
|
||||
predicate pointerArithOverflow0Impl(PointerArithmeticInstruction pai, int size, int delta) {
|
||||
exists(int bound |
|
||||
constantUpperBounded(pai, bound) and
|
||||
delta = bound - size and
|
||||
delta >= 0 and
|
||||
size != 0 and
|
||||
size != 1
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate pointerArithOverflow0(PointerArithmeticInstruction pai, int delta) {
|
||||
exists(int size |
|
||||
arrayTypeHasSizes(_, pai.getElementSize(), size) and
|
||||
pointerArithOverflow0Impl(pai, size, delta)
|
||||
)
|
||||
}
|
||||
|
||||
module PointerArithmeticToDerefConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
pointerArithOverflow0(source.asInstruction(), _, _, _, _)
|
||||
}
|
||||
predicate isSource(DataFlow::Node source) { pointerArithOverflow0(source.asInstruction(), _) }
|
||||
|
||||
predicate isBarrierIn(DataFlow::Node node) { isSource(node) }
|
||||
|
||||
@@ -110,25 +127,38 @@ module PointerArithmeticToDerefConfig implements DataFlow::ConfigSig {
|
||||
|
||||
module PointerArithmeticToDerefFlow = DataFlow::Global<PointerArithmeticToDerefConfig>;
|
||||
|
||||
predicate pointerArithOverflow(
|
||||
PointerArithmeticInstruction pai, Field f, int size, int bound, int delta
|
||||
) {
|
||||
pointerArithOverflow0(pai, f, size, bound, delta) and
|
||||
predicate pointerArithOverflow(PointerArithmeticInstruction pai, int delta) {
|
||||
pointerArithOverflow0(pai, delta) and
|
||||
PointerArithmeticToDerefFlow::flow(DataFlow::instructionNode(pai), _)
|
||||
}
|
||||
|
||||
module FieldAddressToDerefConfig implements DataFlow::StateConfigSig {
|
||||
bindingset[v]
|
||||
predicate finalPointerArithOverflow(Variable v, PointerArithmeticInstruction pai, int delta) {
|
||||
exists(int size |
|
||||
arrayTypeHasSizes(pragma[only_bind_out](v.getUnspecifiedType()), pai.getElementSize(), size) and
|
||||
pointerArithOverflow0Impl(pai, size, delta)
|
||||
)
|
||||
}
|
||||
|
||||
predicate isSourceImpl(DataFlow::Node source, Variable v) {
|
||||
(
|
||||
source.asInstruction().(FieldAddressInstruction).getField() = v
|
||||
or
|
||||
source.asInstruction().(VariableAddressInstruction).getAstVariable() = v
|
||||
) and
|
||||
arrayTypeCand(v.getUnspecifiedType())
|
||||
}
|
||||
|
||||
module ArrayAddressToDerefConfig implements DataFlow::StateConfigSig {
|
||||
newtype FlowState =
|
||||
additional TArray(Field f) { pointerArithOverflow(_, f, _, _, _) } or
|
||||
additional TArray() or
|
||||
additional TOverflowArithmetic(PointerArithmeticInstruction pai) {
|
||||
pointerArithOverflow(pai, _, _, _, _)
|
||||
pointerArithOverflow(pai, _)
|
||||
}
|
||||
|
||||
predicate isSource(DataFlow::Node source, FlowState state) {
|
||||
exists(Field f |
|
||||
source.asInstruction().(FieldAddressInstruction).getField() = f and
|
||||
state = TArray(f)
|
||||
)
|
||||
isSourceImpl(source, _) and
|
||||
state = TArray()
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink, FlowState state) {
|
||||
@@ -138,8 +168,6 @@ module FieldAddressToDerefConfig implements DataFlow::StateConfigSig {
|
||||
)
|
||||
}
|
||||
|
||||
predicate isBarrier(DataFlow::Node node, FlowState state) { none() }
|
||||
|
||||
predicate isBarrierIn(DataFlow::Node node) { isSource(node, _) }
|
||||
|
||||
predicate isBarrierOut(DataFlow::Node node) { isSink(node, _) }
|
||||
@@ -147,27 +175,27 @@ module FieldAddressToDerefConfig implements DataFlow::StateConfigSig {
|
||||
predicate isAdditionalFlowStep(
|
||||
DataFlow::Node node1, FlowState state1, DataFlow::Node node2, FlowState state2
|
||||
) {
|
||||
exists(PointerArithmeticInstruction pai, Field f |
|
||||
state1 = TArray(f) and
|
||||
exists(PointerArithmeticInstruction pai |
|
||||
state1 = TArray() and
|
||||
state2 = TOverflowArithmetic(pai) and
|
||||
pai.getLeft() = node1.asInstruction() and
|
||||
node2.asInstruction() = pai and
|
||||
pointerArithOverflow(pai, f, _, _, _)
|
||||
pointerArithOverflow(pai, _)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
module FieldAddressToDerefFlow = DataFlow::GlobalWithState<FieldAddressToDerefConfig>;
|
||||
module ArrayAddressToDerefFlow = DataFlow::GlobalWithState<ArrayAddressToDerefConfig>;
|
||||
|
||||
from
|
||||
Field f, FieldAddressToDerefFlow::PathNode source, PointerArithmeticInstruction pai,
|
||||
FieldAddressToDerefFlow::PathNode sink, Instruction deref, string operation, int delta
|
||||
Variable v, ArrayAddressToDerefFlow::PathNode source, PointerArithmeticInstruction pai,
|
||||
ArrayAddressToDerefFlow::PathNode sink, Instruction deref, string operation, int delta
|
||||
where
|
||||
FieldAddressToDerefFlow::flowPath(source, sink) and
|
||||
ArrayAddressToDerefFlow::flowPath(pragma[only_bind_into](source), pragma[only_bind_into](sink)) and
|
||||
isInvalidPointerDerefSink2(sink.getNode(), deref, operation) and
|
||||
source.getState() = FieldAddressToDerefConfig::TArray(f) and
|
||||
sink.getState() = FieldAddressToDerefConfig::TOverflowArithmetic(pai) and
|
||||
pointerArithOverflow(pai, f, _, _, delta)
|
||||
pragma[only_bind_out](sink.getState()) = ArrayAddressToDerefConfig::TOverflowArithmetic(pai) and
|
||||
isSourceImpl(source.getNode(), v) and
|
||||
finalPointerArithOverflow(v, pai, 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
|
||||
" error allowing it to overrun $@ at this $@.", v, v.getName(), deref, operation
|
||||
|
||||
@@ -16,400 +16,92 @@
|
||||
*/
|
||||
|
||||
import cpp
|
||||
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.dataflow.new.DataFlow
|
||||
import semmle.code.cpp.ir.IR
|
||||
import codeql.util.Unit
|
||||
|
||||
pragma[nomagic]
|
||||
Instruction getABoundIn(SemBound b, IRFunction func) {
|
||||
getSemanticExpr(result) = b.getExpr(0) and
|
||||
result.getEnclosingIRFunction() = func
|
||||
}
|
||||
import FinalFlow::PathGraph
|
||||
import semmle.code.cpp.security.InvalidPointerDereference.AllocationToInvalidPointer
|
||||
import semmle.code.cpp.security.InvalidPointerDereference.InvalidPointerToDereference
|
||||
|
||||
/**
|
||||
* Holds if `i <= b + delta`.
|
||||
* A configuration that represents the full dataflow path all the way from
|
||||
* the allocation to the dereference. We need this final dataflow traversal
|
||||
* to ensure that the transition from the sink in `AllocToInvalidPointerConfig`
|
||||
* to the source in `InvalidPointerToDerefFlow` did not make us construct an
|
||||
* infeasible path (which can happen since the transition from one configuration
|
||||
* to the next does not preserve information about call contexts).
|
||||
*/
|
||||
pragma[inline]
|
||||
predicate boundedImpl(Instruction i, Instruction b, int delta) {
|
||||
exists(SemBound bound, IRFunction func |
|
||||
semBounded(getSemanticExpr(i), bound, delta, true, _) and
|
||||
b = getABoundIn(bound, func) and
|
||||
i.getEnclosingIRFunction() = func
|
||||
)
|
||||
}
|
||||
module FinalConfig implements DataFlow::StateConfigSig {
|
||||
newtype FlowState =
|
||||
additional TInitial() or
|
||||
additional TPointerArith(PointerArithmeticInstruction pai) {
|
||||
operationIsOffBy(_, pai, _, _, _, _, _)
|
||||
}
|
||||
|
||||
bindingset[i]
|
||||
pragma[inline_late]
|
||||
predicate bounded1(Instruction i, Instruction b, int delta) { boundedImpl(i, b, delta) }
|
||||
|
||||
bindingset[b]
|
||||
pragma[inline_late]
|
||||
predicate bounded2(Instruction i, Instruction b, int delta) { boundedImpl(i, b, delta) }
|
||||
|
||||
VariableAccess getAVariableAccess(Expr e) { e.getAChild*() = result }
|
||||
|
||||
/**
|
||||
* Holds if `(n, state)` pair represents the source of flow for the size
|
||||
* expression associated with `alloc`.
|
||||
*/
|
||||
predicate hasSize(HeuristicAllocationExpr alloc, DataFlow::Node n, int state) {
|
||||
exists(VariableAccess va, Expr size, int delta |
|
||||
size = alloc.getSizeExpr() and
|
||||
// Get the unique variable in a size expression like `x` in `malloc(x + 1)`.
|
||||
va = unique( | | getAVariableAccess(size)) and
|
||||
// Compute `delta` as the constant difference between `x` and `x + 1`.
|
||||
bounded1(any(Instruction instr | instr.getUnconvertedResultExpression() = size),
|
||||
any(LoadInstruction load | load.getUnconvertedResultExpression() = va), delta) and
|
||||
n.asConvertedExpr() = va.getFullyConverted() and
|
||||
state = delta
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A product-flow configuration for flow from an (allocation, size) pair to a
|
||||
* pointer-arithmetic operation that is non-strictly upper-bounded by `allocation + size`.
|
||||
*
|
||||
* The goal of this query is to find patterns such as:
|
||||
* ```cpp
|
||||
* 1. char* begin = (char*)malloc(size);
|
||||
* 2. char* end = begin + size;
|
||||
* 3. for(int *p = begin; p <= end; p++) {
|
||||
* 4. use(*p);
|
||||
* 5. }
|
||||
* ```
|
||||
*
|
||||
* We do this by splitting the task up into two configurations:
|
||||
* 1. `AllocToInvalidPointerConfig` find flow from `malloc(size)` to `begin + size`, and
|
||||
* 2. `InvalidPointerToDerefConfig` finds flow from `begin + size` to an `end` (on line 3).
|
||||
*
|
||||
* 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`).
|
||||
*/
|
||||
module AllocToInvalidPointerConfig implements ProductFlow::StateConfigSig {
|
||||
class FlowState1 = Unit;
|
||||
|
||||
class FlowState2 = int;
|
||||
|
||||
predicate isSourcePair(
|
||||
DataFlow::Node source1, FlowState1 state1, DataFlow::Node source2, FlowState2 state2
|
||||
) {
|
||||
// In the case of an allocation like
|
||||
// ```cpp
|
||||
// malloc(size + 1);
|
||||
// ```
|
||||
// we use `state2` to remember that there was an offset (in this case an offset of `1`) added
|
||||
// to the size of the allocation. This state is then checked in `isSinkPair`.
|
||||
exists(state1) and
|
||||
hasSize(source1.asConvertedExpr(), source2, state2)
|
||||
predicate isSource(DataFlow::Node source, FlowState state) {
|
||||
state = TInitial() and
|
||||
operationIsOffBy(source, _, _, _, _, _, _)
|
||||
}
|
||||
|
||||
predicate isSinkPair(
|
||||
DataFlow::Node sink1, FlowState1 state1, DataFlow::Node sink2, FlowState2 state2
|
||||
) {
|
||||
exists(state1) and
|
||||
// We check that the delta computed by the range analysis matches the
|
||||
// state value that we set in `isSourcePair`.
|
||||
exists(int delta |
|
||||
isSinkImpl(_, sink1, sink2, delta) and
|
||||
state2 = delta
|
||||
predicate isSink(DataFlow::Node sink, FlowState state) {
|
||||
exists(PointerArithmeticInstruction pai |
|
||||
operationIsOffBy(_, pai, _, _, _, sink, _) and
|
||||
state = TPointerArith(pai)
|
||||
)
|
||||
}
|
||||
|
||||
predicate isBarrier1(DataFlow::Node node, FlowState1 state) { none() }
|
||||
|
||||
predicate isBarrier2(DataFlow::Node node, FlowState2 state) { none() }
|
||||
|
||||
predicate isBarrierIn1(DataFlow::Node node) { isSourcePair(node, _, _, _) }
|
||||
|
||||
predicate isBarrierOut2(DataFlow::Node node) {
|
||||
node = any(DataFlow::SsaPhiNode phi).getAnInput(true)
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep1(
|
||||
DataFlow::Node node1, FlowState1 state1, DataFlow::Node node2, FlowState1 state2
|
||||
predicate isAdditionalFlowStep(
|
||||
DataFlow::Node node1, FlowState state1, DataFlow::Node node2, FlowState state2
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
predicate isAdditionalFlowStep2(
|
||||
DataFlow::Node node1, FlowState2 state1, DataFlow::Node node2, FlowState2 state2
|
||||
) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
module AllocToInvalidPointerFlow = ProductFlow::GlobalWithState<AllocToInvalidPointerConfig>;
|
||||
|
||||
/**
|
||||
* Holds if `pai` is non-strictly upper bounded by `sink2 + delta` and `sink1` is the
|
||||
* left operand of the pointer-arithmetic operation.
|
||||
*
|
||||
* For example in,
|
||||
* ```cpp
|
||||
* char* end = p + (size + 1);
|
||||
* ```
|
||||
* We will have:
|
||||
* - `pai` is `p + (size + 1)`,
|
||||
* - `sink1` is `p`
|
||||
* - `sink2` is `size`
|
||||
* - `delta` is `1`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate pointerAddInstructionHasBounds(
|
||||
PointerAddInstruction pai, DataFlow::Node sink1, DataFlow::Node sink2, int delta
|
||||
) {
|
||||
exists(Instruction right |
|
||||
pai.getRight() = right and
|
||||
pai.getLeft() = sink1.asInstruction() and
|
||||
bounded1(right, sink2.asInstruction(), delta)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `pai` is non-strictly upper bounded by `sink2 + delta` and `sink1` is the
|
||||
* left operand of the pointer-arithmetic operation.
|
||||
*
|
||||
* See `pointerAddInstructionHasBounds` for an example.
|
||||
*/
|
||||
predicate isSinkImpl(
|
||||
PointerAddInstruction pai, DataFlow::Node sink1, DataFlow::Node sink2, int delta
|
||||
) {
|
||||
pointerAddInstructionHasBounds(pai, sink1, sink2, delta)
|
||||
}
|
||||
|
||||
/**
|
||||
* Yields any instruction that is control-flow reachable from `instr`.
|
||||
*/
|
||||
bindingset[instr, result]
|
||||
pragma[inline_late]
|
||||
Instruction getASuccessor(Instruction instr) {
|
||||
exists(IRBlock b, int instrIndex, int resultIndex |
|
||||
result.getBlock() = b and
|
||||
instr.getBlock() = b and
|
||||
b.getInstruction(instrIndex) = instr and
|
||||
b.getInstruction(resultIndex) = result
|
||||
|
|
||||
resultIndex >= instrIndex
|
||||
)
|
||||
or
|
||||
instr.getBlock().getASuccessor+() = result.getBlock()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a sink for `InvalidPointerToDerefConfig` and `i` is a `StoreInstruction` that
|
||||
* writes to an address that non-strictly upper-bounds `sink`, or `i` is a `LoadInstruction` that
|
||||
* reads from an address that non-strictly upper-bounds `sink`.
|
||||
*/
|
||||
pragma[inline]
|
||||
predicate isInvalidPointerDerefSink(DataFlow::Node sink, Instruction i, string operation, int delta) {
|
||||
exists(AddressOperand addr, Instruction s |
|
||||
s = sink.asInstruction() and
|
||||
bounded1(addr.getDef(), s, delta) and
|
||||
delta >= 0 and
|
||||
i.getAnOperand() = addr
|
||||
|
|
||||
i instanceof StoreInstruction and
|
||||
operation = "write"
|
||||
// A step from the left-hand side of a pointer-arithmetic operation that has been
|
||||
// identified as creating an out-of-bounds pointer to the result of the pointer-arithmetic
|
||||
// operation.
|
||||
exists(PointerArithmeticInstruction pai |
|
||||
pointerAddInstructionHasBounds(_, pai, node1, _) and
|
||||
operationIsOffBy(_, pai, node2, _, _, _, _) and
|
||||
state1 = TInitial() and
|
||||
state2 = TPointerArith(pai)
|
||||
)
|
||||
or
|
||||
i instanceof LoadInstruction and
|
||||
operation = "read"
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A configuration to track flow from a pointer-arithmetic operation found
|
||||
* 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 isBarrier(DataFlow::Node node) {
|
||||
node = any(DataFlow::SsaPhiNode phi | not phi.isPhiRead()).getAnInput(true)
|
||||
// A step from an out-of-bounds address to the operation (which is either a `StoreInstruction`
|
||||
// or a `LoadInstruction`) that dereferences the address.
|
||||
// This step exists purely for aesthetic reasons: we want the alert to be placed at the operation
|
||||
// that causes the dereference, and not at the address that flows into the operation.
|
||||
state1 = state2 and
|
||||
exists(PointerArithmeticInstruction pai |
|
||||
state1 = TPointerArith(pai) and
|
||||
operationIsOffBy(_, pai, _, node1, _, node2, _)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
module InvalidPointerToDerefFlow = DataFlow::Global<InvalidPointerToDerefConfig>;
|
||||
module FinalFlow = DataFlow::GlobalWithState<FinalConfig>;
|
||||
|
||||
/**
|
||||
* Holds if `pai` is a pointer-arithmetic operation and `source` is a dataflow node with a
|
||||
* pointer-value that is non-strictly upper bounded by `pai + delta`.
|
||||
* Holds if `source` is an allocation that flows into the left-hand side of `pai`, which produces an out-of-bounds
|
||||
* pointer that flows into an address that is dereferenced by `sink` (which is either a `LoadInstruction` or a
|
||||
* `StoreInstruction`). The end result is that `sink` writes to an address that is off-by-`delta` from the end of
|
||||
* the allocation. The string `operation` describes whether the `sink` is a load or a store (which is then used
|
||||
* to produce the alert message).
|
||||
*
|
||||
* For example, if `pai` is a pointer-arithmetic operation `p + size` in an expression such
|
||||
* as `(p + size) + 1` and `source` is the node representing `(p + size) + 1`. In this
|
||||
* case `delta` is 1.
|
||||
* Note that multiple `delta`s can exist for a given `(source, pai, sink)` triplet.
|
||||
*/
|
||||
predicate invalidPointerToDerefSource(
|
||||
PointerArithmeticInstruction pai, DataFlow::Node source, int delta
|
||||
) {
|
||||
exists(AllocToInvalidPointerFlow::PathNode1 p, DataFlow::Node sink1 |
|
||||
pragma[only_bind_out](p.getNode()) = sink1 and
|
||||
AllocToInvalidPointerFlow::flowPath(_, _, pragma[only_bind_into](p), _) and
|
||||
isSinkImpl(pai, sink1, _, _) and
|
||||
bounded2(source.asInstruction(), pai, delta) and
|
||||
delta >= 0
|
||||
)
|
||||
}
|
||||
|
||||
newtype TMergedPathNode =
|
||||
// The path nodes computed by the first projection of `AllocToInvalidPointerConfig`
|
||||
TPathNode1(AllocToInvalidPointerFlow::PathNode1 p) or
|
||||
// The path nodes computed by `InvalidPointerToDerefConfig`
|
||||
TPathNode3(InvalidPointerToDerefFlow::PathNode p) or
|
||||
// The read/write that uses the invalid pointer identified by `InvalidPointerToDerefConfig`.
|
||||
// This one is needed because the sink identified by `InvalidPointerToDerefConfig` is the
|
||||
// pointer, but we want to raise an alert at the dereference.
|
||||
TPathNodeSink(Instruction i) {
|
||||
exists(DataFlow::Node n |
|
||||
InvalidPointerToDerefFlow::flowTo(n) and
|
||||
isInvalidPointerDerefSink(n, i, _, _) and
|
||||
i = getASuccessor(n.asInstruction())
|
||||
)
|
||||
}
|
||||
|
||||
class MergedPathNode extends TMergedPathNode {
|
||||
string toString() { none() }
|
||||
|
||||
final AllocToInvalidPointerFlow::PathNode1 asPathNode1() { this = TPathNode1(result) }
|
||||
|
||||
final InvalidPointerToDerefFlow::PathNode asPathNode3() { this = TPathNode3(result) }
|
||||
|
||||
final Instruction asSinkNode() { this = TPathNodeSink(result) }
|
||||
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
none()
|
||||
}
|
||||
}
|
||||
|
||||
class PathNode1 extends MergedPathNode, TPathNode1 {
|
||||
override string toString() {
|
||||
exists(AllocToInvalidPointerFlow::PathNode1 p |
|
||||
this = TPathNode1(p) and
|
||||
result = p.toString()
|
||||
)
|
||||
}
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
this.asPathNode1().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
}
|
||||
|
||||
class PathNode3 extends MergedPathNode, TPathNode3 {
|
||||
override string toString() {
|
||||
exists(InvalidPointerToDerefFlow::PathNode p |
|
||||
this = TPathNode3(p) and
|
||||
result = p.toString()
|
||||
)
|
||||
}
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
this.asPathNode3().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
}
|
||||
|
||||
class PathSinkNode extends MergedPathNode, TPathNodeSink {
|
||||
override string toString() {
|
||||
exists(Instruction i |
|
||||
this = TPathNodeSink(i) and
|
||||
result = i.toString()
|
||||
)
|
||||
}
|
||||
|
||||
override predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
this.asSinkNode()
|
||||
.getLocation()
|
||||
.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
}
|
||||
}
|
||||
|
||||
query predicate edges(MergedPathNode node1, MergedPathNode node2) {
|
||||
node1.asPathNode1().getASuccessor() = node2.asPathNode1()
|
||||
or
|
||||
joinOn1(_, node1.asPathNode1(), node2.asPathNode3())
|
||||
or
|
||||
node1.asPathNode3().getASuccessor() = node2.asPathNode3()
|
||||
or
|
||||
joinOn2(node1.asPathNode3(), node2.asSinkNode(), _, _)
|
||||
}
|
||||
|
||||
query predicate nodes(MergedPathNode n, string key, string val) {
|
||||
AllocToInvalidPointerFlow::PathGraph1::nodes(n.asPathNode1(), key, val)
|
||||
or
|
||||
InvalidPointerToDerefFlow::PathGraph::nodes(n.asPathNode3(), key, val)
|
||||
or
|
||||
key = "semmle.label" and val = n.asSinkNode().toString()
|
||||
}
|
||||
|
||||
query predicate subpaths(
|
||||
MergedPathNode arg, MergedPathNode par, MergedPathNode ret, MergedPathNode out
|
||||
) {
|
||||
AllocToInvalidPointerFlow::PathGraph1::subpaths(arg.asPathNode1(), par.asPathNode1(),
|
||||
ret.asPathNode1(), out.asPathNode1())
|
||||
or
|
||||
InvalidPointerToDerefFlow::PathGraph::subpaths(arg.asPathNode3(), par.asPathNode3(),
|
||||
ret.asPathNode3(), out.asPathNode3())
|
||||
}
|
||||
|
||||
/**
|
||||
* 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,
|
||||
InvalidPointerToDerefFlow::PathNode p2
|
||||
) {
|
||||
isSinkImpl(pai, p1.getNode(), _, _) and
|
||||
invalidPointerToDerefSource(pai, p2.getNode(), _)
|
||||
}
|
||||
|
||||
/**
|
||||
* 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, int delta) {
|
||||
isInvalidPointerDerefSink(p1.getNode(), i, operation, delta)
|
||||
}
|
||||
|
||||
predicate hasFlowPath(
|
||||
MergedPathNode source1, MergedPathNode sink, InvalidPointerToDerefFlow::PathNode source3,
|
||||
PointerArithmeticInstruction pai, string operation, int delta
|
||||
FinalFlow::PathNode source, FinalFlow::PathNode sink, 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, delta)
|
||||
)
|
||||
FinalFlow::flowPath(source, sink) and
|
||||
operationIsOffBy(source.getNode(), pai, _, _, operation, sink.getNode(), delta) and
|
||||
sink.getState() = FinalConfig::TPointerArith(pai)
|
||||
}
|
||||
|
||||
from
|
||||
MergedPathNode source, MergedPathNode sink, int k, string kstr, PointerArithmeticInstruction pai,
|
||||
string operation, Expr offset, DataFlow::Node n
|
||||
FinalFlow::PathNode source, FinalFlow::PathNode sink, int k, string kstr,
|
||||
PointerArithmeticInstruction pai, string operation, Expr offset, DataFlow::Node n
|
||||
where
|
||||
k =
|
||||
min(int k2, int k3, InvalidPointerToDerefFlow::PathNode source3 |
|
||||
hasFlowPath(source, sink, source3, pai, operation, k3) and
|
||||
invalidPointerToDerefSource(pai, source3.getNode(), k2)
|
||||
|
|
||||
k2 + k3
|
||||
) and
|
||||
k = min(int cand | hasFlowPath(source, sink, pai, operation, cand)) and
|
||||
offset = pai.getRight().getUnconvertedResultExpression() and
|
||||
n = source.asPathNode1().getNode() and
|
||||
n = source.getNode() and
|
||||
if k = 0 then kstr = "" else kstr = " + " + k
|
||||
select sink, source, sink,
|
||||
select sink.getNode(), source, sink,
|
||||
"This " + operation + " might be out of bounds, as the pointer might be equal to $@ + $@" + kstr +
|
||||
".", n, n.toString(), offset, offset.toString()
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-queries
|
||||
version: 0.6.4-dev
|
||||
version: 0.7.1-dev
|
||||
groups:
|
||||
- cpp
|
||||
- queries
|
||||
|
||||
@@ -4,8 +4,9 @@ edges
|
||||
| test.cpp:19:9:19:16 | mk_array indirection [p] | test.cpp:28:19:28:26 | call to mk_array [p] |
|
||||
| test.cpp:19:9:19:16 | mk_array indirection [p] | test.cpp:50:18:50:25 | call to mk_array [p] |
|
||||
| test.cpp:21:5:21:24 | ... = ... | test.cpp:21:9:21:9 | arr indirection [post update] [p] |
|
||||
| test.cpp:21:9:21:9 | arr indirection [post update] [p] | test.cpp:19:9:19:16 | mk_array indirection [p] |
|
||||
| test.cpp:21:9:21:9 | arr indirection [post update] [p] | test.cpp:22:5:22:7 | arr indirection [p] |
|
||||
| test.cpp:21:13:21:18 | call to malloc | test.cpp:21:5:21:24 | ... = ... |
|
||||
| test.cpp:22:5:22:7 | arr indirection [p] | test.cpp:19:9:19:16 | mk_array indirection [p] |
|
||||
| test.cpp:28:19:28:26 | call to mk_array [p] | test.cpp:31:9:31:11 | arr indirection [p] |
|
||||
| test.cpp:28:19:28:26 | call to mk_array [p] | test.cpp:35:9:35:11 | arr indirection [p] |
|
||||
| test.cpp:31:9:31:11 | arr indirection [p] | test.cpp:31:13:31:13 | p indirection |
|
||||
@@ -20,9 +21,10 @@ edges
|
||||
| test.cpp:45:13:45:13 | p indirection | test.cpp:45:13:45:13 | p |
|
||||
| test.cpp:50:18:50:25 | call to mk_array [p] | test.cpp:39:27:39:29 | arr [p] |
|
||||
| test.cpp:55:5:55:24 | ... = ... | test.cpp:55:9:55:9 | arr indirection [post update] [p] |
|
||||
| test.cpp:55:9:55:9 | arr indirection [post update] [p] | test.cpp:59:9:59:11 | arr indirection [p] |
|
||||
| test.cpp:55:9:55:9 | arr indirection [post update] [p] | test.cpp:63:9:63:11 | arr indirection [p] |
|
||||
| test.cpp:55:9:55:9 | arr indirection [post update] [p] | test.cpp:56:5:56:7 | arr indirection [p] |
|
||||
| test.cpp:55:13:55:18 | call to malloc | test.cpp:55:5:55:24 | ... = ... |
|
||||
| test.cpp:56:5:56:7 | arr indirection [p] | test.cpp:59:9:59:11 | arr indirection [p] |
|
||||
| test.cpp:56:5:56:7 | arr indirection [p] | test.cpp:63:9:63:11 | arr indirection [p] |
|
||||
| test.cpp:59:9:59:11 | arr indirection [p] | test.cpp:59:13:59:13 | p indirection |
|
||||
| test.cpp:59:13:59:13 | p indirection | test.cpp:59:13:59:13 | p |
|
||||
| test.cpp:63:9:63:11 | arr indirection [p] | test.cpp:63:13:63:13 | p indirection |
|
||||
@@ -30,8 +32,9 @@ edges
|
||||
| test.cpp:67:10:67:19 | mk_array_p indirection [p] | test.cpp:76:20:76:29 | call to mk_array_p indirection [p] |
|
||||
| test.cpp:67:10:67:19 | mk_array_p indirection [p] | test.cpp:98:18:98:27 | call to mk_array_p indirection [p] |
|
||||
| test.cpp:69:5:69:25 | ... = ... | test.cpp:69:10:69:10 | arr indirection [post update] [p] |
|
||||
| test.cpp:69:10:69:10 | arr indirection [post update] [p] | test.cpp:67:10:67:19 | mk_array_p indirection [p] |
|
||||
| test.cpp:69:10:69:10 | arr indirection [post update] [p] | test.cpp:70:5:70:7 | arr indirection [p] |
|
||||
| test.cpp:69:14:69:19 | call to malloc | test.cpp:69:5:69:25 | ... = ... |
|
||||
| test.cpp:70:5:70:7 | arr indirection [p] | test.cpp:67:10:67:19 | mk_array_p indirection [p] |
|
||||
| test.cpp:76:20:76:29 | call to mk_array_p indirection [p] | test.cpp:79:9:79:11 | arr indirection [p] |
|
||||
| test.cpp:76:20:76:29 | call to mk_array_p indirection [p] | test.cpp:83:9:83:11 | arr indirection [p] |
|
||||
| test.cpp:79:9:79:11 | arr indirection [p] | test.cpp:79:14:79:14 | p indirection |
|
||||
@@ -53,6 +56,7 @@ nodes
|
||||
| test.cpp:21:5:21:24 | ... = ... | semmle.label | ... = ... |
|
||||
| test.cpp:21:9:21:9 | arr indirection [post update] [p] | semmle.label | arr indirection [post update] [p] |
|
||||
| test.cpp:21:13:21:18 | call to malloc | semmle.label | call to malloc |
|
||||
| test.cpp:22:5:22:7 | arr indirection [p] | semmle.label | arr indirection [p] |
|
||||
| test.cpp:28:19:28:26 | call to mk_array [p] | semmle.label | call to mk_array [p] |
|
||||
| test.cpp:31:9:31:11 | arr indirection [p] | semmle.label | arr indirection [p] |
|
||||
| test.cpp:31:13:31:13 | p | semmle.label | p |
|
||||
@@ -71,6 +75,7 @@ nodes
|
||||
| test.cpp:55:5:55:24 | ... = ... | semmle.label | ... = ... |
|
||||
| test.cpp:55:9:55:9 | arr indirection [post update] [p] | semmle.label | arr indirection [post update] [p] |
|
||||
| test.cpp:55:13:55:18 | call to malloc | semmle.label | call to malloc |
|
||||
| test.cpp:56:5:56:7 | arr indirection [p] | semmle.label | arr indirection [p] |
|
||||
| test.cpp:59:9:59:11 | arr indirection [p] | semmle.label | arr indirection [p] |
|
||||
| test.cpp:59:13:59:13 | p | semmle.label | p |
|
||||
| test.cpp:59:13:59:13 | p indirection | semmle.label | p indirection |
|
||||
@@ -81,6 +86,7 @@ nodes
|
||||
| test.cpp:69:5:69:25 | ... = ... | semmle.label | ... = ... |
|
||||
| test.cpp:69:10:69:10 | arr indirection [post update] [p] | semmle.label | arr indirection [post update] [p] |
|
||||
| test.cpp:69:14:69:19 | call to malloc | semmle.label | call to malloc |
|
||||
| test.cpp:70:5:70:7 | arr indirection [p] | semmle.label | arr indirection [p] |
|
||||
| test.cpp:76:20:76:29 | call to mk_array_p indirection [p] | semmle.label | call to mk_array_p indirection [p] |
|
||||
| test.cpp:79:9:79:11 | arr indirection [p] | semmle.label | arr indirection [p] |
|
||||
| test.cpp:79:14:79:14 | p | semmle.label | p |
|
||||
|
||||
@@ -1,38 +1,177 @@
|
||||
edges
|
||||
| test.cpp:34:10:34:12 | buf | test.cpp:34:5:34:24 | access to array |
|
||||
| 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:39:14:39:16 | buf | test.cpp:39:9:39:19 | access to array |
|
||||
| test.cpp:43:14:43:16 | buf | test.cpp:43:9:43:19 | access to array |
|
||||
| test.cpp:48:10:48:12 | buf | test.cpp:48:5:48:24 | 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:53:14:53:16 | buf | test.cpp:53:9:53:19 | 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:71:5:71:17 | access to array |
|
||||
| test.cpp:70:33:70:33 | p | test.cpp:72:5:72:15 | access to array |
|
||||
| test.cpp:76:26:76:46 | & ... | test.cpp:66:32:66:32 | p |
|
||||
| test.cpp:76:32:76:34 | buf | test.cpp:76:26:76:46 | & ... |
|
||||
| test.cpp:77:26:77:44 | & ... | test.cpp:66:32:66:32 | p |
|
||||
| test.cpp:77:32:77:34 | buf | test.cpp:77:26:77:44 | & ... |
|
||||
| test.cpp:79:27:79:34 | buf | test.cpp:70:33:70:33 | p |
|
||||
| test.cpp:79:32:79:34 | buf | test.cpp:79:27:79:34 | buf |
|
||||
| test.cpp:85:34:85:36 | buf | test.cpp:87:5:87:31 | access to array |
|
||||
| test.cpp:85:34:85:36 | buf | test.cpp:88:5:88:27 | access to array |
|
||||
| test.cpp:96:13:96:15 | arr | test.cpp:96:13:96:18 | access to array |
|
||||
| test.cpp:111:17:111:19 | arr | test.cpp:111:17:111:22 | access to array |
|
||||
| test.cpp:111:17:111:19 | arr | test.cpp:115:35:115:40 | access to array |
|
||||
| test.cpp:111:17:111:19 | arr | test.cpp:119:17:119:22 | access to array |
|
||||
| test.cpp:115:35:115:37 | arr | test.cpp:111:17:111:22 | access to array |
|
||||
| test.cpp:115:35:115:37 | arr | test.cpp:115:35:115:40 | access to array |
|
||||
| test.cpp:115:35:115:37 | arr | test.cpp:119:17:119:22 | access to array |
|
||||
| test.cpp:119:17:119:19 | arr | test.cpp:111:17:111:22 | access to array |
|
||||
| test.cpp:119:17:119:19 | arr | test.cpp:115:35:115:40 | access to array |
|
||||
| test.cpp:119:17:119:19 | arr | test.cpp:119:17:119:22 | access to array |
|
||||
| test.cpp:128:9:128:11 | arr | test.cpp:128:9:128:14 | access to array |
|
||||
| test.cpp:134:25:134:27 | arr | test.cpp:136:9:136:16 | ... += ... |
|
||||
| test.cpp:136:9:136:16 | ... += ... | test.cpp:138:13:138:15 | arr |
|
||||
| test.cpp:143:18:143:21 | asdf | test.cpp:134:25:134:27 | arr |
|
||||
| test.cpp:143:18:143:21 | asdf | test.cpp:143:18:143:21 | asdf |
|
||||
| test.cpp:146:26:146:26 | p indirection | test.cpp:148:6:148:9 | * ... |
|
||||
| test.cpp:156:12:156:14 | buf | test.cpp:156:12:156:18 | ... + ... |
|
||||
| test.cpp:156:12:156:18 | ... + ... | test.cpp:158:17:158:18 | & ... indirection |
|
||||
| test.cpp:158:17:158:18 | & ... indirection | test.cpp:146:26:146:26 | p indirection |
|
||||
| test.cpp:218:23:218:28 | buffer | test.cpp:220:5:220:11 | access to array |
|
||||
| test.cpp:218:23:218:28 | buffer | test.cpp:221:5:221:11 | access to array |
|
||||
| test.cpp:229:25:229:29 | array | test.cpp:231:5:231:10 | access to array |
|
||||
| test.cpp:229:25:229:29 | array | test.cpp:232:5:232:10 | access to array |
|
||||
| test.cpp:245:30:245:30 | p | test.cpp:261:27:261:30 | access to array |
|
||||
| test.cpp:245:30:245:30 | p | test.cpp:261:27:261:30 | access to array |
|
||||
| test.cpp:274:14:274:20 | buffer3 | test.cpp:245:30:245:30 | p |
|
||||
| test.cpp:274:14:274:20 | buffer3 | test.cpp:274:14:274:20 | buffer3 |
|
||||
| test.cpp:277:35:277:35 | p | test.cpp:278:14:278:14 | p |
|
||||
| test.cpp:278:14:278:14 | p | test.cpp:245:30:245:30 | p |
|
||||
| test.cpp:283:19:283:25 | buffer1 | test.cpp:277:35:277:35 | p |
|
||||
| test.cpp:283:19:283:25 | buffer1 | test.cpp:283:19:283:25 | buffer1 |
|
||||
| test.cpp:286:19:286:25 | buffer2 | test.cpp:277:35:277:35 | p |
|
||||
| test.cpp:286:19:286:25 | buffer2 | test.cpp:286:19:286:25 | buffer2 |
|
||||
| test.cpp:289:19:289:25 | buffer3 | test.cpp:277:35:277:35 | p |
|
||||
| test.cpp:289:19:289:25 | buffer3 | test.cpp:289:19:289:25 | buffer3 |
|
||||
| test.cpp:292:25:292:27 | arr | test.cpp:299:16:299:21 | access to array |
|
||||
| test.cpp:292:25:292:27 | arr | test.cpp:299:16:299:21 | access to array |
|
||||
| test.cpp:306:20:306:23 | arr1 | test.cpp:292:25:292:27 | arr |
|
||||
| test.cpp:306:20:306:23 | arr1 | test.cpp:306:20:306:23 | arr1 |
|
||||
| test.cpp:309:20:309:23 | arr2 | test.cpp:292:25:292:27 | arr |
|
||||
| test.cpp:309:20:309:23 | arr2 | test.cpp:309:20:309:23 | arr2 |
|
||||
| test.cpp:319:19:319:22 | temp | test.cpp:319:19:319:27 | ... + ... |
|
||||
| test.cpp:319:19:319:22 | temp | test.cpp:324:23:324:32 | ... + ... |
|
||||
| test.cpp:319:19:319:27 | ... + ... | test.cpp:325:24:325:26 | end |
|
||||
| test.cpp:322:19:322:22 | temp | test.cpp:322:19:322:27 | ... + ... |
|
||||
| test.cpp:322:19:322:22 | temp | test.cpp:324:23:324:32 | ... + ... |
|
||||
| test.cpp:322:19:322:27 | ... + ... | test.cpp:325:24:325:26 | end |
|
||||
| test.cpp:324:23:324:26 | temp | test.cpp:324:23:324:32 | ... + ... |
|
||||
| test.cpp:324:23:324:32 | ... + ... | test.cpp:325:15:325:19 | temp2 |
|
||||
| test.cpp:351:9:351:11 | arr | test.cpp:351:9:351:14 | access to array |
|
||||
| test.cpp:351:9:351:11 | arr | test.cpp:351:18:351:25 | access to array |
|
||||
| test.cpp:351:18:351:20 | arr | test.cpp:351:9:351:14 | access to array |
|
||||
| test.cpp:351:18:351:20 | arr | test.cpp:351:18:351:25 | access to array |
|
||||
| test.cpp:351:29:351:31 | arr | test.cpp:351:9:351:14 | access to array |
|
||||
| test.cpp:351:29:351:31 | arr | test.cpp:351:18:351:25 | access to array |
|
||||
nodes
|
||||
| test.cpp:34:5:34:24 | access to array | semmle.label | access to array |
|
||||
| test.cpp:34:10:34:12 | buf | semmle.label | buf |
|
||||
| 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:39:9:39:19 | access to array | semmle.label | access to array |
|
||||
| test.cpp:39:14:39:16 | 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:48:5:48:24 | access to array | semmle.label | access to array |
|
||||
| test.cpp:48:10:48:12 | 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:53:9:53:19 | access to array | semmle.label | access to array |
|
||||
| test.cpp:53:14:53:16 | 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:70:33:70:33 | p | semmle.label | p |
|
||||
| test.cpp:71:5:71:17 | access to array | semmle.label | access to array |
|
||||
| test.cpp:72:5:72:15 | access to array | semmle.label | access to array |
|
||||
| test.cpp:76:26:76:46 | & ... | semmle.label | & ... |
|
||||
| test.cpp:76:32:76:34 | buf | semmle.label | buf |
|
||||
| test.cpp:77:26:77:44 | & ... | semmle.label | & ... |
|
||||
| test.cpp:77:32:77:34 | buf | semmle.label | buf |
|
||||
| test.cpp:79:27:79:34 | buf | semmle.label | buf |
|
||||
| test.cpp:79:32:79:34 | buf | semmle.label | buf |
|
||||
| test.cpp:85:34:85:36 | buf | semmle.label | buf |
|
||||
| test.cpp:87:5:87:31 | access to array | semmle.label | access to array |
|
||||
| test.cpp:88:5:88:27 | access to array | semmle.label | access to array |
|
||||
| test.cpp:96:13:96:15 | arr | semmle.label | arr |
|
||||
| test.cpp:96:13:96:18 | access to array | semmle.label | access to array |
|
||||
| test.cpp:111:17:111:19 | arr | semmle.label | arr |
|
||||
| test.cpp:111:17:111:22 | access to array | semmle.label | access to array |
|
||||
| test.cpp:115:35:115:37 | arr | semmle.label | arr |
|
||||
| test.cpp:115:35:115:40 | access to array | semmle.label | access to array |
|
||||
| test.cpp:119:17:119:19 | arr | semmle.label | arr |
|
||||
| test.cpp:119:17:119:22 | access to array | semmle.label | access to array |
|
||||
| test.cpp:128:9:128:11 | arr | semmle.label | arr |
|
||||
| test.cpp:128:9:128:14 | access to array | semmle.label | access to array |
|
||||
| test.cpp:134:25:134:27 | arr | semmle.label | arr |
|
||||
| test.cpp:136:9:136:16 | ... += ... | semmle.label | ... += ... |
|
||||
| test.cpp:138:13:138:15 | arr | semmle.label | arr |
|
||||
| test.cpp:143:18:143:21 | asdf | semmle.label | asdf |
|
||||
| test.cpp:143:18:143:21 | asdf | semmle.label | asdf |
|
||||
| test.cpp:146:26:146:26 | p indirection | semmle.label | p indirection |
|
||||
| test.cpp:148:6:148:9 | * ... | semmle.label | * ... |
|
||||
| test.cpp:156:12:156:14 | buf | semmle.label | buf |
|
||||
| test.cpp:156:12:156:18 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:158:17:158:18 | & ... indirection | semmle.label | & ... indirection |
|
||||
| test.cpp:218:23:218:28 | buffer | semmle.label | buffer |
|
||||
| test.cpp:220:5:220:11 | access to array | semmle.label | access to array |
|
||||
| test.cpp:221:5:221:11 | access to array | semmle.label | access to array |
|
||||
| test.cpp:229:25:229:29 | array | semmle.label | array |
|
||||
| test.cpp:231:5:231:10 | access to array | semmle.label | access to array |
|
||||
| test.cpp:232:5:232:10 | access to array | semmle.label | access to array |
|
||||
| test.cpp:245:30:245:30 | p | semmle.label | p |
|
||||
| test.cpp:245:30:245:30 | p | semmle.label | p |
|
||||
| test.cpp:261:27:261:30 | access to array | semmle.label | access to array |
|
||||
| test.cpp:274:14:274:20 | buffer3 | semmle.label | buffer3 |
|
||||
| test.cpp:274:14:274:20 | buffer3 | semmle.label | buffer3 |
|
||||
| test.cpp:277:35:277:35 | p | semmle.label | p |
|
||||
| test.cpp:278:14:278:14 | p | semmle.label | p |
|
||||
| test.cpp:283:19:283:25 | buffer1 | semmle.label | buffer1 |
|
||||
| test.cpp:283:19:283:25 | buffer1 | semmle.label | buffer1 |
|
||||
| test.cpp:286:19:286:25 | buffer2 | semmle.label | buffer2 |
|
||||
| test.cpp:286:19:286:25 | buffer2 | semmle.label | buffer2 |
|
||||
| test.cpp:289:19:289:25 | buffer3 | semmle.label | buffer3 |
|
||||
| test.cpp:289:19:289:25 | buffer3 | semmle.label | buffer3 |
|
||||
| test.cpp:292:25:292:27 | arr | semmle.label | arr |
|
||||
| test.cpp:292:25:292:27 | arr | semmle.label | arr |
|
||||
| test.cpp:299:16:299:21 | access to array | semmle.label | access to array |
|
||||
| test.cpp:306:20:306:23 | arr1 | semmle.label | arr1 |
|
||||
| test.cpp:306:20:306:23 | arr1 | semmle.label | arr1 |
|
||||
| test.cpp:309:20:309:23 | arr2 | semmle.label | arr2 |
|
||||
| test.cpp:309:20:309:23 | arr2 | semmle.label | arr2 |
|
||||
| test.cpp:319:19:319:22 | temp | semmle.label | temp |
|
||||
| test.cpp:319:19:319:27 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:322:19:322:22 | temp | semmle.label | temp |
|
||||
| test.cpp:322:19:322:27 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:324:23:324:26 | temp | semmle.label | temp |
|
||||
| test.cpp:324:23:324:32 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:325:15:325:19 | temp2 | semmle.label | temp2 |
|
||||
| test.cpp:325:24:325:26 | end | semmle.label | end |
|
||||
| test.cpp:325:24:325:26 | end | semmle.label | end |
|
||||
| test.cpp:351:9:351:11 | arr | semmle.label | arr |
|
||||
| test.cpp:351:9:351:14 | access to array | semmle.label | access to array |
|
||||
| test.cpp:351:18:351:20 | arr | semmle.label | arr |
|
||||
| test.cpp:351:18:351:25 | access to array | semmle.label | access to array |
|
||||
| test.cpp:351:29:351:31 | arr | semmle.label | arr |
|
||||
subpaths
|
||||
#select
|
||||
| test.cpp:35:5:35:22 | PointerAdd: access to array | test.cpp:35:10:35:12 | buf | test.cpp:35:5:35:22 | access to array | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:15:9:15:11 | buf | buf | test.cpp:35:5:35:26 | Store: ... = ... | write |
|
||||
@@ -44,3 +183,17 @@ subpaths
|
||||
| test.cpp:61:9:61:19 | PointerAdd: access to array | test.cpp:61:14:61:16 | buf | test.cpp:61:9:61:19 | access to array | This pointer arithmetic may have an off-by-2 error allowing it to overrun $@ at this $@. | test.cpp:19:9:19:11 | buf | buf | test.cpp:61:9:61:23 | Store: ... = ... | write |
|
||||
| test.cpp:72:5:72:15 | PointerAdd: access to array | test.cpp:79:32:79:34 | buf | test.cpp:72:5:72:15 | access to array | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:15:9:15:11 | buf | buf | test.cpp:72:5:72:19 | Store: ... = ... | write |
|
||||
| test.cpp:77:27:77:44 | PointerAdd: access to array | test.cpp:77:32:77:34 | buf | test.cpp:66:32:66:32 | p | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:15:9:15:11 | buf | buf | test.cpp:67:5:67:10 | Store: ... = ... | write |
|
||||
| test.cpp:88:5:88:27 | PointerAdd: access to array | test.cpp:85:34:85:36 | buf | test.cpp:88:5:88:27 | 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:88:5:88:31 | Store: ... = ... | write |
|
||||
| test.cpp:128:9:128:14 | PointerAdd: access to array | test.cpp:128:9:128:11 | arr | test.cpp:128:9:128:14 | access to array | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:125:11:125:13 | arr | arr | test.cpp:128:9:128:18 | Store: ... = ... | write |
|
||||
| test.cpp:136:9:136:16 | PointerAdd: ... += ... | test.cpp:143:18:143:21 | asdf | test.cpp:138:13:138:15 | arr | This pointer arithmetic may have an off-by-2 error allowing it to overrun $@ at this $@. | test.cpp:142:10:142:13 | asdf | asdf | test.cpp:138:12:138:15 | Load: * ... | read |
|
||||
| test.cpp:156:12:156:18 | PointerAdd: ... + ... | test.cpp:156:12:156:14 | buf | test.cpp:148:6:148:9 | * ... | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:154:7:154:9 | buf | buf | test.cpp:147:3:147:13 | Store: ... = ... | write |
|
||||
| test.cpp:221:5:221:11 | PointerAdd: access to array | test.cpp:218:23:218:28 | buffer | test.cpp:221:5:221:11 | access to array | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:217:19:217:24 | buffer | buffer | test.cpp:221:5:221:15 | Store: ... = ... | write |
|
||||
| test.cpp:232:5:232:10 | PointerAdd: access to array | test.cpp:229:25:229:29 | array | test.cpp:232:5:232:10 | access to array | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:228:10:228:14 | array | array | test.cpp:232:5:232:19 | Store: ... = ... | write |
|
||||
| test.cpp:261:27:261:30 | PointerAdd: access to array | test.cpp:286:19:286:25 | buffer2 | test.cpp:261:27:261:30 | access to array | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:285:19:285:25 | buffer2 | buffer2 | test.cpp:261:27:261:30 | Load: access to array | read |
|
||||
| test.cpp:299:16:299:21 | PointerAdd: access to array | test.cpp:309:20:309:23 | arr2 | test.cpp:299:16:299:21 | access to array | This pointer arithmetic may have an off-by-1014 error allowing it to overrun $@ at this $@. | test.cpp:308:9:308:12 | arr2 | arr2 | test.cpp:299:16:299:21 | Load: access to array | read |
|
||||
| test.cpp:322:19:322:27 | PointerAdd: ... + ... | test.cpp:322:19:322:22 | temp | test.cpp:325:24:325:26 | end | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:314:10:314:13 | temp | temp | test.cpp:330:13:330:24 | Store: ... = ... | write |
|
||||
| test.cpp:322:19:322:27 | PointerAdd: ... + ... | test.cpp:322:19:322:22 | temp | test.cpp:325:24:325:26 | end | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:314:10:314:13 | temp | temp | test.cpp:331:13:331:24 | Store: ... = ... | write |
|
||||
| test.cpp:322:19:322:27 | PointerAdd: ... + ... | test.cpp:322:19:322:22 | temp | test.cpp:325:24:325:26 | end | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:314:10:314:13 | temp | temp | test.cpp:333:13:333:24 | Store: ... = ... | write |
|
||||
| test.cpp:351:18:351:25 | PointerAdd: access to array | test.cpp:351:9:351:11 | arr | test.cpp:351:18:351:25 | access to array | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:348:9:348:11 | arr | arr | test.cpp:351:18:351:25 | Load: access to array | read |
|
||||
| test.cpp:351:18:351:25 | PointerAdd: access to array | test.cpp:351:18:351:20 | arr | test.cpp:351:18:351:25 | access to array | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:348:9:348:11 | arr | arr | test.cpp:351:18:351:25 | Load: access to array | read |
|
||||
| test.cpp:351:18:351:25 | PointerAdd: access to array | test.cpp:351:29:351:31 | arr | test.cpp:351:18:351:25 | access to array | This pointer arithmetic may have an off-by-1 error allowing it to overrun $@ at this $@. | test.cpp:348:9:348:11 | arr | arr | test.cpp:351:18:351:25 | Load: access to array | read |
|
||||
|
||||
@@ -85,7 +85,7 @@ void testCharIndex(BigArray *arr) {
|
||||
char *charBuf = (char*) arr->buf;
|
||||
|
||||
charBuf[MAX_SIZE_BYTES - 1] = 0; // GOOD
|
||||
charBuf[MAX_SIZE_BYTES] = 0; // BAD [FALSE NEGATIVE]
|
||||
charBuf[MAX_SIZE_BYTES] = 0; // BAD
|
||||
}
|
||||
|
||||
void testEqRefinement() {
|
||||
@@ -120,3 +120,235 @@ void testEqRefinement2() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void testStackAllocated() {
|
||||
char *arr[MAX_SIZE];
|
||||
|
||||
for(int i = 0; i <= MAX_SIZE; i++) {
|
||||
arr[i] = 0; // BAD
|
||||
}
|
||||
}
|
||||
|
||||
int strncmp(const char*, const char*, int);
|
||||
|
||||
char testStrncmp2(char *arr) {
|
||||
if(strncmp(arr, "<test>", 6) == 0) {
|
||||
arr += 6;
|
||||
}
|
||||
return *arr; // GOOD [FALSE POSITIVE]
|
||||
}
|
||||
|
||||
void testStrncmp1() {
|
||||
char asdf[5];
|
||||
testStrncmp2(asdf);
|
||||
}
|
||||
|
||||
void countdownBuf1(int **p) {
|
||||
*--(*p) = 1; // GOOD [FALSE POSITIVE]
|
||||
*--(*p) = 2; // GOOD
|
||||
*--(*p) = 3; // GOOD
|
||||
*--(*p) = 4; // GOOD
|
||||
}
|
||||
|
||||
void countdownBuf2() {
|
||||
int buf[4];
|
||||
|
||||
int *x = buf + 4;
|
||||
|
||||
countdownBuf1(&x);
|
||||
}
|
||||
|
||||
int access(int *p) {
|
||||
return p[0];
|
||||
}
|
||||
|
||||
|
||||
// unrolled loop style seen in crypto code.
|
||||
int countdownLength1(int *p, int len) {
|
||||
while(len > 0) {
|
||||
access(p);
|
||||
p[1] = 1;
|
||||
p[2] = 2;
|
||||
p[3] = 3;
|
||||
p[4] = 4;
|
||||
p[5] = 5;
|
||||
p[6] = 6; // BAD [FALSE NEGATIVE]
|
||||
p[7] = 7; // BAD [FALSE NEGATIVE]
|
||||
p += 8;
|
||||
len -= 8;
|
||||
}
|
||||
|
||||
return p[5];
|
||||
}
|
||||
|
||||
int callCountdownLength() {
|
||||
|
||||
int buf[6];
|
||||
|
||||
return countdownLength1(buf, 6);
|
||||
}
|
||||
|
||||
int countdownLength2() {
|
||||
int buf[6];
|
||||
int len = 6;
|
||||
int *p = buf;
|
||||
|
||||
if(len % 8) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
while(len > 0) {
|
||||
p[0] = 0;
|
||||
p[1] = 1;
|
||||
p[2] = 2;
|
||||
p[3] = 3;
|
||||
p[4] = 4;
|
||||
p[5] = 5;
|
||||
p[6] = 6; // GOOD
|
||||
p[7] = 7; // GOOD
|
||||
p += 8;
|
||||
len -= 8;
|
||||
}
|
||||
|
||||
return p[5];
|
||||
}
|
||||
|
||||
void pointer_size_larger_than_array_element_size() {
|
||||
unsigned char buffer[100]; // getByteSize() = 100
|
||||
int *ptr = (int *)buffer; // pai.getElementSize() will be sizeof(int) = 4 -> size = 25
|
||||
|
||||
ptr[24] = 0; // GOOD: writes bytes 96, 97, 98, 99
|
||||
ptr[25] = 0; // BAD: writes bytes 100, 101, 102, 103
|
||||
}
|
||||
|
||||
struct vec2 { int x, y; };
|
||||
struct vec3 { int x, y, z; };
|
||||
|
||||
void pointer_size_smaller_than_array_element_size_but_does_not_divide_it() {
|
||||
vec3 array[3]; // getByteSize() = 9 * sizeof(int)
|
||||
vec2 *ptr = (vec2 *)array; // pai.getElementSize() will be 2 * sizeof(int) -> size = 4
|
||||
|
||||
ptr[3] = vec2{}; // GOOD: writes ints 6, 7
|
||||
ptr[4] = vec2{}; // BAD: writes ints 8, 9
|
||||
}
|
||||
|
||||
void pointer_size_larger_than_array_element_size_and_does_not_divide_it() {
|
||||
vec2 array[2]; // getByteSize() = 4 * sizeof(int) = 4 * 4 = 16
|
||||
vec3 *ptr = (vec3 *)array; // pai.getElementSize() will be 3 * sizeof(int) -> size = 1
|
||||
|
||||
ptr[0] = vec3{}; // GOOD: writes ints 0, 1, 2
|
||||
ptr[1] = vec3{}; // BAD: writes ints 3, 4, 5 [NOT DETECTED]
|
||||
}
|
||||
|
||||
void use(...);
|
||||
|
||||
void call_use(unsigned char* p, int n) {
|
||||
if(n == 0) {
|
||||
return;
|
||||
}
|
||||
if(n == 1) {
|
||||
unsigned char x = p[0];
|
||||
use(x);
|
||||
}
|
||||
if(n == 2) {
|
||||
unsigned char x = p[0];
|
||||
unsigned char y = p[1];
|
||||
use(x, y);
|
||||
}
|
||||
if(n == 3) {
|
||||
unsigned char x = p[0];
|
||||
unsigned char y = p[1];
|
||||
unsigned char z = p[2]; // GOOD [FALSE POSITIVE]: `call_use(buffer2, 2)` won't reach this point.
|
||||
use(x, y, z);
|
||||
}
|
||||
}
|
||||
|
||||
void test_call_use() {
|
||||
unsigned char buffer1[1];
|
||||
call_use(buffer1,1);
|
||||
|
||||
unsigned char buffer2[2];
|
||||
call_use(buffer2,2);
|
||||
|
||||
unsigned char buffer3[3];
|
||||
call_use(buffer3,3);
|
||||
}
|
||||
|
||||
void call_call_use(unsigned char* p, int n) {
|
||||
call_use(p, n);
|
||||
}
|
||||
|
||||
void test_call_use2() {
|
||||
unsigned char buffer1[1];
|
||||
call_call_use(buffer1,1);
|
||||
|
||||
unsigned char buffer2[2];
|
||||
call_call_use(buffer2,2);
|
||||
|
||||
unsigned char buffer3[3];
|
||||
call_call_use(buffer3,3);
|
||||
}
|
||||
|
||||
int guardingCallee(int *arr, int size) {
|
||||
if (size > MAX_SIZE) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int sum;
|
||||
for (int i = 0; i < size; i++) {
|
||||
sum += arr[i]; // GOOD [FALSE POSITIVE] - guarded by size
|
||||
}
|
||||
return sum;
|
||||
}
|
||||
|
||||
int guardingCaller() {
|
||||
int arr1[MAX_SIZE];
|
||||
guardingCallee(arr1, MAX_SIZE);
|
||||
|
||||
int arr2[10];
|
||||
guardingCallee(arr2, 10);
|
||||
}
|
||||
|
||||
// simplified md5 padding
|
||||
void correlatedCondition(int num) {
|
||||
char temp[64];
|
||||
|
||||
char *end;
|
||||
if(num < 64) {
|
||||
if (num < 56) {
|
||||
end = temp + 56;
|
||||
}
|
||||
else if (num < 64) {
|
||||
end = temp + 64; // GOOD [FALSE POSITVE]
|
||||
}
|
||||
char *temp2 = temp + num;
|
||||
while(temp2 != end) {
|
||||
*temp2 = 0;
|
||||
temp2++;
|
||||
}
|
||||
if(num < 56) {
|
||||
temp2[0] = 0;
|
||||
temp2[1] = 0;
|
||||
// ...
|
||||
temp2[7] = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int positiveRange(int x) {
|
||||
if (x < 40) {
|
||||
return -1;
|
||||
}
|
||||
if (x > 1024) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
int offset = (unsigned char)(x + 7)/8;
|
||||
|
||||
int arr[128];
|
||||
|
||||
for(int i=127-offset; i>= 0; i--) {
|
||||
arr[i] = arr[i+1] + arr[i+offset]; // GOOD [FALSE POSITIVE]
|
||||
}
|
||||
return arr[0];
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.security.InvalidPointerDereference.AllocationToInvalidPointer
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
import semmle.code.cpp.ir.IR
|
||||
import semmle.code.cpp.dataflow.new.DataFlow
|
||||
|
||||
module AllocationToInvalidPointerTest implements TestSig {
|
||||
string getARelevantTag() { result = "alloc" }
|
||||
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(DataFlow::Node allocation, PointerAddInstruction pai, int delta |
|
||||
pointerAddInstructionHasBounds(allocation, pai, _, delta) and
|
||||
location = pai.getLocation() and
|
||||
element = pai.toString() and
|
||||
tag = "alloc"
|
||||
|
|
||||
delta > 0 and
|
||||
value = "L" + allocation.getLocation().getStartLine().toString() + "+" + delta.toString()
|
||||
or
|
||||
delta = 0 and
|
||||
value = "L" + allocation.getLocation().getStartLine().toString()
|
||||
or
|
||||
delta < 0 and
|
||||
value = "L" + allocation.getLocation().getStartLine().toString() + "-" + (-delta).toString()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
import MakeTest<AllocationToInvalidPointerTest>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
||||
failures
|
||||
testFailures
|
||||
@@ -0,0 +1,81 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.security.InvalidPointerDereference.InvalidPointerToDereference
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
import semmle.code.cpp.ir.IR
|
||||
import semmle.code.cpp.dataflow.new.DataFlow
|
||||
|
||||
string case3(DataFlow::Node derefSource, DataFlow::Node derefSink, DataFlow::Node operation) {
|
||||
operationIsOffBy(_, _, derefSource, derefSink, _, operation, _) and
|
||||
not exists(case2(_, _, operation)) and
|
||||
not exists(case1(_, _, operation)) and
|
||||
exists(int derefSourceLine, int derefSinkLine, int operationLine |
|
||||
derefSourceLine = derefSource.getLocation().getStartLine() and
|
||||
derefSinkLine = derefSink.getLocation().getStartLine() and
|
||||
operationLine = operation.getLocation().getStartLine() and
|
||||
derefSourceLine != derefSinkLine and
|
||||
derefSinkLine != operationLine and
|
||||
result = "L" + derefSourceLine + "->L" + derefSinkLine + "->L" + operationLine
|
||||
)
|
||||
}
|
||||
|
||||
string case2(DataFlow::Node derefSource, DataFlow::Node derefSink, DataFlow::Node operation) {
|
||||
operationIsOffBy(_, _, derefSource, derefSink, _, operation, _) and
|
||||
not exists(case1(_, _, operation)) and
|
||||
exists(int derefSourceLine, int derefSinkLine, int operationLine |
|
||||
derefSourceLine = derefSource.getLocation().getStartLine() and
|
||||
derefSinkLine = derefSink.getLocation().getStartLine() and
|
||||
operationLine = operation.getLocation().getStartLine() and
|
||||
derefSourceLine = derefSinkLine and
|
||||
derefSinkLine != operationLine and
|
||||
result = "L" + derefSourceLine + "->L" + operationLine
|
||||
)
|
||||
}
|
||||
|
||||
string case1(DataFlow::Node derefSource, DataFlow::Node derefSink, DataFlow::Node operation) {
|
||||
operationIsOffBy(_, _, derefSource, derefSink, _, operation, _) and
|
||||
exists(int derefSourceLine, int derefSinkLine, int operationLine |
|
||||
derefSourceLine = derefSource.getLocation().getStartLine() and
|
||||
derefSinkLine = derefSink.getLocation().getStartLine() and
|
||||
operationLine = operation.getLocation().getStartLine() and
|
||||
derefSourceLine = derefSinkLine and
|
||||
derefSinkLine = operationLine and
|
||||
result = "L" + derefSourceLine
|
||||
)
|
||||
}
|
||||
|
||||
module InvalidPointerToDereferenceTest implements TestSig {
|
||||
string getARelevantTag() { result = "deref" }
|
||||
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(
|
||||
DataFlow::Node derefSource, DataFlow::Node derefSink, DataFlow::Node operation, int delta,
|
||||
string value1, string value2
|
||||
|
|
||||
operationIsOffBy(_, _, derefSource, derefSink, _, operation, delta) and
|
||||
location = operation.getLocation() and
|
||||
element = operation.toString() and
|
||||
tag = "deref" and
|
||||
value = value1 + value2
|
||||
|
|
||||
(
|
||||
value1 = case3(derefSource, derefSink, operation)
|
||||
or
|
||||
value1 = case2(derefSource, derefSink, operation)
|
||||
or
|
||||
value1 = case1(derefSource, derefSink, operation)
|
||||
) and
|
||||
(
|
||||
delta > 0 and
|
||||
value2 = "+" + delta
|
||||
or
|
||||
delta = 0 and
|
||||
value2 = ""
|
||||
or
|
||||
delta < 0 and
|
||||
value2 = "-" + (-delta)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
import MakeTest<InvalidPointerToDereferenceTest>
|
||||
@@ -2,10 +2,10 @@ char *malloc(int size);
|
||||
|
||||
void test1(int size) {
|
||||
char* p = malloc(size);
|
||||
char* q = p + size;
|
||||
char a = *q; // BAD
|
||||
char* q = p + size; // $ alloc=L4
|
||||
char a = *q; // $ deref=L6 // BAD
|
||||
char b = *(q - 1); // GOOD
|
||||
char c = *(q + 1); // BAD
|
||||
char c = *(q + 1); // $ deref=L8+1 // BAD
|
||||
char d = *(q + size); // BAD [NOT DETECTED]
|
||||
char e = *(q - size); // GOOD
|
||||
char f = *(q + size + 1); // BAD [NOT DETECTED]
|
||||
@@ -14,10 +14,10 @@ void test1(int size) {
|
||||
|
||||
void test2(int size) {
|
||||
char* p = malloc(size);
|
||||
char* q = p + size - 1;
|
||||
char* q = p + size - 1; // $ alloc=L16
|
||||
char a = *q; // GOOD
|
||||
char b = *(q - 1); // GOOD
|
||||
char c = *(q + 1); // BAD
|
||||
char c = *(q + 1); // $ deref=L20 // BAD
|
||||
char d = *(q + size); // BAD [NOT DETECTED]
|
||||
char e = *(q - size); // GOOD
|
||||
char f = *(q + size + 1); // BAD [NOT DETECTED]
|
||||
@@ -26,10 +26,10 @@ void test2(int size) {
|
||||
|
||||
void test3(int size) {
|
||||
char* p = malloc(size + 1);
|
||||
char* q = p + (size + 1);
|
||||
char a = *q; // BAD
|
||||
char* q = p + (size + 1); // $ alloc=L28+1
|
||||
char a = *q; // $ deref=L30 // BAD
|
||||
char b = *(q - 1); // GOOD
|
||||
char c = *(q + 1); // BAD
|
||||
char c = *(q + 1); // $ deref=L32+1 // BAD
|
||||
char d = *(q + size); // BAD [NOT DETECTED]
|
||||
char e = *(q - size); // GOOD
|
||||
char f = *(q + size + 1); // BAD [NOT DETECTED]
|
||||
@@ -38,10 +38,10 @@ void test3(int size) {
|
||||
|
||||
void test4(int size) {
|
||||
char* p = malloc(size - 1);
|
||||
char* q = p + (size - 1);
|
||||
char a = *q; // BAD
|
||||
char* q = p + (size - 1); // $ alloc=L40-1
|
||||
char a = *q; // $ deref=L42 // BAD
|
||||
char b = *(q - 1); // GOOD
|
||||
char c = *(q + 1); // BAD
|
||||
char c = *(q + 1); // $ deref=L44+1 // BAD
|
||||
char d = *(q + size); // BAD [NOT DETECTED]
|
||||
char e = *(q - size); // GOOD
|
||||
char f = *(q + size + 1); // BAD [NOT DETECTED]
|
||||
@@ -50,7 +50,7 @@ void test4(int size) {
|
||||
|
||||
char* mk_array(int size, char** end) {
|
||||
char* begin = malloc(size);
|
||||
*end = begin + size;
|
||||
*end = begin + size; // $ alloc=L52
|
||||
|
||||
return begin;
|
||||
}
|
||||
@@ -64,7 +64,7 @@ void test5(int size) {
|
||||
}
|
||||
|
||||
for (char* p = begin; p <= end; ++p) {
|
||||
*p = 0; // BAD
|
||||
*p = 0; // $ deref=L53->L62->L67 deref=L53->L66->L67 // BAD
|
||||
}
|
||||
|
||||
for (char* p = begin; p < end; ++p) {
|
||||
@@ -80,7 +80,7 @@ struct array_t {
|
||||
array_t mk_array(int size) {
|
||||
array_t arr;
|
||||
arr.begin = malloc(size);
|
||||
arr.end = arr.begin + size;
|
||||
arr.end = arr.begin + size; // $ alloc=L82
|
||||
|
||||
return arr;
|
||||
}
|
||||
@@ -93,7 +93,7 @@ void test6(int size) {
|
||||
}
|
||||
|
||||
for (char* p = arr.begin; p <= arr.end; ++p) {
|
||||
*p = 0; // BAD
|
||||
*p = 0; // $ deref=L83->L91->L96 deref=L83->L95->L96 // BAD
|
||||
}
|
||||
|
||||
for (char* p = arr.begin; p < arr.end; ++p) {
|
||||
@@ -107,7 +107,7 @@ void test7_callee(array_t arr) {
|
||||
}
|
||||
|
||||
for (char* p = arr.begin; p <= arr.end; ++p) {
|
||||
*p = 0; // BAD
|
||||
*p = 0; // $ deref=L83->L105->L110 deref=L83->L109->L110 // BAD
|
||||
}
|
||||
|
||||
for (char* p = arr.begin; p < arr.end; ++p) {
|
||||
@@ -123,7 +123,7 @@ void test8(int size) {
|
||||
array_t arr;
|
||||
char* p = malloc(size);
|
||||
arr.begin = p;
|
||||
arr.end = p + size;
|
||||
arr.end = p + size; // $ alloc=L124
|
||||
|
||||
for (int i = 0; i < arr.end - arr.begin; i++) {
|
||||
*(arr.begin + i) = 0; // GOOD
|
||||
@@ -141,7 +141,7 @@ void test8(int size) {
|
||||
array_t *mk_array_p(int size) {
|
||||
array_t *arr = (array_t*) malloc(sizeof(array_t));
|
||||
arr->begin = malloc(size);
|
||||
arr->end = arr->begin + size;
|
||||
arr->end = arr->begin + size; // $ alloc=L143
|
||||
|
||||
return arr;
|
||||
}
|
||||
@@ -154,7 +154,7 @@ void test9(int size) {
|
||||
}
|
||||
|
||||
for (char* p = arr->begin; p <= arr->end; ++p) {
|
||||
*p = 0; // BAD
|
||||
*p = 0; // $ deref=L144->L156->L157 // BAD
|
||||
}
|
||||
|
||||
for (char* p = arr->begin; p < arr->end; ++p) {
|
||||
@@ -168,7 +168,7 @@ void test10_callee(array_t *arr) {
|
||||
}
|
||||
|
||||
for (char* p = arr->begin; p <= arr->end; ++p) {
|
||||
*p = 0; // BAD
|
||||
*p = 0; // $ deref=L144->L166->L171 deref=L144->L170->L171 // BAD
|
||||
}
|
||||
|
||||
for (char* p = arr->begin; p < arr->end; ++p) {
|
||||
@@ -186,31 +186,31 @@ void deref_plus_one(char* q) {
|
||||
|
||||
void test11(unsigned size) {
|
||||
char *p = malloc(size);
|
||||
char *q = p + size - 1;
|
||||
char *q = p + size - 1; // $ alloc=L188
|
||||
deref_plus_one(q);
|
||||
}
|
||||
|
||||
void test12(unsigned len, unsigned index) {
|
||||
char* p = (char *)malloc(len);
|
||||
char* end = p + len;
|
||||
char* end = p + len; // $ alloc=L194
|
||||
|
||||
if(p + index > end) {
|
||||
return;
|
||||
}
|
||||
|
||||
p[index] = '\0'; // BAD
|
||||
p[index] = '\0'; // $ deref=L201 // BAD
|
||||
}
|
||||
|
||||
void test13(unsigned len, unsigned index) {
|
||||
char* p = (char *)malloc(len);
|
||||
char* end = p + len;
|
||||
char* end = p + len; // $ alloc=L205
|
||||
|
||||
char* q = p + index;
|
||||
if(q > end) {
|
||||
return;
|
||||
}
|
||||
|
||||
*q = '\0'; // BAD
|
||||
*q = '\0'; // $ deref=L213 // BAD
|
||||
}
|
||||
|
||||
bool unknown();
|
||||
@@ -229,14 +229,14 @@ void test15(unsigned index) {
|
||||
return;
|
||||
}
|
||||
int* newname = new int[size];
|
||||
newname[index] = 0; // GOOD [FALSE POSITIVE]
|
||||
newname[index] = 0; // $ alloc=L231 deref=L232 // GOOD [FALSE POSITIVE]
|
||||
}
|
||||
|
||||
void test16(unsigned index) {
|
||||
unsigned size = index + 13;
|
||||
if(size >= index) {
|
||||
int* newname = new int[size];
|
||||
newname[index] = 0; // GOOD [FALSE POSITIVE]
|
||||
newname[index] = 0; // $ alloc=L238 deref=L239 // GOOD [FALSE POSITIVE]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -251,34 +251,34 @@ void test17(unsigned *p, unsigned x, unsigned k) {
|
||||
// The following access is okay because:
|
||||
// n = 3*p[0] + k >= p[0] + k >= p[1] + k > p[1] = i
|
||||
// (where p[0] denotes the original value for p[0])
|
||||
p[i] = x; // GOOD [FALSE POSITIVE]
|
||||
p[i] = x; // $ alloc=L248 deref=L254 // GOOD [FALSE POSITIVE]
|
||||
}
|
||||
}
|
||||
|
||||
void test17(unsigned len)
|
||||
{
|
||||
int *xs = new int[len];
|
||||
int *end = xs + len;
|
||||
int *end = xs + len; // $ alloc=L260
|
||||
for (int *x = xs; x <= end; x++)
|
||||
{
|
||||
int i = *x; // BAD
|
||||
int i = *x; // $ deref=L264 // BAD
|
||||
}
|
||||
}
|
||||
|
||||
void test18(unsigned len)
|
||||
{
|
||||
int *xs = new int[len];
|
||||
int *end = xs + len;
|
||||
int *end = xs + len; // $ alloc=L270
|
||||
for (int *x = xs; x <= end; x++)
|
||||
{
|
||||
*x = 0; // BAD
|
||||
*x = 0; // $ deref=L274 // BAD
|
||||
}
|
||||
}
|
||||
|
||||
void test19(unsigned len)
|
||||
{
|
||||
int *xs = new int[len];
|
||||
int *end = xs + len;
|
||||
int *end = xs + len; // $ alloc=L280
|
||||
for (int *x = xs; x < end; x++)
|
||||
{
|
||||
int i = *x; // GOOD
|
||||
@@ -288,7 +288,7 @@ void test19(unsigned len)
|
||||
void test20(unsigned len)
|
||||
{
|
||||
int *xs = new int[len];
|
||||
int *end = xs + len;
|
||||
int *end = xs + len; // $ alloc=L290
|
||||
for (int *x = xs; x < end; x++)
|
||||
{
|
||||
*x = 0; // GOOD
|
||||
@@ -305,13 +305,13 @@ void test21() {
|
||||
|
||||
for (int i = 0; i < n; i += 2) {
|
||||
xs[i] = test21_get(i); // GOOD
|
||||
xs[i+1] = test21_get(i+1); // GOOD [FALSE POSITIVE]
|
||||
xs[i+1] = test21_get(i+1); // $ alloc=L304 alloc=L304-1 deref=L308 // GOOD [FALSE POSITIVE]
|
||||
}
|
||||
}
|
||||
|
||||
void test22(unsigned size, int val) {
|
||||
char *xs = new char[size];
|
||||
char *end = xs + size; // GOOD
|
||||
char *end = xs + size; // $ alloc=L313 // GOOD
|
||||
char **current = &end;
|
||||
do {
|
||||
if (*current - xs < 1) // GOOD
|
||||
@@ -323,7 +323,7 @@ void test22(unsigned size, int val) {
|
||||
|
||||
void test23(unsigned size, int val) {
|
||||
char *xs = new char[size];
|
||||
char *end = xs + size;
|
||||
char *end = xs + size; // $ alloc=L325
|
||||
char **current = &end;
|
||||
|
||||
if (val < 1) {
|
||||
@@ -345,7 +345,7 @@ void test23(unsigned size, int val) {
|
||||
|
||||
void test24(unsigned size) {
|
||||
char *xs = new char[size];
|
||||
char *end = xs + size;
|
||||
char *end = xs + size; // $ alloc=L347
|
||||
if (xs < end) {
|
||||
int val = *xs++; // GOOD
|
||||
}
|
||||
@@ -353,46 +353,139 @@ void test24(unsigned size) {
|
||||
|
||||
void test25(unsigned size) {
|
||||
char *xs = new char[size];
|
||||
char *end = xs + size;
|
||||
char *end = xs + size; // $ alloc=L355
|
||||
char *end_plus_one = end + 1;
|
||||
int val1 = *end_plus_one; // BAD
|
||||
int val2 = *(end_plus_one + 1); // BAD
|
||||
int val1 = *end_plus_one; // $ deref=L358+1 // BAD
|
||||
int val2 = *(end_plus_one + 1); // $ deref=L359+2 // BAD
|
||||
}
|
||||
|
||||
void test26(unsigned size) {
|
||||
char *xs = new char[size];
|
||||
char *p = xs;
|
||||
char *end = p + size;
|
||||
char *end = p + size; // $ alloc=L363
|
||||
|
||||
if (p + 4 <= end) {
|
||||
p += 4;
|
||||
}
|
||||
|
||||
if (p < end) {
|
||||
int val = *p; // GOOD [FALSE POSITIVE]
|
||||
int val = *p; // GOOD
|
||||
}
|
||||
}
|
||||
|
||||
void test27(unsigned size, bool b) {
|
||||
char *xs = new char[size];
|
||||
char *end = xs + size;
|
||||
char *end = xs + size; // $ alloc=L377
|
||||
|
||||
if (b) {
|
||||
end++;
|
||||
}
|
||||
|
||||
int val = *end; // BAD
|
||||
int val = *end; // $ deref=L384+1 // BAD
|
||||
}
|
||||
|
||||
void test28(unsigned size) {
|
||||
char *xs = new char[size];
|
||||
char *end = &xs[size];
|
||||
if (xs >= end)
|
||||
return;
|
||||
char *end = &xs[size]; // $ alloc=L388
|
||||
if (xs >= end)
|
||||
return;
|
||||
xs++;
|
||||
if (xs >= end)
|
||||
return;
|
||||
xs[0] = 0; // GOOD
|
||||
}
|
||||
|
||||
void test28_simple(unsigned size) {
|
||||
char *xs = new char[size];
|
||||
char *end = &xs[size]; // $ alloc=L399
|
||||
if (xs < end) {
|
||||
xs++;
|
||||
if (xs >= end)
|
||||
return;
|
||||
xs[0] = 0; // GOOD [FALSE POSITIVE]
|
||||
if (xs < end) {
|
||||
xs[0] = 0; // GOOD
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void test28_simple2(unsigned size) {
|
||||
char *xs = new char[size];
|
||||
char *end = &xs[size]; // $ alloc=L410
|
||||
if (xs < end) {
|
||||
xs++;
|
||||
if (xs < end + 1) {
|
||||
xs[0] = 0; // $ deref=L415 // BAD
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void test28_simple3(unsigned size) {
|
||||
char *xs = new char[size];
|
||||
char *end = &xs[size]; // $ alloc=L421
|
||||
if (xs < end) {
|
||||
xs++;
|
||||
if (xs - 1 < end) {
|
||||
xs[0] = 0; // $ deref=L426 // BAD
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void test28_simple4(unsigned size) {
|
||||
char *xs = new char[size];
|
||||
char *end = &xs[size]; // $ alloc=L432
|
||||
if (xs < end) {
|
||||
end++;
|
||||
xs++;
|
||||
if (xs < end) {
|
||||
xs[0] = 0; // $ deref=L438 // BAD
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void test28_simple5(unsigned size) {
|
||||
char *xs = new char[size];
|
||||
char *end = &xs[size]; // $ alloc=L444
|
||||
end++;
|
||||
if (xs < end) {
|
||||
xs++;
|
||||
if (xs < end) {
|
||||
xs[0] = 0; // $ deref=L450 // BAD
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void test28_simple6(unsigned size) {
|
||||
char *xs = new char[size + 1];
|
||||
char *end = &xs[size];
|
||||
end++;
|
||||
if (xs < end) {
|
||||
xs++;
|
||||
if (xs < end) {
|
||||
xs[0] = 0; // GOOD
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void test28_simple7(unsigned size) {
|
||||
char *xs = new char[size];
|
||||
char *end = &xs[size]; // $ alloc=L468
|
||||
end++;
|
||||
if (xs < end) {
|
||||
xs++;
|
||||
if (xs < end - 1) {
|
||||
xs[0] = 0; // GOOD
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void test28_simple8(unsigned size) {
|
||||
char *xs = new char[size];
|
||||
char *end = &xs[size]; // $ alloc=L480
|
||||
end += 500;
|
||||
if (xs < end) {
|
||||
xs++;
|
||||
if (xs < end - 1) {
|
||||
xs[0] = 0; // $ deref=L486+498 // BAD
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct test29_struct {
|
||||
@@ -404,7 +497,7 @@ void test29(unsigned size) {
|
||||
val.xs = new char[size];
|
||||
size++;
|
||||
val.xs = new char[size];
|
||||
val.xs[size - 1] = 0; // GOOD [FALSE POSITIVE]
|
||||
val.xs[size - 1] = 0; // GOOD
|
||||
}
|
||||
|
||||
void test30(int *size)
|
||||
@@ -416,7 +509,7 @@ void test30(int *size)
|
||||
new_size = tmp_size + 1;
|
||||
char *xs = new char[new_size];
|
||||
for (int i = 0; i < new_size; i++) {
|
||||
xs[i] = 0; // GOOD [FALSE POSITIVE]
|
||||
xs[i] = 0; // GOOD
|
||||
}
|
||||
}
|
||||
*size = new_size;
|
||||
@@ -429,7 +522,171 @@ void test31(unsigned size, unsigned src_pos)
|
||||
src_pos = size;
|
||||
}
|
||||
unsigned dst_pos = src_pos;
|
||||
if(dst_pos < size - 3) {
|
||||
xs[dst_pos++] = 0; // GOOD [FALSE POSITIVE]
|
||||
if (dst_pos < size - 3) {
|
||||
xs[dst_pos++] = 0; // GOOD
|
||||
}
|
||||
}
|
||||
|
||||
void test31_simple1(unsigned size, unsigned src_pos)
|
||||
{
|
||||
char *xs = new char[size];
|
||||
if (src_pos > size) {
|
||||
src_pos = size;
|
||||
}
|
||||
if (src_pos < size) {
|
||||
xs[src_pos] = 0; // GOOD
|
||||
}
|
||||
}
|
||||
|
||||
void test31_simple2(unsigned size, unsigned src_pos)
|
||||
{
|
||||
char *xs = new char[size];
|
||||
if (src_pos > size) {
|
||||
src_pos = size;
|
||||
}
|
||||
if (src_pos < size + 1) {
|
||||
xs[src_pos] = 0; // $ alloc=L543 deref=L548 // BAD
|
||||
}
|
||||
}
|
||||
|
||||
void test31_simple3(unsigned size, unsigned src_pos)
|
||||
{
|
||||
char *xs = new char[size];
|
||||
if (src_pos > size) {
|
||||
src_pos = size;
|
||||
}
|
||||
if (src_pos - 1 < size) {
|
||||
xs[src_pos] = 0; // $ alloc=L554 deref=L559 // BAD
|
||||
}
|
||||
}
|
||||
|
||||
void test31_simple4(unsigned size, unsigned src_pos)
|
||||
{
|
||||
char *xs = new char[size];
|
||||
if (src_pos > size) {
|
||||
src_pos = size;
|
||||
}
|
||||
if (src_pos < size - 1) {
|
||||
xs[src_pos] = 0; // GOOD
|
||||
}
|
||||
}
|
||||
|
||||
void test31_simple5(unsigned size, unsigned src_pos)
|
||||
{
|
||||
char *xs = new char[size];
|
||||
if (src_pos > size) {
|
||||
src_pos = size;
|
||||
}
|
||||
if (src_pos + 1 < size) {
|
||||
xs[src_pos] = 0; // GOOD
|
||||
}
|
||||
}
|
||||
|
||||
void test31_simple1_plus1(unsigned size, unsigned src_pos)
|
||||
{
|
||||
char *xs = new char[size + 1];
|
||||
if (src_pos > size) {
|
||||
src_pos = size;
|
||||
}
|
||||
if (src_pos < size) {
|
||||
xs[src_pos] = 0; // GOOD
|
||||
}
|
||||
}
|
||||
|
||||
void test31_simple2_plus1(unsigned size, unsigned src_pos)
|
||||
{
|
||||
char *xs = new char[size + 1];
|
||||
if (src_pos > size) {
|
||||
src_pos = size;
|
||||
}
|
||||
if (src_pos < size + 1) {
|
||||
xs[src_pos] = 0; // GOOD
|
||||
}
|
||||
}
|
||||
|
||||
void test31_simple3_plus1(unsigned size, unsigned src_pos)
|
||||
{
|
||||
char *xs = new char[size + 1];
|
||||
if (src_pos > size) {
|
||||
src_pos = size;
|
||||
}
|
||||
if (src_pos - 1 < size) {
|
||||
xs[src_pos] = 0; // GOOD
|
||||
}
|
||||
}
|
||||
|
||||
void test31_simple4_plus1(unsigned size, unsigned src_pos)
|
||||
{
|
||||
char *xs = new char[size + 1];
|
||||
if (src_pos > size) {
|
||||
src_pos = size;
|
||||
}
|
||||
if (src_pos < size - 1) {
|
||||
xs[src_pos] = 0; // GOOD
|
||||
}
|
||||
}
|
||||
|
||||
void test31_simple5_plus1(unsigned size, unsigned src_pos)
|
||||
{
|
||||
char *xs = new char[size + 1];
|
||||
if (src_pos > size) {
|
||||
src_pos = size;
|
||||
}
|
||||
if (src_pos + 1 < size) {
|
||||
xs[src_pos] = 0; // GOOD
|
||||
}
|
||||
}
|
||||
|
||||
void test31_simple1_sub1(unsigned size, unsigned src_pos)
|
||||
{
|
||||
char *xs = new char[size - 1];
|
||||
if (src_pos > size) {
|
||||
src_pos = size;
|
||||
}
|
||||
if (src_pos < size) {
|
||||
xs[src_pos] = 0; // $ alloc=L642-1 deref=L647 // BAD
|
||||
}
|
||||
}
|
||||
|
||||
void test32(unsigned size) {
|
||||
char *xs = new char[size];
|
||||
char *end = &xs[size]; // $ alloc=L652
|
||||
if (xs >= end)
|
||||
return;
|
||||
xs++;
|
||||
if (xs >= end)
|
||||
return;
|
||||
xs++;
|
||||
if (xs >= end)
|
||||
return;
|
||||
xs[0] = 0; // $ deref=L656->L662+1 deref=L657->L662+1 GOOD [FALSE POSITIVE]
|
||||
}
|
||||
|
||||
void test33(unsigned size, unsigned src_pos)
|
||||
{
|
||||
char *xs = new char[size + 1];
|
||||
if (src_pos > size) {
|
||||
src_pos = size;
|
||||
}
|
||||
unsigned dst_pos = src_pos;
|
||||
while (dst_pos < size - 1) {
|
||||
dst_pos++;
|
||||
if (true)
|
||||
xs[dst_pos++] = 0; // $ alloc=L667+1 deref=L675 // GOOD [FALSE POSITIVE]
|
||||
}
|
||||
}
|
||||
|
||||
int* pointer_arithmetic(int *p, int offset) {
|
||||
return p + offset; // $ alloc=L684
|
||||
}
|
||||
|
||||
void test_missing_call_context_1(unsigned size) {
|
||||
int* p = new int[size];
|
||||
int* end = pointer_arithmetic(p, size);
|
||||
}
|
||||
|
||||
void test_missing_call_context_2(unsigned size) {
|
||||
int* p = new int[size];
|
||||
int* end_minus_one = pointer_arithmetic(p, size - 1);
|
||||
*end_minus_one = '0'; // $ deref=L680->L690->L691 // GOOD
|
||||
}
|
||||
@@ -151,3 +151,19 @@ void test5(int x) {
|
||||
void test6(int x, int y) {
|
||||
return x && y;
|
||||
}
|
||||
|
||||
int ptr_test(int *x, int *y) {
|
||||
if (x == y + 42) {
|
||||
}
|
||||
|
||||
if (x == y - 42) {
|
||||
}
|
||||
|
||||
if (x < y + 42) {
|
||||
}
|
||||
|
||||
if (x < y - 42) {
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -30,6 +30,10 @@ astGuards
|
||||
| test.c:152:10:152:10 | x |
|
||||
| test.c:152:10:152:15 | ... && ... |
|
||||
| test.c:152:15:152:15 | y |
|
||||
| test.c:156:9:156:19 | ... == ... |
|
||||
| test.c:159:9:159:19 | ... == ... |
|
||||
| test.c:162:9:162:18 | ... < ... |
|
||||
| test.c:165:9:165:18 | ... < ... |
|
||||
| test.cpp:18:8:18:10 | call to get |
|
||||
| test.cpp:31:7:31:13 | ... == ... |
|
||||
| test.cpp:42:13:42:20 | call to getABool |
|
||||
@@ -122,6 +126,38 @@ astGuardsCompare
|
||||
| 109 | y < 0+0 when ... < ... is true |
|
||||
| 109 | y >= 0+0 when ... < ... is false |
|
||||
| 109 | y >= 0+0 when ... \|\| ... is false |
|
||||
| 156 | ... + ... != x+0 when ... == ... is false |
|
||||
| 156 | ... + ... == x+0 when ... == ... is true |
|
||||
| 156 | x != ... + ...+0 when ... == ... is false |
|
||||
| 156 | x != y+42 when ... == ... is false |
|
||||
| 156 | x == ... + ...+0 when ... == ... is true |
|
||||
| 156 | x == y+42 when ... == ... is true |
|
||||
| 156 | y != x+-42 when ... == ... is false |
|
||||
| 156 | y == x+-42 when ... == ... is true |
|
||||
| 159 | ... - ... != x+0 when ... == ... is false |
|
||||
| 159 | ... - ... == x+0 when ... == ... is true |
|
||||
| 159 | x != ... - ...+0 when ... == ... is false |
|
||||
| 159 | x != y+-42 when ... == ... is false |
|
||||
| 159 | x == ... - ...+0 when ... == ... is true |
|
||||
| 159 | x == y+-42 when ... == ... is true |
|
||||
| 159 | y != x+42 when ... == ... is false |
|
||||
| 159 | y == x+42 when ... == ... is true |
|
||||
| 162 | ... + ... < x+1 when ... < ... is false |
|
||||
| 162 | ... + ... >= x+1 when ... < ... is true |
|
||||
| 162 | x < ... + ...+0 when ... < ... is true |
|
||||
| 162 | x < y+42 when ... < ... is true |
|
||||
| 162 | x >= ... + ...+0 when ... < ... is false |
|
||||
| 162 | x >= y+42 when ... < ... is false |
|
||||
| 162 | y < x+-41 when ... < ... is false |
|
||||
| 162 | y >= x+-41 when ... < ... is true |
|
||||
| 165 | ... - ... < x+1 when ... < ... is false |
|
||||
| 165 | ... - ... >= x+1 when ... < ... is true |
|
||||
| 165 | x < ... - ...+0 when ... < ... is true |
|
||||
| 165 | x < y+-42 when ... < ... is true |
|
||||
| 165 | x >= ... - ...+0 when ... < ... is false |
|
||||
| 165 | x >= y+-42 when ... < ... is false |
|
||||
| 165 | y < x+43 when ... < ... is false |
|
||||
| 165 | y >= x+43 when ... < ... is true |
|
||||
astGuardsControl
|
||||
| test.c:7:9:7:13 | ... > ... | false | 10 | 11 |
|
||||
| test.c:7:9:7:13 | ... > ... | true | 7 | 9 |
|
||||
@@ -208,6 +244,10 @@ astGuardsControl
|
||||
| test.c:152:10:152:10 | x | true | 152 | 152 |
|
||||
| test.c:152:10:152:15 | ... && ... | true | 151 | 152 |
|
||||
| test.c:152:15:152:15 | y | true | 151 | 152 |
|
||||
| test.c:156:9:156:19 | ... == ... | true | 156 | 157 |
|
||||
| test.c:159:9:159:19 | ... == ... | true | 159 | 160 |
|
||||
| test.c:162:9:162:18 | ... < ... | true | 162 | 163 |
|
||||
| test.c:165:9:165:18 | ... < ... | true | 165 | 166 |
|
||||
| test.cpp:18:8:18:10 | call to get | true | 19 | 19 |
|
||||
| test.cpp:31:7:31:13 | ... == ... | false | 30 | 30 |
|
||||
| test.cpp:31:7:31:13 | ... == ... | false | 34 | 34 |
|
||||
@@ -364,6 +404,22 @@ astGuardsEnsure
|
||||
| test.c:109:9:109:23 | ... \|\| ... | test.c:109:23:109:23 | 0 | < | test.c:109:19:109:19 | y | 1 | 113 | 113 |
|
||||
| test.c:109:19:109:23 | ... < ... | test.c:109:19:109:19 | y | >= | test.c:109:23:109:23 | 0 | 0 | 113 | 113 |
|
||||
| test.c:109:19:109:23 | ... < ... | test.c:109:23:109:23 | 0 | < | test.c:109:19:109:19 | y | 1 | 113 | 113 |
|
||||
| test.c:156:9:156:19 | ... == ... | test.c:156:9:156:9 | x | == | test.c:156:14:156:14 | y | 42 | 156 | 157 |
|
||||
| test.c:156:9:156:19 | ... == ... | test.c:156:9:156:9 | x | == | test.c:156:14:156:19 | ... + ... | 0 | 156 | 157 |
|
||||
| test.c:156:9:156:19 | ... == ... | test.c:156:14:156:14 | y | == | test.c:156:9:156:9 | x | -42 | 156 | 157 |
|
||||
| test.c:156:9:156:19 | ... == ... | test.c:156:14:156:19 | ... + ... | == | test.c:156:9:156:9 | x | 0 | 156 | 157 |
|
||||
| test.c:159:9:159:19 | ... == ... | test.c:159:9:159:9 | x | == | test.c:159:14:159:14 | y | -42 | 159 | 160 |
|
||||
| test.c:159:9:159:19 | ... == ... | test.c:159:9:159:9 | x | == | test.c:159:14:159:19 | ... - ... | 0 | 159 | 160 |
|
||||
| test.c:159:9:159:19 | ... == ... | test.c:159:14:159:14 | y | == | test.c:159:9:159:9 | x | 42 | 159 | 160 |
|
||||
| test.c:159:9:159:19 | ... == ... | test.c:159:14:159:19 | ... - ... | == | test.c:159:9:159:9 | x | 0 | 159 | 160 |
|
||||
| test.c:162:9:162:18 | ... < ... | test.c:162:9:162:9 | x | < | test.c:162:13:162:13 | y | 42 | 162 | 163 |
|
||||
| test.c:162:9:162:18 | ... < ... | test.c:162:9:162:9 | x | < | test.c:162:13:162:18 | ... + ... | 0 | 162 | 163 |
|
||||
| test.c:162:9:162:18 | ... < ... | test.c:162:13:162:13 | y | >= | test.c:162:9:162:9 | x | -41 | 162 | 163 |
|
||||
| test.c:162:9:162:18 | ... < ... | test.c:162:13:162:18 | ... + ... | >= | test.c:162:9:162:9 | x | 1 | 162 | 163 |
|
||||
| test.c:165:9:165:18 | ... < ... | test.c:165:9:165:9 | x | < | test.c:165:13:165:13 | y | -42 | 165 | 166 |
|
||||
| test.c:165:9:165:18 | ... < ... | test.c:165:9:165:9 | x | < | test.c:165:13:165:18 | ... - ... | 0 | 165 | 166 |
|
||||
| test.c:165:9:165:18 | ... < ... | test.c:165:13:165:13 | y | >= | test.c:165:9:165:9 | x | 43 | 165 | 166 |
|
||||
| test.c:165:9:165:18 | ... < ... | test.c:165:13:165:18 | ... - ... | >= | test.c:165:9:165:9 | x | 1 | 165 | 166 |
|
||||
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | != | test.cpp:31:12:31:13 | - ... | 0 | 30 | 30 |
|
||||
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | != | test.cpp:31:12:31:13 | - ... | 0 | 34 | 34 |
|
||||
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | == | test.cpp:31:12:31:13 | - ... | 0 | 30 | 30 |
|
||||
@@ -397,6 +453,10 @@ irGuards
|
||||
| test.c:146:8:146:8 | Load: x |
|
||||
| test.c:152:10:152:10 | Load: x |
|
||||
| test.c:152:15:152:15 | Load: y |
|
||||
| test.c:156:9:156:19 | CompareEQ: ... == ... |
|
||||
| test.c:159:9:159:19 | CompareEQ: ... == ... |
|
||||
| test.c:162:9:162:18 | CompareLT: ... < ... |
|
||||
| test.c:165:9:165:18 | CompareLT: ... < ... |
|
||||
| test.cpp:18:8:18:12 | CompareNE: (bool)... |
|
||||
| test.cpp:31:7:31:13 | CompareEQ: ... == ... |
|
||||
| test.cpp:42:13:42:20 | Call: call to getABool |
|
||||
@@ -473,6 +533,38 @@ irGuardsCompare
|
||||
| 109 | x == 0+0 when CompareEQ: ... == ... is true |
|
||||
| 109 | y < 0+0 when CompareLT: ... < ... is true |
|
||||
| 109 | y >= 0+0 when CompareLT: ... < ... is false |
|
||||
| 156 | ... + ... != x+0 when CompareEQ: ... == ... is false |
|
||||
| 156 | ... + ... == x+0 when CompareEQ: ... == ... is true |
|
||||
| 156 | x != ... + ...+0 when CompareEQ: ... == ... is false |
|
||||
| 156 | x != y+42 when CompareEQ: ... == ... is false |
|
||||
| 156 | x == ... + ...+0 when CompareEQ: ... == ... is true |
|
||||
| 156 | x == y+42 when CompareEQ: ... == ... is true |
|
||||
| 156 | y != x+-42 when CompareEQ: ... == ... is false |
|
||||
| 156 | y == x+-42 when CompareEQ: ... == ... is true |
|
||||
| 159 | ... - ... != x+0 when CompareEQ: ... == ... is false |
|
||||
| 159 | ... - ... == x+0 when CompareEQ: ... == ... is true |
|
||||
| 159 | x != ... - ...+0 when CompareEQ: ... == ... is false |
|
||||
| 159 | x != y+-42 when CompareEQ: ... == ... is false |
|
||||
| 159 | x == ... - ...+0 when CompareEQ: ... == ... is true |
|
||||
| 159 | x == y+-42 when CompareEQ: ... == ... is true |
|
||||
| 159 | y != x+42 when CompareEQ: ... == ... is false |
|
||||
| 159 | y == x+42 when CompareEQ: ... == ... is true |
|
||||
| 162 | ... + ... < x+1 when CompareLT: ... < ... is false |
|
||||
| 162 | ... + ... >= x+1 when CompareLT: ... < ... is true |
|
||||
| 162 | x < ... + ...+0 when CompareLT: ... < ... is true |
|
||||
| 162 | x < y+42 when CompareLT: ... < ... is true |
|
||||
| 162 | x >= ... + ...+0 when CompareLT: ... < ... is false |
|
||||
| 162 | x >= y+42 when CompareLT: ... < ... is false |
|
||||
| 162 | y < x+-41 when CompareLT: ... < ... is false |
|
||||
| 162 | y >= x+-41 when CompareLT: ... < ... is true |
|
||||
| 165 | ... - ... < x+1 when CompareLT: ... < ... is false |
|
||||
| 165 | ... - ... >= x+1 when CompareLT: ... < ... is true |
|
||||
| 165 | x < ... - ...+0 when CompareLT: ... < ... is true |
|
||||
| 165 | x < y+-42 when CompareLT: ... < ... is true |
|
||||
| 165 | x >= ... - ...+0 when CompareLT: ... < ... is false |
|
||||
| 165 | x >= y+-42 when CompareLT: ... < ... is false |
|
||||
| 165 | y < x+43 when CompareLT: ... < ... is false |
|
||||
| 165 | y >= x+43 when CompareLT: ... < ... is true |
|
||||
irGuardsControl
|
||||
| test.c:7:9:7:13 | CompareGT: ... > ... | false | 11 | 11 |
|
||||
| test.c:7:9:7:13 | CompareGT: ... > ... | true | 8 | 8 |
|
||||
@@ -551,6 +643,10 @@ irGuardsControl
|
||||
| test.c:146:8:146:8 | Load: x | false | 147 | 147 |
|
||||
| test.c:152:10:152:10 | Load: x | true | 152 | 152 |
|
||||
| test.c:152:15:152:15 | Load: y | true | 152 | 152 |
|
||||
| test.c:156:9:156:19 | CompareEQ: ... == ... | true | 156 | 157 |
|
||||
| test.c:159:9:159:19 | CompareEQ: ... == ... | true | 159 | 160 |
|
||||
| test.c:162:9:162:18 | CompareLT: ... < ... | true | 162 | 163 |
|
||||
| test.c:165:9:165:18 | CompareLT: ... < ... | true | 165 | 166 |
|
||||
| test.cpp:18:8:18:12 | CompareNE: (bool)... | true | 19 | 19 |
|
||||
| test.cpp:31:7:31:13 | CompareEQ: ... == ... | false | 34 | 34 |
|
||||
| test.cpp:31:7:31:13 | CompareEQ: ... == ... | true | 30 | 30 |
|
||||
@@ -690,6 +786,22 @@ irGuardsEnsure
|
||||
| test.c:109:9:109:14 | CompareEQ: ... == ... | test.c:109:14:109:14 | Constant: 0 | != | test.c:109:9:109:9 | Load: x | 0 | 113 | 113 |
|
||||
| test.c:109:19:109:23 | CompareLT: ... < ... | test.c:109:19:109:19 | Load: y | >= | test.c:109:23:109:23 | Constant: (long)... | 0 | 113 | 113 |
|
||||
| test.c:109:19:109:23 | CompareLT: ... < ... | test.c:109:23:109:23 | Constant: (long)... | < | test.c:109:19:109:19 | Load: y | 1 | 113 | 113 |
|
||||
| test.c:156:9:156:19 | CompareEQ: ... == ... | test.c:156:9:156:9 | Load: x | == | test.c:156:14:156:14 | Load: y | 42 | 156 | 157 |
|
||||
| test.c:156:9:156:19 | CompareEQ: ... == ... | test.c:156:9:156:9 | Load: x | == | test.c:156:14:156:19 | PointerAdd: ... + ... | 0 | 156 | 157 |
|
||||
| test.c:156:9:156:19 | CompareEQ: ... == ... | test.c:156:14:156:14 | Load: y | == | test.c:156:9:156:9 | Load: x | -42 | 156 | 157 |
|
||||
| test.c:156:9:156:19 | CompareEQ: ... == ... | test.c:156:14:156:19 | PointerAdd: ... + ... | == | test.c:156:9:156:9 | Load: x | 0 | 156 | 157 |
|
||||
| test.c:159:9:159:19 | CompareEQ: ... == ... | test.c:159:9:159:9 | Load: x | == | test.c:159:14:159:14 | Load: y | -42 | 159 | 160 |
|
||||
| test.c:159:9:159:19 | CompareEQ: ... == ... | test.c:159:9:159:9 | Load: x | == | test.c:159:14:159:19 | PointerSub: ... - ... | 0 | 159 | 160 |
|
||||
| test.c:159:9:159:19 | CompareEQ: ... == ... | test.c:159:14:159:14 | Load: y | == | test.c:159:9:159:9 | Load: x | 42 | 159 | 160 |
|
||||
| test.c:159:9:159:19 | CompareEQ: ... == ... | test.c:159:14:159:19 | PointerSub: ... - ... | == | test.c:159:9:159:9 | Load: x | 0 | 159 | 160 |
|
||||
| test.c:162:9:162:18 | CompareLT: ... < ... | test.c:162:9:162:9 | Load: x | < | test.c:162:13:162:13 | Load: y | 42 | 162 | 163 |
|
||||
| test.c:162:9:162:18 | CompareLT: ... < ... | test.c:162:9:162:9 | Load: x | < | test.c:162:13:162:18 | PointerAdd: ... + ... | 0 | 162 | 163 |
|
||||
| test.c:162:9:162:18 | CompareLT: ... < ... | test.c:162:13:162:13 | Load: y | >= | test.c:162:9:162:9 | Load: x | -41 | 162 | 163 |
|
||||
| test.c:162:9:162:18 | CompareLT: ... < ... | test.c:162:13:162:18 | PointerAdd: ... + ... | >= | test.c:162:9:162:9 | Load: x | 1 | 162 | 163 |
|
||||
| test.c:165:9:165:18 | CompareLT: ... < ... | test.c:165:9:165:9 | Load: x | < | test.c:165:13:165:13 | Load: y | -42 | 165 | 166 |
|
||||
| test.c:165:9:165:18 | CompareLT: ... < ... | test.c:165:9:165:9 | Load: x | < | test.c:165:13:165:18 | PointerSub: ... - ... | 0 | 165 | 166 |
|
||||
| test.c:165:9:165:18 | CompareLT: ... < ... | test.c:165:13:165:13 | Load: y | >= | test.c:165:9:165:9 | Load: x | 43 | 165 | 166 |
|
||||
| test.c:165:9:165:18 | CompareLT: ... < ... | test.c:165:13:165:18 | PointerSub: ... - ... | >= | test.c:165:9:165:9 | Load: x | 1 | 165 | 166 |
|
||||
| test.cpp:18:8:18:12 | CompareNE: (bool)... | test.cpp:18:8:18:10 | Call: call to get | != | test.cpp:18:8:18:12 | Constant: (bool)... | 0 | 19 | 19 |
|
||||
| test.cpp:18:8:18:12 | CompareNE: (bool)... | test.cpp:18:8:18:12 | Constant: (bool)... | != | test.cpp:18:8:18:10 | Call: call to get | 0 | 19 | 19 |
|
||||
| test.cpp:31:7:31:13 | CompareEQ: ... == ... | test.cpp:31:7:31:7 | Load: x | != | test.cpp:31:12:31:13 | Constant: - ... | 0 | 34 | 34 |
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (additionalEdges.ql:31,6-14)
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (additionalEdges.ql:31,31-39)
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (additionalEdges.ql:32,7-15)
|
||||
| tryExcept.c:7:7:7:7 | x | tryExcept.c:14:10:14:10 | x |
|
||||
| tryExcept.c:7:13:7:14 | 0 | tryExcept.c:10:9:10:9 | y |
|
||||
| tryExcept.c:10:9:10:9 | y | tryExcept.c:10:5:10:9 | ... = ... |
|
||||
|
||||
@@ -1,2 +1,5 @@
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (standardEdges.ql:4,6-14)
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (standardEdges.ql:4,31-39)
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (standardEdges.ql:5,7-15)
|
||||
| tryExcept.c:7:13:7:14 | 0 | tryExcept.c:10:9:10:9 | y |
|
||||
| tryExcept.c:10:9:10:9 | y | tryExcept.c:10:5:10:9 | ... = ... |
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (has-parameter-flow-out.ql:5,18-61)
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (localFlow.ql:4,6-14)
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (localFlow.ql:4,31-39)
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (localFlow.ql:6,3-11)
|
||||
| example.c:15:37:15:37 | b | example.c:15:37:15:37 | b |
|
||||
| example.c:15:37:15:37 | b | example.c:19:6:19:6 | b |
|
||||
| example.c:15:44:15:46 | pos | example.c:24:24:24:26 | pos |
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
#include "../../../include/iterator.h"
|
||||
int source();
|
||||
|
||||
template<typename T>
|
||||
void sink(T);
|
||||
|
||||
template<> struct std::iterator_traits<unsigned long>
|
||||
{ // get traits from integer type
|
||||
typedef std::input_iterator_tag iterator_category;
|
||||
typedef unsigned long value_type;
|
||||
typedef unsigned long difference_type;
|
||||
typedef unsigned long distance_type;
|
||||
typedef unsigned long * pointer;
|
||||
typedef unsigned long& reference;
|
||||
};
|
||||
|
||||
|
||||
int test() {
|
||||
unsigned long x = source();
|
||||
sink(x); // $ ast ir
|
||||
}
|
||||
@@ -1,2 +1,3 @@
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (test-number-of-outnodes.ql:5,18-61)
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -734,3 +734,58 @@ void test_does_not_write_source_to_dereference()
|
||||
does_not_write_source_to_dereference(&x);
|
||||
sink(x); // $ ast,ir=733:7 SPURIOUS: ast,ir=726:11
|
||||
}
|
||||
|
||||
void sometimes_calls_sink_eq(int x, int n) {
|
||||
if(n == 0) {
|
||||
sink(x); // $ ast,ir=751:27 ast,ir=755:32 SPURIOUS: ast=749:27 ast,ir=753:32 // IR spurious results because we only have call contexts of depth 1
|
||||
}
|
||||
}
|
||||
|
||||
void call_sometimes_calls_sink_eq(int x, int n) {
|
||||
sometimes_calls_sink_eq(x, n);
|
||||
}
|
||||
|
||||
void test_sometimes_calls_sink_eq_1() {
|
||||
sometimes_calls_sink_eq(source(), 1);
|
||||
sometimes_calls_sink_eq(0, 0);
|
||||
sometimes_calls_sink_eq(source(), 0);
|
||||
|
||||
call_sometimes_calls_sink_eq(source(), 1);
|
||||
call_sometimes_calls_sink_eq(0, 0);
|
||||
call_sometimes_calls_sink_eq(source(), 0);
|
||||
}
|
||||
|
||||
void sometimes_calls_sink_lt(int x, int n) {
|
||||
if(n < 10) {
|
||||
sink(x); // $ ast,ir=771:27 ast,ir=775:32 SPURIOUS: ast=769:27 ast,ir=773:32 // IR spurious results because we only have call contexts of depth 1
|
||||
}
|
||||
}
|
||||
|
||||
void call_sometimes_calls_sink_lt(int x, int n) {
|
||||
sometimes_calls_sink_lt(x, n);
|
||||
}
|
||||
|
||||
void test_sometimes_calls_sink_lt() {
|
||||
sometimes_calls_sink_lt(source(), 10);
|
||||
sometimes_calls_sink_lt(0, 0);
|
||||
sometimes_calls_sink_lt(source(), 2);
|
||||
|
||||
call_sometimes_calls_sink_lt(source(), 10);
|
||||
call_sometimes_calls_sink_lt(0, 0);
|
||||
call_sometimes_calls_sink_lt(source(), 2);
|
||||
|
||||
}
|
||||
|
||||
void sometimes_calls_sink_switch(int x, int n) {
|
||||
switch(n) {
|
||||
case 0:
|
||||
sink(x); // $ ast,ir=790:31 SPURIOUS: ast,ir=788:31 // IR spurious results because IRGuard doesn't understand switch statements.
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void test_sometimes_calls_sink_switch() {
|
||||
sometimes_calls_sink_switch(source(), 1);
|
||||
sometimes_calls_sink_switch(0, 0);
|
||||
sometimes_calls_sink_switch(source(), 0);
|
||||
}
|
||||
@@ -1,2 +1,9 @@
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (test.ql:19,45-53)
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (test.ql:20,24-32)
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (test.ql:27,15-23)
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (test.ql:33,22-30)
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (test.ql:40,25-33)
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (test.ql:42,17-25)
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (test.ql:46,20-28)
|
||||
failures
|
||||
testFailures
|
||||
|
||||
182
cpp/ql/test/library-tests/dataflow/fields/clearning.cpp
Normal file
182
cpp/ql/test/library-tests/dataflow/fields/clearning.cpp
Normal file
@@ -0,0 +1,182 @@
|
||||
// We want a source of user input that can be both a pointer and a non-pointer. So we
|
||||
// hack the testing a bit by providing an overload that takes a boolean to distinguish
|
||||
// between the two while still satisfying the test requirement that the function must
|
||||
// be named `user_input`.
|
||||
int user_input();
|
||||
int* user_input(bool);
|
||||
void sink(...);
|
||||
void argument_source(int*);
|
||||
|
||||
struct S {
|
||||
int** x;
|
||||
};
|
||||
|
||||
void test()
|
||||
{
|
||||
{
|
||||
S s;
|
||||
**s.x = user_input();
|
||||
*s.x = 0;
|
||||
sink(**s.x); // clean, as *s.x was overwritten and that contains the tainted **s.x
|
||||
}
|
||||
|
||||
{
|
||||
S s;
|
||||
**s.x = user_input();
|
||||
**s.x = 0;
|
||||
sink(**s.x); // clean, as **s.x was overwritten and tainted
|
||||
}
|
||||
|
||||
{
|
||||
S s;
|
||||
*s.x = user_input(true);
|
||||
**s.x = 0;
|
||||
sink(*s.x); // $ ir // not clean, as **s.x was overwritten and is neither equal nor contains the tainted *s.x
|
||||
}
|
||||
|
||||
{
|
||||
S s;
|
||||
*s.x = user_input(true);
|
||||
s.x = 0;
|
||||
sink(*s.x); // clean, as s.x was overwritten and contains the tainted *s.x
|
||||
}
|
||||
|
||||
{
|
||||
S s;
|
||||
**s.x = user_input();
|
||||
s.x = 0;
|
||||
sink(*s.x); // clean, as s.x was overwritten and contains the tainted **s.x
|
||||
}
|
||||
|
||||
{
|
||||
S s;
|
||||
*s.x = user_input(true);
|
||||
s.x++;
|
||||
sink(s.x); // $ SPURIOUS: ir ast // Cannot tell the difference with the whole array being tainted
|
||||
}
|
||||
|
||||
{
|
||||
S s;
|
||||
**s.x = user_input();
|
||||
s.x++;
|
||||
sink(s.x); // $ SPURIOUS: ir // Cannot tell the difference with the whole array being tainted
|
||||
}
|
||||
}
|
||||
|
||||
struct S2
|
||||
{
|
||||
int* val;
|
||||
};
|
||||
|
||||
void test_uncertain_write_is_not_clear()
|
||||
{
|
||||
S2 s;
|
||||
argument_source(s.val);
|
||||
s.val[10] = 0;
|
||||
sink(*s.val); // $ ir MISSING: ast // not clean, as all elements of s.val are tainted and only one is overwitten
|
||||
}
|
||||
|
||||
void test_indirection_should_not_be_cleared_with_write_1() {
|
||||
S2 s;
|
||||
argument_source(s.val); // *s.val is tainted
|
||||
s.val[0] = 0;
|
||||
s.val = s.val + 1;
|
||||
sink(*s.val); // $ ir MISSING: ast // not clean, as all elements of s.val are tainted, only one if overwritten, and the updated pointer still points to tainted elements
|
||||
}
|
||||
|
||||
void test_indirection_should_not_be_cleared_with_write_2() {
|
||||
S2 s;
|
||||
argument_source(s.val); // *s.val is tainted
|
||||
*s.val++ = 0;
|
||||
sink(*s.val); // $ ir MISSING: ast // not clean, as all elements of s.val are tainted, only one if overwritten, and the updated pointer still points to tainted elements
|
||||
}
|
||||
|
||||
void test_indirection_should_not_be_cleared_without_write_1() {
|
||||
S2 s;
|
||||
argument_source(s.val); // *s.val is tainted
|
||||
s.val = s.val + 1;
|
||||
sink(*s.val); // $ ir MISSING: ast // not clean, as all elements of s.val are tainted and the updated pointer still points to tainted elements
|
||||
}
|
||||
|
||||
void test_indirection_should_not_be_cleared_without_write_2() {
|
||||
S2 s;
|
||||
argument_source(s.val); // *s.val is tainted
|
||||
s.val++;
|
||||
sink(*s.val); // $ ir MISSING: ast // not clean, as all elements of s.val are tainted and the updated pointer still points to tainted elements
|
||||
}
|
||||
|
||||
void test_indirection_should_not_be_cleared_without_write_3() {
|
||||
S2 s;
|
||||
argument_source(s.val); // *s.val is tainted
|
||||
++s.val;
|
||||
sink(*s.val); // $ ir MISSING: ast // not clean as the pointer is only moved to the next tainted element
|
||||
}
|
||||
|
||||
void test_indirection_should_not_be_cleared_without_write_4() {
|
||||
S2 s;
|
||||
argument_source(s.val); // *s.val is tainted
|
||||
s.val += 1;
|
||||
sink(*s.val); // $ ir MISSING: ast // not clean as the pointer is only moved to the next tainted element
|
||||
}
|
||||
|
||||
void test_direct_should_be_cleared() {
|
||||
S2 s;
|
||||
s.val = user_input(true); // s.val is tainted
|
||||
s.val += 1;
|
||||
sink(s.val); // $ SPURIOUS: ast // clean, as s.val was overwritten and tainted
|
||||
}
|
||||
|
||||
void test_direct_should_be_cleared_post() {
|
||||
S2 s;
|
||||
s.val = user_input(true); // s.val is tainted
|
||||
s.val++;
|
||||
sink(s.val); // $ SPURIOUS: ast // clean, as s.val was overwritten and tainted
|
||||
}
|
||||
|
||||
void test_direct_should_be_cleared_pre() {
|
||||
S2 s;
|
||||
s.val = user_input(true); // s.val is tainted
|
||||
++s.val;
|
||||
sink(s.val); // $ SPURIOUS: ast // // clean, as s.x was overwritten and tainted
|
||||
}
|
||||
|
||||
struct S3
|
||||
{
|
||||
int val;
|
||||
};
|
||||
|
||||
void test_direct() {
|
||||
{
|
||||
S3 s;
|
||||
s.val = user_input();
|
||||
sink(s.val); // $ ir ast
|
||||
}
|
||||
|
||||
{
|
||||
S3 s;
|
||||
s.val = user_input();
|
||||
s.val = 0;
|
||||
sink(s.val); // $ SPURIOUS: ast // clean
|
||||
}
|
||||
|
||||
{
|
||||
S3 s;
|
||||
s.val = user_input();
|
||||
s.val++;
|
||||
sink(s.val); // $ SPURIOUS: ast // clean
|
||||
}
|
||||
|
||||
{
|
||||
S3 s;
|
||||
s.val = user_input();
|
||||
s.val += 1;
|
||||
sink(s.val); // $ SPURIOUS: ast // clean
|
||||
}
|
||||
|
||||
{
|
||||
S3 s;
|
||||
s.val = user_input();
|
||||
s.val = s.val + 1;
|
||||
sink(s.val); // $ SPURIOUS: ast // clean
|
||||
}
|
||||
}
|
||||
@@ -43,6 +43,9 @@ argHasPostUpdate
|
||||
| arrays.cpp:10:8:10:15 | * ... | ArgumentNode is missing PostUpdateNode. |
|
||||
| arrays.cpp:16:8:16:13 | access to array | ArgumentNode is missing PostUpdateNode. |
|
||||
| arrays.cpp:17:8:17:13 | access to array | ArgumentNode is missing PostUpdateNode. |
|
||||
| clearning.cpp:34:8:34:11 | * ... | ArgumentNode is missing PostUpdateNode. |
|
||||
| clearning.cpp:41:8:41:11 | * ... | ArgumentNode is missing PostUpdateNode. |
|
||||
| clearning.cpp:48:8:48:11 | * ... | ArgumentNode is missing PostUpdateNode. |
|
||||
postWithInFlow
|
||||
| A.cpp:25:13:25:13 | c [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| A.cpp:27:28:27:28 | c [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
@@ -123,6 +126,32 @@ postWithInFlow
|
||||
| by_reference.cpp:108:24:108:24 | a [inner post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| by_reference.cpp:123:28:123:36 | inner_ptr [inner post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| by_reference.cpp:127:30:127:38 | inner_ptr [inner post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| clearning.cpp:19:3:19:6 | * ... [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| clearning.cpp:19:6:19:6 | x [inner post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| clearning.cpp:32:3:32:6 | * ... [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| clearning.cpp:32:6:32:6 | x [inner post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| clearning.cpp:39:3:39:6 | * ... [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| clearning.cpp:39:6:39:6 | x [inner post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| clearning.cpp:40:5:40:5 | x [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| clearning.cpp:47:5:47:5 | x [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| clearning.cpp:53:3:53:6 | * ... [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| clearning.cpp:53:6:53:6 | x [inner post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| clearning.cpp:75:2:75:10 | access to array [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| clearning.cpp:75:4:75:6 | val [inner post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| clearning.cpp:82:2:82:9 | access to array [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| clearning.cpp:82:4:82:6 | val [inner post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| clearning.cpp:83:7:83:9 | val [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| clearning.cpp:97:4:97:6 | val [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| clearning.cpp:124:4:124:6 | val [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| clearning.cpp:131:4:131:6 | val [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| clearning.cpp:138:4:138:6 | val [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| clearning.cpp:151:5:151:7 | val [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| clearning.cpp:157:5:157:7 | val [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| clearning.cpp:158:5:158:7 | val [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| clearning.cpp:164:5:164:7 | val [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| clearning.cpp:171:5:171:7 | val [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| clearning.cpp:178:5:178:7 | val [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| clearning.cpp:179:5:179:7 | val [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| complex.cpp:11:22:11:23 | a_ [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| complex.cpp:12:22:12:23 | b_ [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| conflated.cpp:10:3:10:7 | * ... [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
|
||||
@@ -19,6 +19,17 @@ uniquePostUpdate
|
||||
| aliasing.cpp:77:11:77:11 | definition of w indirection | Node has multiple PostUpdateNodes. |
|
||||
| aliasing.cpp:84:11:84:11 | definition of w indirection | Node has multiple PostUpdateNodes. |
|
||||
| aliasing.cpp:91:11:91:11 | definition of w indirection | Node has multiple PostUpdateNodes. |
|
||||
| clearning.cpp:54:3:54:3 | s indirection | Node has multiple PostUpdateNodes. |
|
||||
| clearning.cpp:61:3:61:3 | s indirection | Node has multiple PostUpdateNodes. |
|
||||
| clearning.cpp:90:3:90:3 | s indirection | Node has multiple PostUpdateNodes. |
|
||||
| clearning.cpp:104:2:104:2 | s indirection | Node has multiple PostUpdateNodes. |
|
||||
| clearning.cpp:111:4:111:4 | s indirection | Node has multiple PostUpdateNodes. |
|
||||
| clearning.cpp:118:2:118:2 | s indirection | Node has multiple PostUpdateNodes. |
|
||||
| clearning.cpp:125:2:125:2 | s indirection | Node has multiple PostUpdateNodes. |
|
||||
| clearning.cpp:132:2:132:2 | s indirection | Node has multiple PostUpdateNodes. |
|
||||
| clearning.cpp:139:4:139:4 | s indirection | Node has multiple PostUpdateNodes. |
|
||||
| clearning.cpp:165:3:165:3 | s indirection | Node has multiple PostUpdateNodes. |
|
||||
| clearning.cpp:172:3:172:3 | s indirection | Node has multiple PostUpdateNodes. |
|
||||
| complex.cpp:22:3:22:5 | this indirection | Node has multiple PostUpdateNodes. |
|
||||
| complex.cpp:25:7:25:7 | this indirection | Node has multiple PostUpdateNodes. |
|
||||
| complex.cpp:42:10:42:14 | inner indirection | Node has multiple PostUpdateNodes. |
|
||||
|
||||
@@ -12,8 +12,10 @@ edges
|
||||
| A.cpp:31:14:31:21 | call to B [c] | A.cpp:29:15:29:18 | make indirection [c] |
|
||||
| A.cpp:31:20:31:20 | c | A.cpp:23:10:23:10 | c |
|
||||
| A.cpp:31:20:31:20 | c | A.cpp:31:14:31:21 | call to B [c] |
|
||||
| A.cpp:41:15:41:21 | new | A.cpp:43:10:43:12 | & ... indirection |
|
||||
| A.cpp:41:15:41:21 | new | A.cpp:43:10:43:12 | & ... indirection |
|
||||
| A.cpp:41:5:41:6 | insert output argument | A.cpp:43:10:43:12 | & ... indirection |
|
||||
| A.cpp:41:15:41:21 | new | A.cpp:41:5:41:6 | insert output argument |
|
||||
| A.cpp:41:15:41:21 | new | A.cpp:41:5:41:6 | insert output argument |
|
||||
| A.cpp:41:15:41:21 | new | A.cpp:41:15:41:21 | new |
|
||||
| A.cpp:47:12:47:18 | new | A.cpp:48:20:48:20 | c |
|
||||
| A.cpp:48:12:48:18 | call to make indirection [c] | A.cpp:49:10:49:10 | b indirection [c] |
|
||||
| A.cpp:48:20:48:20 | c | A.cpp:29:23:29:23 | c |
|
||||
@@ -572,6 +574,136 @@ edges
|
||||
| by_reference.cpp:136:8:136:13 | pouter indirection [a] | by_reference.cpp:136:16:136:16 | a |
|
||||
| by_reference.cpp:136:8:136:13 | pouter indirection [a] | by_reference.cpp:136:16:136:16 | a indirection |
|
||||
| by_reference.cpp:136:16:136:16 | a indirection | by_reference.cpp:136:16:136:16 | a |
|
||||
| clearning.cpp:32:3:32:25 | ... = ... | clearning.cpp:32:6:32:6 | s indirection [post update] [x indirection] |
|
||||
| clearning.cpp:32:6:32:6 | s indirection [post update] [x indirection] | clearning.cpp:33:5:33:5 | s indirection [x indirection] |
|
||||
| clearning.cpp:32:10:32:19 | call to user_input | clearning.cpp:32:3:32:25 | ... = ... |
|
||||
| clearning.cpp:33:5:33:5 | s indirection [x indirection] | clearning.cpp:34:9:34:9 | s indirection [x indirection] |
|
||||
| clearning.cpp:34:9:34:9 | s indirection [x indirection] | clearning.cpp:34:8:34:11 | * ... |
|
||||
| clearning.cpp:34:9:34:9 | s indirection [x indirection] | clearning.cpp:34:11:34:11 | x indirection |
|
||||
| clearning.cpp:34:9:34:9 | s indirection [x indirection] | clearning.cpp:34:11:34:11 | x indirection |
|
||||
| clearning.cpp:34:11:34:11 | x indirection | clearning.cpp:34:8:34:11 | * ... |
|
||||
| clearning.cpp:34:11:34:11 | x indirection | clearning.cpp:34:8:34:11 | * ... |
|
||||
| clearning.cpp:53:3:53:25 | ... = ... | clearning.cpp:53:6:53:6 | s indirection [post update] [x indirection] |
|
||||
| clearning.cpp:53:6:53:6 | s indirection [post update] [x indirection] | clearning.cpp:54:3:54:3 | s indirection [x indirection] |
|
||||
| clearning.cpp:53:10:53:19 | call to user_input | clearning.cpp:53:3:53:25 | ... = ... |
|
||||
| clearning.cpp:54:3:54:3 | s indirection [x indirection] | clearning.cpp:54:3:54:7 | ... ++ indirection |
|
||||
| clearning.cpp:54:3:54:3 | s indirection [x indirection] | clearning.cpp:54:5:54:5 | x indirection |
|
||||
| clearning.cpp:54:3:54:3 | s indirection [x indirection] | clearning.cpp:55:8:55:8 | s indirection [x indirection] |
|
||||
| clearning.cpp:54:3:54:7 | ... ++ indirection | clearning.cpp:54:3:54:7 | ... ++ indirection |
|
||||
| clearning.cpp:54:3:54:7 | ... ++ indirection | clearning.cpp:54:5:54:5 | s indirection [post update] [x indirection] |
|
||||
| clearning.cpp:54:5:54:5 | s indirection [post update] [x indirection] | clearning.cpp:55:8:55:8 | s indirection [x indirection] |
|
||||
| clearning.cpp:54:5:54:5 | x indirection | clearning.cpp:54:3:54:7 | ... ++ indirection |
|
||||
| clearning.cpp:55:8:55:8 | s indirection [x indirection] | clearning.cpp:55:10:55:10 | x indirection |
|
||||
| clearning.cpp:55:8:55:8 | s indirection [x indirection] | clearning.cpp:55:10:55:10 | x indirection |
|
||||
| clearning.cpp:55:10:55:10 | x indirection | clearning.cpp:55:10:55:10 | x indirection |
|
||||
| clearning.cpp:60:3:60:22 | ... = ... | clearning.cpp:60:7:60:7 | s indirection [post update] [x indirection] |
|
||||
| clearning.cpp:60:7:60:7 | s indirection [post update] [x indirection] | clearning.cpp:61:3:61:3 | s indirection [x indirection] |
|
||||
| clearning.cpp:60:11:60:20 | call to user_input | clearning.cpp:60:3:60:22 | ... = ... |
|
||||
| clearning.cpp:61:3:61:3 | s indirection [x indirection] | clearning.cpp:61:3:61:7 | ... ++ indirection |
|
||||
| clearning.cpp:61:3:61:3 | s indirection [x indirection] | clearning.cpp:61:5:61:5 | x indirection |
|
||||
| clearning.cpp:61:3:61:3 | s indirection [x indirection] | clearning.cpp:62:8:62:8 | s indirection [x indirection] |
|
||||
| clearning.cpp:61:3:61:7 | ... ++ indirection | clearning.cpp:61:3:61:7 | ... ++ indirection |
|
||||
| clearning.cpp:61:3:61:7 | ... ++ indirection | clearning.cpp:61:5:61:5 | s indirection [post update] [x indirection] |
|
||||
| clearning.cpp:61:5:61:5 | s indirection [post update] [x indirection] | clearning.cpp:62:8:62:8 | s indirection [x indirection] |
|
||||
| clearning.cpp:61:5:61:5 | x indirection | clearning.cpp:61:3:61:7 | ... ++ indirection |
|
||||
| clearning.cpp:62:8:62:8 | s indirection [x indirection] | clearning.cpp:62:10:62:10 | x indirection |
|
||||
| clearning.cpp:62:8:62:8 | s indirection [x indirection] | clearning.cpp:62:10:62:10 | x indirection |
|
||||
| clearning.cpp:62:10:62:10 | x indirection | clearning.cpp:62:10:62:10 | x indirection |
|
||||
| clearning.cpp:74:20:74:22 | argument_source output argument | clearning.cpp:74:20:74:22 | s indirection [post update] [val indirection] |
|
||||
| clearning.cpp:74:20:74:22 | s indirection [post update] [val indirection] | clearning.cpp:76:8:76:8 | s indirection [val indirection] |
|
||||
| clearning.cpp:76:8:76:8 | s indirection [val indirection] | clearning.cpp:76:7:76:12 | * ... |
|
||||
| clearning.cpp:76:8:76:8 | s indirection [val indirection] | clearning.cpp:76:10:76:12 | val indirection |
|
||||
| clearning.cpp:76:8:76:8 | s indirection [val indirection] | clearning.cpp:76:10:76:12 | val indirection |
|
||||
| clearning.cpp:76:10:76:12 | val indirection | clearning.cpp:76:7:76:12 | * ... |
|
||||
| clearning.cpp:76:10:76:12 | val indirection | clearning.cpp:76:7:76:12 | * ... |
|
||||
| clearning.cpp:81:20:81:22 | argument_source output argument | clearning.cpp:81:20:81:22 | s indirection [post update] [val indirection] |
|
||||
| clearning.cpp:81:20:81:22 | s indirection [post update] [val indirection] | clearning.cpp:83:13:83:13 | s indirection [val indirection] |
|
||||
| clearning.cpp:83:5:83:21 | ... = ... indirection | clearning.cpp:83:7:83:9 | s indirection [post update] [val indirection] |
|
||||
| clearning.cpp:83:7:83:9 | s indirection [post update] [val indirection] | clearning.cpp:84:8:84:8 | s indirection [val indirection] |
|
||||
| clearning.cpp:83:13:83:13 | s indirection [val indirection] | clearning.cpp:83:13:83:21 | ... + ... indirection |
|
||||
| clearning.cpp:83:13:83:13 | s indirection [val indirection] | clearning.cpp:83:15:83:17 | val indirection |
|
||||
| clearning.cpp:83:13:83:21 | ... + ... indirection | clearning.cpp:83:5:83:21 | ... = ... indirection |
|
||||
| clearning.cpp:83:15:83:17 | val indirection | clearning.cpp:83:5:83:21 | ... = ... indirection |
|
||||
| clearning.cpp:84:8:84:8 | s indirection [val indirection] | clearning.cpp:84:7:84:12 | * ... |
|
||||
| clearning.cpp:84:8:84:8 | s indirection [val indirection] | clearning.cpp:84:10:84:12 | val indirection |
|
||||
| clearning.cpp:84:8:84:8 | s indirection [val indirection] | clearning.cpp:84:10:84:12 | val indirection |
|
||||
| clearning.cpp:84:10:84:12 | val indirection | clearning.cpp:84:7:84:12 | * ... |
|
||||
| clearning.cpp:84:10:84:12 | val indirection | clearning.cpp:84:7:84:12 | * ... |
|
||||
| clearning.cpp:89:20:89:22 | argument_source output argument | clearning.cpp:89:20:89:22 | s indirection [post update] [val indirection] |
|
||||
| clearning.cpp:89:20:89:22 | s indirection [post update] [val indirection] | clearning.cpp:90:3:90:3 | s indirection [val indirection] |
|
||||
| clearning.cpp:90:3:90:3 | s indirection [val indirection] | clearning.cpp:90:3:90:9 | ... ++ indirection |
|
||||
| clearning.cpp:90:3:90:3 | s indirection [val indirection] | clearning.cpp:90:5:90:7 | val indirection |
|
||||
| clearning.cpp:90:3:90:3 | s indirection [val indirection] | clearning.cpp:91:8:91:8 | s indirection [val indirection] |
|
||||
| clearning.cpp:90:3:90:9 | ... ++ indirection | clearning.cpp:90:3:90:9 | ... ++ indirection |
|
||||
| clearning.cpp:90:3:90:9 | ... ++ indirection | clearning.cpp:90:5:90:7 | s indirection [post update] [val indirection] |
|
||||
| clearning.cpp:90:5:90:7 | s indirection [post update] [val indirection] | clearning.cpp:91:8:91:8 | s indirection [val indirection] |
|
||||
| clearning.cpp:90:5:90:7 | val indirection | clearning.cpp:90:3:90:9 | ... ++ indirection |
|
||||
| clearning.cpp:91:8:91:8 | s indirection [val indirection] | clearning.cpp:91:7:91:12 | * ... |
|
||||
| clearning.cpp:91:8:91:8 | s indirection [val indirection] | clearning.cpp:91:10:91:12 | val indirection |
|
||||
| clearning.cpp:91:8:91:8 | s indirection [val indirection] | clearning.cpp:91:10:91:12 | val indirection |
|
||||
| clearning.cpp:91:10:91:12 | val indirection | clearning.cpp:91:7:91:12 | * ... |
|
||||
| clearning.cpp:91:10:91:12 | val indirection | clearning.cpp:91:7:91:12 | * ... |
|
||||
| clearning.cpp:96:20:96:22 | argument_source output argument | clearning.cpp:96:20:96:22 | s indirection [post update] [val indirection] |
|
||||
| clearning.cpp:96:20:96:22 | s indirection [post update] [val indirection] | clearning.cpp:97:10:97:10 | s indirection [val indirection] |
|
||||
| clearning.cpp:97:2:97:18 | ... = ... indirection | clearning.cpp:97:4:97:6 | s indirection [post update] [val indirection] |
|
||||
| clearning.cpp:97:4:97:6 | s indirection [post update] [val indirection] | clearning.cpp:98:8:98:8 | s indirection [val indirection] |
|
||||
| clearning.cpp:97:10:97:10 | s indirection [val indirection] | clearning.cpp:97:10:97:18 | ... + ... indirection |
|
||||
| clearning.cpp:97:10:97:10 | s indirection [val indirection] | clearning.cpp:97:12:97:14 | val indirection |
|
||||
| clearning.cpp:97:10:97:18 | ... + ... indirection | clearning.cpp:97:2:97:18 | ... = ... indirection |
|
||||
| clearning.cpp:97:12:97:14 | val indirection | clearning.cpp:97:2:97:18 | ... = ... indirection |
|
||||
| clearning.cpp:98:8:98:8 | s indirection [val indirection] | clearning.cpp:98:7:98:12 | * ... |
|
||||
| clearning.cpp:98:8:98:8 | s indirection [val indirection] | clearning.cpp:98:10:98:12 | val indirection |
|
||||
| clearning.cpp:98:8:98:8 | s indirection [val indirection] | clearning.cpp:98:10:98:12 | val indirection |
|
||||
| clearning.cpp:98:10:98:12 | val indirection | clearning.cpp:98:7:98:12 | * ... |
|
||||
| clearning.cpp:98:10:98:12 | val indirection | clearning.cpp:98:7:98:12 | * ... |
|
||||
| clearning.cpp:103:20:103:22 | argument_source output argument | clearning.cpp:103:20:103:22 | s indirection [post update] [val indirection] |
|
||||
| clearning.cpp:103:20:103:22 | s indirection [post update] [val indirection] | clearning.cpp:104:2:104:2 | s indirection [val indirection] |
|
||||
| clearning.cpp:104:2:104:2 | s indirection [val indirection] | clearning.cpp:104:2:104:8 | ... ++ indirection |
|
||||
| clearning.cpp:104:2:104:2 | s indirection [val indirection] | clearning.cpp:104:4:104:6 | val indirection |
|
||||
| clearning.cpp:104:2:104:2 | s indirection [val indirection] | clearning.cpp:105:8:105:8 | s indirection [val indirection] |
|
||||
| clearning.cpp:104:2:104:8 | ... ++ indirection | clearning.cpp:104:2:104:8 | ... ++ indirection |
|
||||
| clearning.cpp:104:2:104:8 | ... ++ indirection | clearning.cpp:104:4:104:6 | s indirection [post update] [val indirection] |
|
||||
| clearning.cpp:104:4:104:6 | s indirection [post update] [val indirection] | clearning.cpp:105:8:105:8 | s indirection [val indirection] |
|
||||
| clearning.cpp:104:4:104:6 | val indirection | clearning.cpp:104:2:104:8 | ... ++ indirection |
|
||||
| clearning.cpp:105:8:105:8 | s indirection [val indirection] | clearning.cpp:105:7:105:12 | * ... |
|
||||
| clearning.cpp:105:8:105:8 | s indirection [val indirection] | clearning.cpp:105:10:105:12 | val indirection |
|
||||
| clearning.cpp:105:8:105:8 | s indirection [val indirection] | clearning.cpp:105:10:105:12 | val indirection |
|
||||
| clearning.cpp:105:10:105:12 | val indirection | clearning.cpp:105:7:105:12 | * ... |
|
||||
| clearning.cpp:105:10:105:12 | val indirection | clearning.cpp:105:7:105:12 | * ... |
|
||||
| clearning.cpp:110:20:110:22 | argument_source output argument | clearning.cpp:110:20:110:22 | s indirection [post update] [val indirection] |
|
||||
| clearning.cpp:110:20:110:22 | s indirection [post update] [val indirection] | clearning.cpp:111:4:111:4 | s indirection [val indirection] |
|
||||
| clearning.cpp:111:2:111:8 | ++ ... indirection | clearning.cpp:111:2:111:8 | ++ ... indirection |
|
||||
| clearning.cpp:111:2:111:8 | ++ ... indirection | clearning.cpp:111:6:111:8 | s indirection [post update] [val indirection] |
|
||||
| clearning.cpp:111:4:111:4 | s indirection [val indirection] | clearning.cpp:111:2:111:8 | ++ ... indirection |
|
||||
| clearning.cpp:111:4:111:4 | s indirection [val indirection] | clearning.cpp:111:6:111:8 | val indirection |
|
||||
| clearning.cpp:111:4:111:4 | s indirection [val indirection] | clearning.cpp:112:8:112:8 | s indirection [val indirection] |
|
||||
| clearning.cpp:111:6:111:8 | s indirection [post update] [val indirection] | clearning.cpp:112:8:112:8 | s indirection [val indirection] |
|
||||
| clearning.cpp:111:6:111:8 | val indirection | clearning.cpp:111:2:111:8 | ++ ... indirection |
|
||||
| clearning.cpp:112:8:112:8 | s indirection [val indirection] | clearning.cpp:112:7:112:12 | * ... |
|
||||
| clearning.cpp:112:8:112:8 | s indirection [val indirection] | clearning.cpp:112:10:112:12 | val indirection |
|
||||
| clearning.cpp:112:8:112:8 | s indirection [val indirection] | clearning.cpp:112:10:112:12 | val indirection |
|
||||
| clearning.cpp:112:10:112:12 | val indirection | clearning.cpp:112:7:112:12 | * ... |
|
||||
| clearning.cpp:112:10:112:12 | val indirection | clearning.cpp:112:7:112:12 | * ... |
|
||||
| clearning.cpp:117:20:117:22 | argument_source output argument | clearning.cpp:117:20:117:22 | s indirection [post update] [val indirection] |
|
||||
| clearning.cpp:117:20:117:22 | s indirection [post update] [val indirection] | clearning.cpp:118:2:118:2 | s indirection [val indirection] |
|
||||
| clearning.cpp:118:2:118:2 | s indirection [val indirection] | clearning.cpp:118:2:118:11 | ... += ... indirection |
|
||||
| clearning.cpp:118:2:118:2 | s indirection [val indirection] | clearning.cpp:118:4:118:6 | val indirection |
|
||||
| clearning.cpp:118:2:118:2 | s indirection [val indirection] | clearning.cpp:119:8:119:8 | s indirection [val indirection] |
|
||||
| clearning.cpp:118:2:118:11 | ... += ... indirection | clearning.cpp:118:2:118:11 | ... += ... indirection |
|
||||
| clearning.cpp:118:2:118:11 | ... += ... indirection | clearning.cpp:118:4:118:6 | s indirection [post update] [val indirection] |
|
||||
| clearning.cpp:118:4:118:6 | s indirection [post update] [val indirection] | clearning.cpp:119:8:119:8 | s indirection [val indirection] |
|
||||
| clearning.cpp:118:4:118:6 | val indirection | clearning.cpp:118:2:118:11 | ... += ... indirection |
|
||||
| clearning.cpp:119:8:119:8 | s indirection [val indirection] | clearning.cpp:119:7:119:12 | * ... |
|
||||
| clearning.cpp:119:8:119:8 | s indirection [val indirection] | clearning.cpp:119:10:119:12 | val indirection |
|
||||
| clearning.cpp:119:8:119:8 | s indirection [val indirection] | clearning.cpp:119:10:119:12 | val indirection |
|
||||
| clearning.cpp:119:10:119:12 | val indirection | clearning.cpp:119:7:119:12 | * ... |
|
||||
| clearning.cpp:119:10:119:12 | val indirection | clearning.cpp:119:7:119:12 | * ... |
|
||||
| clearning.cpp:151:3:151:22 | ... = ... | clearning.cpp:151:5:151:7 | s indirection [post update] [val] |
|
||||
| clearning.cpp:151:5:151:7 | s indirection [post update] [val] | clearning.cpp:152:8:152:8 | s indirection [val] |
|
||||
| clearning.cpp:151:11:151:20 | call to user_input | clearning.cpp:151:3:151:22 | ... = ... |
|
||||
| clearning.cpp:152:8:152:8 | s indirection [val] | clearning.cpp:152:10:152:12 | val |
|
||||
| clearning.cpp:152:8:152:8 | s indirection [val] | clearning.cpp:152:10:152:12 | val indirection |
|
||||
| clearning.cpp:152:10:152:12 | val indirection | clearning.cpp:152:10:152:12 | val |
|
||||
| complex.cpp:9:7:9:7 | this indirection [a_] | complex.cpp:9:20:9:21 | this indirection [a_] |
|
||||
| complex.cpp:9:20:9:21 | a_ | complex.cpp:9:7:9:7 | a indirection |
|
||||
| complex.cpp:9:20:9:21 | a_ indirection | complex.cpp:9:7:9:7 | a indirection |
|
||||
@@ -861,19 +993,20 @@ edges
|
||||
| struct_init.c:15:8:15:9 | ab indirection [a] | struct_init.c:15:12:15:12 | a |
|
||||
| struct_init.c:15:8:15:9 | ab indirection [a] | struct_init.c:15:12:15:12 | a indirection |
|
||||
| struct_init.c:15:12:15:12 | a indirection | struct_init.c:15:12:15:12 | a |
|
||||
| struct_init.c:20:17:20:36 | definition of ab indirection [post update] [a] | struct_init.c:22:8:22:9 | ab indirection [a] |
|
||||
| struct_init.c:20:17:20:36 | definition of ab indirection [post update] [a] | struct_init.c:24:10:24:12 | & ... indirection [a] |
|
||||
| struct_init.c:20:17:20:36 | definition of ab indirection [post update] [a] | struct_init.c:28:5:28:7 | & ... indirection [a] |
|
||||
| struct_init.c:20:13:20:14 | definition of ab indirection [a] | struct_init.c:22:8:22:9 | ab indirection [a] |
|
||||
| struct_init.c:20:13:20:14 | definition of ab indirection [a] | struct_init.c:24:10:24:12 | & ... indirection [a] |
|
||||
| struct_init.c:20:13:20:14 | definition of ab indirection [a] | struct_init.c:28:5:28:7 | & ... indirection [a] |
|
||||
| struct_init.c:20:17:20:36 | definition of ab indirection [post update] [a] | struct_init.c:20:13:20:14 | definition of ab indirection [a] |
|
||||
| struct_init.c:20:20:20:29 | call to user_input | struct_init.c:20:17:20:36 | definition of ab indirection [post update] [a] |
|
||||
| struct_init.c:20:20:20:29 | call to user_input | struct_init.c:20:20:20:29 | call to user_input |
|
||||
| struct_init.c:22:8:22:9 | ab indirection [a] | struct_init.c:22:11:22:11 | a |
|
||||
| struct_init.c:22:8:22:9 | ab indirection [a] | struct_init.c:22:11:22:11 | a indirection |
|
||||
| struct_init.c:22:11:22:11 | a indirection | struct_init.c:22:11:22:11 | a |
|
||||
| struct_init.c:24:10:24:12 | & ... indirection [a] | struct_init.c:14:24:14:25 | ab indirection [a] |
|
||||
| struct_init.c:26:23:29:3 | definition of outer indirection [post update] [nestedAB, a] | struct_init.c:31:8:31:12 | outer indirection [nestedAB, a] |
|
||||
| struct_init.c:26:23:29:3 | definition of outer indirection [post update] [nestedAB, a] | struct_init.c:31:8:31:12 | outer indirection [nestedAB, a] |
|
||||
| struct_init.c:26:23:29:3 | definition of outer indirection [post update] [nestedAB, a] | struct_init.c:36:11:36:15 | outer indirection [nestedAB, a] |
|
||||
| struct_init.c:26:23:29:3 | definition of outer indirection [post update] [nestedAB, a] | struct_init.c:36:11:36:15 | outer indirection [nestedAB, a] |
|
||||
| struct_init.c:26:16:26:20 | definition of outer indirection [nestedAB, a] | struct_init.c:31:8:31:12 | outer indirection [nestedAB, a] |
|
||||
| struct_init.c:26:16:26:20 | definition of outer indirection [nestedAB, a] | struct_init.c:36:11:36:15 | outer indirection [nestedAB, a] |
|
||||
| struct_init.c:26:23:29:3 | definition of outer indirection [post update] [nestedAB, a] | struct_init.c:26:16:26:20 | definition of outer indirection [nestedAB, a] |
|
||||
| struct_init.c:26:23:29:3 | definition of outer indirection [post update] [nestedAB, a] | struct_init.c:26:16:26:20 | definition of outer indirection [nestedAB, a] |
|
||||
| struct_init.c:26:23:29:3 | definition of outer indirection [post update] [pointerAB indirection, a] | struct_init.c:33:8:33:12 | outer indirection [pointerAB indirection, a] |
|
||||
| struct_init.c:27:5:27:23 | {...} indirection [post update] [a] | struct_init.c:26:23:29:3 | definition of outer indirection [post update] [nestedAB, a] |
|
||||
| struct_init.c:27:5:27:23 | {...} indirection [post update] [a] | struct_init.c:26:23:29:3 | definition of outer indirection [post update] [nestedAB, a] |
|
||||
@@ -892,7 +1025,8 @@ edges
|
||||
| struct_init.c:33:25:33:25 | a indirection | struct_init.c:33:25:33:25 | a |
|
||||
| struct_init.c:36:10:36:24 | & ... indirection [a] | struct_init.c:14:24:14:25 | ab indirection [a] |
|
||||
| struct_init.c:36:11:36:15 | outer indirection [nestedAB, a] | struct_init.c:36:10:36:24 | & ... indirection [a] |
|
||||
| struct_init.c:40:17:40:36 | definition of ab indirection [post update] [a] | struct_init.c:43:5:43:7 | & ... indirection [a] |
|
||||
| struct_init.c:40:13:40:14 | definition of ab indirection [a] | struct_init.c:43:5:43:7 | & ... indirection [a] |
|
||||
| struct_init.c:40:17:40:36 | definition of ab indirection [post update] [a] | struct_init.c:40:13:40:14 | definition of ab indirection [a] |
|
||||
| struct_init.c:40:20:40:29 | call to user_input | struct_init.c:40:17:40:36 | definition of ab indirection [post update] [a] |
|
||||
| struct_init.c:40:20:40:29 | call to user_input | struct_init.c:40:20:40:29 | call to user_input |
|
||||
| struct_init.c:41:23:44:3 | definition of outer indirection [post update] [pointerAB indirection, a] | struct_init.c:46:10:46:14 | outer indirection [pointerAB indirection, a] |
|
||||
@@ -917,6 +1051,7 @@ nodes
|
||||
| A.cpp:29:23:29:23 | c | semmle.label | c |
|
||||
| A.cpp:31:14:31:21 | call to B [c] | semmle.label | call to B [c] |
|
||||
| A.cpp:31:20:31:20 | c | semmle.label | c |
|
||||
| A.cpp:41:5:41:6 | insert output argument | semmle.label | insert output argument |
|
||||
| A.cpp:41:15:41:21 | new | semmle.label | new |
|
||||
| A.cpp:41:15:41:21 | new | semmle.label | new |
|
||||
| A.cpp:43:10:43:12 | & ... indirection | semmle.label | & ... indirection |
|
||||
@@ -1433,6 +1568,114 @@ nodes
|
||||
| by_reference.cpp:136:8:136:13 | pouter indirection [a] | semmle.label | pouter indirection [a] |
|
||||
| by_reference.cpp:136:16:136:16 | a | semmle.label | a |
|
||||
| by_reference.cpp:136:16:136:16 | a indirection | semmle.label | a indirection |
|
||||
| clearning.cpp:32:3:32:25 | ... = ... | semmle.label | ... = ... |
|
||||
| clearning.cpp:32:6:32:6 | s indirection [post update] [x indirection] | semmle.label | s indirection [post update] [x indirection] |
|
||||
| clearning.cpp:32:10:32:19 | call to user_input | semmle.label | call to user_input |
|
||||
| clearning.cpp:33:5:33:5 | s indirection [x indirection] | semmle.label | s indirection [x indirection] |
|
||||
| clearning.cpp:34:8:34:11 | * ... | semmle.label | * ... |
|
||||
| clearning.cpp:34:9:34:9 | s indirection [x indirection] | semmle.label | s indirection [x indirection] |
|
||||
| clearning.cpp:34:11:34:11 | x indirection | semmle.label | x indirection |
|
||||
| clearning.cpp:34:11:34:11 | x indirection | semmle.label | x indirection |
|
||||
| clearning.cpp:53:3:53:25 | ... = ... | semmle.label | ... = ... |
|
||||
| clearning.cpp:53:6:53:6 | s indirection [post update] [x indirection] | semmle.label | s indirection [post update] [x indirection] |
|
||||
| clearning.cpp:53:10:53:19 | call to user_input | semmle.label | call to user_input |
|
||||
| clearning.cpp:54:3:54:3 | s indirection [x indirection] | semmle.label | s indirection [x indirection] |
|
||||
| clearning.cpp:54:3:54:7 | ... ++ indirection | semmle.label | ... ++ indirection |
|
||||
| clearning.cpp:54:3:54:7 | ... ++ indirection | semmle.label | ... ++ indirection |
|
||||
| clearning.cpp:54:5:54:5 | s indirection [post update] [x indirection] | semmle.label | s indirection [post update] [x indirection] |
|
||||
| clearning.cpp:54:5:54:5 | x indirection | semmle.label | x indirection |
|
||||
| clearning.cpp:55:8:55:8 | s indirection [x indirection] | semmle.label | s indirection [x indirection] |
|
||||
| clearning.cpp:55:10:55:10 | x indirection | semmle.label | x indirection |
|
||||
| clearning.cpp:55:10:55:10 | x indirection | semmle.label | x indirection |
|
||||
| clearning.cpp:60:3:60:22 | ... = ... | semmle.label | ... = ... |
|
||||
| clearning.cpp:60:7:60:7 | s indirection [post update] [x indirection] | semmle.label | s indirection [post update] [x indirection] |
|
||||
| clearning.cpp:60:11:60:20 | call to user_input | semmle.label | call to user_input |
|
||||
| clearning.cpp:61:3:61:3 | s indirection [x indirection] | semmle.label | s indirection [x indirection] |
|
||||
| clearning.cpp:61:3:61:7 | ... ++ indirection | semmle.label | ... ++ indirection |
|
||||
| clearning.cpp:61:3:61:7 | ... ++ indirection | semmle.label | ... ++ indirection |
|
||||
| clearning.cpp:61:5:61:5 | s indirection [post update] [x indirection] | semmle.label | s indirection [post update] [x indirection] |
|
||||
| clearning.cpp:61:5:61:5 | x indirection | semmle.label | x indirection |
|
||||
| clearning.cpp:62:8:62:8 | s indirection [x indirection] | semmle.label | s indirection [x indirection] |
|
||||
| clearning.cpp:62:10:62:10 | x indirection | semmle.label | x indirection |
|
||||
| clearning.cpp:62:10:62:10 | x indirection | semmle.label | x indirection |
|
||||
| clearning.cpp:74:20:74:22 | argument_source output argument | semmle.label | argument_source output argument |
|
||||
| clearning.cpp:74:20:74:22 | s indirection [post update] [val indirection] | semmle.label | s indirection [post update] [val indirection] |
|
||||
| clearning.cpp:76:7:76:12 | * ... | semmle.label | * ... |
|
||||
| clearning.cpp:76:8:76:8 | s indirection [val indirection] | semmle.label | s indirection [val indirection] |
|
||||
| clearning.cpp:76:10:76:12 | val indirection | semmle.label | val indirection |
|
||||
| clearning.cpp:76:10:76:12 | val indirection | semmle.label | val indirection |
|
||||
| clearning.cpp:81:20:81:22 | argument_source output argument | semmle.label | argument_source output argument |
|
||||
| clearning.cpp:81:20:81:22 | s indirection [post update] [val indirection] | semmle.label | s indirection [post update] [val indirection] |
|
||||
| clearning.cpp:83:5:83:21 | ... = ... indirection | semmle.label | ... = ... indirection |
|
||||
| clearning.cpp:83:7:83:9 | s indirection [post update] [val indirection] | semmle.label | s indirection [post update] [val indirection] |
|
||||
| clearning.cpp:83:13:83:13 | s indirection [val indirection] | semmle.label | s indirection [val indirection] |
|
||||
| clearning.cpp:83:13:83:21 | ... + ... indirection | semmle.label | ... + ... indirection |
|
||||
| clearning.cpp:83:15:83:17 | val indirection | semmle.label | val indirection |
|
||||
| clearning.cpp:84:7:84:12 | * ... | semmle.label | * ... |
|
||||
| clearning.cpp:84:8:84:8 | s indirection [val indirection] | semmle.label | s indirection [val indirection] |
|
||||
| clearning.cpp:84:10:84:12 | val indirection | semmle.label | val indirection |
|
||||
| clearning.cpp:84:10:84:12 | val indirection | semmle.label | val indirection |
|
||||
| clearning.cpp:89:20:89:22 | argument_source output argument | semmle.label | argument_source output argument |
|
||||
| clearning.cpp:89:20:89:22 | s indirection [post update] [val indirection] | semmle.label | s indirection [post update] [val indirection] |
|
||||
| clearning.cpp:90:3:90:3 | s indirection [val indirection] | semmle.label | s indirection [val indirection] |
|
||||
| clearning.cpp:90:3:90:9 | ... ++ indirection | semmle.label | ... ++ indirection |
|
||||
| clearning.cpp:90:3:90:9 | ... ++ indirection | semmle.label | ... ++ indirection |
|
||||
| clearning.cpp:90:5:90:7 | s indirection [post update] [val indirection] | semmle.label | s indirection [post update] [val indirection] |
|
||||
| clearning.cpp:90:5:90:7 | val indirection | semmle.label | val indirection |
|
||||
| clearning.cpp:91:7:91:12 | * ... | semmle.label | * ... |
|
||||
| clearning.cpp:91:8:91:8 | s indirection [val indirection] | semmle.label | s indirection [val indirection] |
|
||||
| clearning.cpp:91:10:91:12 | val indirection | semmle.label | val indirection |
|
||||
| clearning.cpp:91:10:91:12 | val indirection | semmle.label | val indirection |
|
||||
| clearning.cpp:96:20:96:22 | argument_source output argument | semmle.label | argument_source output argument |
|
||||
| clearning.cpp:96:20:96:22 | s indirection [post update] [val indirection] | semmle.label | s indirection [post update] [val indirection] |
|
||||
| clearning.cpp:97:2:97:18 | ... = ... indirection | semmle.label | ... = ... indirection |
|
||||
| clearning.cpp:97:4:97:6 | s indirection [post update] [val indirection] | semmle.label | s indirection [post update] [val indirection] |
|
||||
| clearning.cpp:97:10:97:10 | s indirection [val indirection] | semmle.label | s indirection [val indirection] |
|
||||
| clearning.cpp:97:10:97:18 | ... + ... indirection | semmle.label | ... + ... indirection |
|
||||
| clearning.cpp:97:12:97:14 | val indirection | semmle.label | val indirection |
|
||||
| clearning.cpp:98:7:98:12 | * ... | semmle.label | * ... |
|
||||
| clearning.cpp:98:8:98:8 | s indirection [val indirection] | semmle.label | s indirection [val indirection] |
|
||||
| clearning.cpp:98:10:98:12 | val indirection | semmle.label | val indirection |
|
||||
| clearning.cpp:98:10:98:12 | val indirection | semmle.label | val indirection |
|
||||
| clearning.cpp:103:20:103:22 | argument_source output argument | semmle.label | argument_source output argument |
|
||||
| clearning.cpp:103:20:103:22 | s indirection [post update] [val indirection] | semmle.label | s indirection [post update] [val indirection] |
|
||||
| clearning.cpp:104:2:104:2 | s indirection [val indirection] | semmle.label | s indirection [val indirection] |
|
||||
| clearning.cpp:104:2:104:8 | ... ++ indirection | semmle.label | ... ++ indirection |
|
||||
| clearning.cpp:104:2:104:8 | ... ++ indirection | semmle.label | ... ++ indirection |
|
||||
| clearning.cpp:104:4:104:6 | s indirection [post update] [val indirection] | semmle.label | s indirection [post update] [val indirection] |
|
||||
| clearning.cpp:104:4:104:6 | val indirection | semmle.label | val indirection |
|
||||
| clearning.cpp:105:7:105:12 | * ... | semmle.label | * ... |
|
||||
| clearning.cpp:105:8:105:8 | s indirection [val indirection] | semmle.label | s indirection [val indirection] |
|
||||
| clearning.cpp:105:10:105:12 | val indirection | semmle.label | val indirection |
|
||||
| clearning.cpp:105:10:105:12 | val indirection | semmle.label | val indirection |
|
||||
| clearning.cpp:110:20:110:22 | argument_source output argument | semmle.label | argument_source output argument |
|
||||
| clearning.cpp:110:20:110:22 | s indirection [post update] [val indirection] | semmle.label | s indirection [post update] [val indirection] |
|
||||
| clearning.cpp:111:2:111:8 | ++ ... indirection | semmle.label | ++ ... indirection |
|
||||
| clearning.cpp:111:2:111:8 | ++ ... indirection | semmle.label | ++ ... indirection |
|
||||
| clearning.cpp:111:4:111:4 | s indirection [val indirection] | semmle.label | s indirection [val indirection] |
|
||||
| clearning.cpp:111:6:111:8 | s indirection [post update] [val indirection] | semmle.label | s indirection [post update] [val indirection] |
|
||||
| clearning.cpp:111:6:111:8 | val indirection | semmle.label | val indirection |
|
||||
| clearning.cpp:112:7:112:12 | * ... | semmle.label | * ... |
|
||||
| clearning.cpp:112:8:112:8 | s indirection [val indirection] | semmle.label | s indirection [val indirection] |
|
||||
| clearning.cpp:112:10:112:12 | val indirection | semmle.label | val indirection |
|
||||
| clearning.cpp:112:10:112:12 | val indirection | semmle.label | val indirection |
|
||||
| clearning.cpp:117:20:117:22 | argument_source output argument | semmle.label | argument_source output argument |
|
||||
| clearning.cpp:117:20:117:22 | s indirection [post update] [val indirection] | semmle.label | s indirection [post update] [val indirection] |
|
||||
| clearning.cpp:118:2:118:2 | s indirection [val indirection] | semmle.label | s indirection [val indirection] |
|
||||
| clearning.cpp:118:2:118:11 | ... += ... indirection | semmle.label | ... += ... indirection |
|
||||
| clearning.cpp:118:2:118:11 | ... += ... indirection | semmle.label | ... += ... indirection |
|
||||
| clearning.cpp:118:4:118:6 | s indirection [post update] [val indirection] | semmle.label | s indirection [post update] [val indirection] |
|
||||
| clearning.cpp:118:4:118:6 | val indirection | semmle.label | val indirection |
|
||||
| clearning.cpp:119:7:119:12 | * ... | semmle.label | * ... |
|
||||
| clearning.cpp:119:8:119:8 | s indirection [val indirection] | semmle.label | s indirection [val indirection] |
|
||||
| clearning.cpp:119:10:119:12 | val indirection | semmle.label | val indirection |
|
||||
| clearning.cpp:119:10:119:12 | val indirection | semmle.label | val indirection |
|
||||
| clearning.cpp:151:3:151:22 | ... = ... | semmle.label | ... = ... |
|
||||
| clearning.cpp:151:5:151:7 | s indirection [post update] [val] | semmle.label | s indirection [post update] [val] |
|
||||
| clearning.cpp:151:11:151:20 | call to user_input | semmle.label | call to user_input |
|
||||
| clearning.cpp:152:8:152:8 | s indirection [val] | semmle.label | s indirection [val] |
|
||||
| clearning.cpp:152:10:152:12 | val | semmle.label | val |
|
||||
| clearning.cpp:152:10:152:12 | val indirection | semmle.label | val indirection |
|
||||
| complex.cpp:9:7:9:7 | a indirection | semmle.label | a indirection |
|
||||
| complex.cpp:9:7:9:7 | this indirection [a_] | semmle.label | this indirection [a_] |
|
||||
| complex.cpp:9:20:9:21 | a_ | semmle.label | a_ |
|
||||
@@ -1699,6 +1942,7 @@ nodes
|
||||
| struct_init.c:15:8:15:9 | ab indirection [a] | semmle.label | ab indirection [a] |
|
||||
| struct_init.c:15:12:15:12 | a | semmle.label | a |
|
||||
| struct_init.c:15:12:15:12 | a indirection | semmle.label | a indirection |
|
||||
| struct_init.c:20:13:20:14 | definition of ab indirection [a] | semmle.label | definition of ab indirection [a] |
|
||||
| struct_init.c:20:17:20:36 | definition of ab indirection [post update] [a] | semmle.label | definition of ab indirection [post update] [a] |
|
||||
| struct_init.c:20:20:20:29 | call to user_input | semmle.label | call to user_input |
|
||||
| struct_init.c:20:20:20:29 | call to user_input | semmle.label | call to user_input |
|
||||
@@ -1706,6 +1950,7 @@ nodes
|
||||
| struct_init.c:22:11:22:11 | a | semmle.label | a |
|
||||
| struct_init.c:22:11:22:11 | a indirection | semmle.label | a indirection |
|
||||
| struct_init.c:24:10:24:12 | & ... indirection [a] | semmle.label | & ... indirection [a] |
|
||||
| struct_init.c:26:16:26:20 | definition of outer indirection [nestedAB, a] | semmle.label | definition of outer indirection [nestedAB, a] |
|
||||
| struct_init.c:26:23:29:3 | definition of outer indirection [post update] [nestedAB, a] | semmle.label | definition of outer indirection [post update] [nestedAB, a] |
|
||||
| struct_init.c:26:23:29:3 | definition of outer indirection [post update] [nestedAB, a] | semmle.label | definition of outer indirection [post update] [nestedAB, a] |
|
||||
| struct_init.c:26:23:29:3 | definition of outer indirection [post update] [pointerAB indirection, a] | semmle.label | definition of outer indirection [post update] [pointerAB indirection, a] |
|
||||
@@ -1724,6 +1969,7 @@ nodes
|
||||
| struct_init.c:33:25:33:25 | a indirection | semmle.label | a indirection |
|
||||
| struct_init.c:36:10:36:24 | & ... indirection [a] | semmle.label | & ... indirection [a] |
|
||||
| struct_init.c:36:11:36:15 | outer indirection [nestedAB, a] | semmle.label | outer indirection [nestedAB, a] |
|
||||
| struct_init.c:40:13:40:14 | definition of ab indirection [a] | semmle.label | definition of ab indirection [a] |
|
||||
| struct_init.c:40:17:40:36 | definition of ab indirection [post update] [a] | semmle.label | definition of ab indirection [post update] [a] |
|
||||
| struct_init.c:40:20:40:29 | call to user_input | semmle.label | call to user_input |
|
||||
| struct_init.c:40:20:40:29 | call to user_input | semmle.label | call to user_input |
|
||||
@@ -1883,6 +2129,17 @@ subpaths
|
||||
| by_reference.cpp:134:29:134:29 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:134:29:134:29 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input |
|
||||
| by_reference.cpp:135:27:135:27 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:135:27:135:27 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input |
|
||||
| by_reference.cpp:136:16:136:16 | a | by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:136:16:136:16 | a | a flows from $@ | by_reference.cpp:96:8:96:17 | call to user_input | call to user_input |
|
||||
| clearning.cpp:34:8:34:11 | * ... | clearning.cpp:32:10:32:19 | call to user_input | clearning.cpp:34:8:34:11 | * ... | * ... flows from $@ | clearning.cpp:32:10:32:19 | call to user_input | call to user_input |
|
||||
| clearning.cpp:55:10:55:10 | x indirection | clearning.cpp:53:10:53:19 | call to user_input | clearning.cpp:55:10:55:10 | x indirection | x indirection flows from $@ | clearning.cpp:53:10:53:19 | call to user_input | call to user_input |
|
||||
| clearning.cpp:62:10:62:10 | x indirection | clearning.cpp:60:11:60:20 | call to user_input | clearning.cpp:62:10:62:10 | x indirection | x indirection flows from $@ | clearning.cpp:60:11:60:20 | call to user_input | call to user_input |
|
||||
| clearning.cpp:76:7:76:12 | * ... | clearning.cpp:74:20:74:22 | argument_source output argument | clearning.cpp:76:7:76:12 | * ... | * ... flows from $@ | clearning.cpp:74:20:74:22 | argument_source output argument | argument_source output argument |
|
||||
| clearning.cpp:84:7:84:12 | * ... | clearning.cpp:81:20:81:22 | argument_source output argument | clearning.cpp:84:7:84:12 | * ... | * ... flows from $@ | clearning.cpp:81:20:81:22 | argument_source output argument | argument_source output argument |
|
||||
| clearning.cpp:91:7:91:12 | * ... | clearning.cpp:89:20:89:22 | argument_source output argument | clearning.cpp:91:7:91:12 | * ... | * ... flows from $@ | clearning.cpp:89:20:89:22 | argument_source output argument | argument_source output argument |
|
||||
| clearning.cpp:98:7:98:12 | * ... | clearning.cpp:96:20:96:22 | argument_source output argument | clearning.cpp:98:7:98:12 | * ... | * ... flows from $@ | clearning.cpp:96:20:96:22 | argument_source output argument | argument_source output argument |
|
||||
| clearning.cpp:105:7:105:12 | * ... | clearning.cpp:103:20:103:22 | argument_source output argument | clearning.cpp:105:7:105:12 | * ... | * ... flows from $@ | clearning.cpp:103:20:103:22 | argument_source output argument | argument_source output argument |
|
||||
| clearning.cpp:112:7:112:12 | * ... | clearning.cpp:110:20:110:22 | argument_source output argument | clearning.cpp:112:7:112:12 | * ... | * ... flows from $@ | clearning.cpp:110:20:110:22 | argument_source output argument | argument_source output argument |
|
||||
| clearning.cpp:119:7:119:12 | * ... | clearning.cpp:117:20:117:22 | argument_source output argument | clearning.cpp:119:7:119:12 | * ... | * ... flows from $@ | clearning.cpp:117:20:117:22 | argument_source output argument | argument_source output argument |
|
||||
| clearning.cpp:152:10:152:12 | val | clearning.cpp:151:11:151:20 | call to user_input | clearning.cpp:152:10:152:12 | val | val flows from $@ | clearning.cpp:151:11:151:20 | call to user_input | call to user_input |
|
||||
| complex.cpp:42:18:42:18 | call to a | complex.cpp:53:19:53:28 | call to user_input | complex.cpp:42:18:42:18 | call to a | call to a flows from $@ | complex.cpp:53:19:53:28 | call to user_input | call to user_input |
|
||||
| complex.cpp:42:18:42:18 | call to a | complex.cpp:55:19:55:28 | call to user_input | complex.cpp:42:18:42:18 | call to a | call to a flows from $@ | complex.cpp:55:19:55:28 | call to user_input | call to user_input |
|
||||
| complex.cpp:43:18:43:18 | call to b | complex.cpp:54:19:54:28 | call to user_input | complex.cpp:43:18:43:18 | call to b | call to b flows from $@ | complex.cpp:54:19:54:28 | call to user_input | call to user_input |
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (partial-definition-diff.ql:7,8-51)
|
||||
| A.cpp:25:13:25:13 | c | AST only |
|
||||
| A.cpp:27:28:27:28 | c | AST only |
|
||||
| A.cpp:28:29:28:29 | this | IR only |
|
||||
@@ -167,6 +168,66 @@
|
||||
| by_reference.cpp:88:9:88:9 | a | AST only |
|
||||
| by_reference.cpp:92:3:92:5 | * ... | AST only |
|
||||
| by_reference.cpp:96:3:96:4 | pa | AST only |
|
||||
| clearning.cpp:18:7:18:7 | s | IR only |
|
||||
| clearning.cpp:19:3:19:6 | * ... | AST only |
|
||||
| clearning.cpp:20:12:20:12 | s | IR only |
|
||||
| clearning.cpp:25:7:25:7 | s | IR only |
|
||||
| clearning.cpp:26:7:26:7 | s | IR only |
|
||||
| clearning.cpp:27:12:27:12 | s | IR only |
|
||||
| clearning.cpp:32:3:32:6 | * ... | AST only |
|
||||
| clearning.cpp:33:7:33:7 | s | IR only |
|
||||
| clearning.cpp:34:8:34:11 | * ... | IR only |
|
||||
| clearning.cpp:34:11:34:11 | s | IR only |
|
||||
| clearning.cpp:39:3:39:6 | * ... | AST only |
|
||||
| clearning.cpp:40:5:40:5 | x | AST only |
|
||||
| clearning.cpp:41:8:41:11 | * ... | IR only |
|
||||
| clearning.cpp:41:11:41:11 | s | IR only |
|
||||
| clearning.cpp:46:7:46:7 | s | IR only |
|
||||
| clearning.cpp:47:5:47:5 | x | AST only |
|
||||
| clearning.cpp:48:8:48:11 | * ... | IR only |
|
||||
| clearning.cpp:48:11:48:11 | s | IR only |
|
||||
| clearning.cpp:53:3:53:6 | * ... | AST only |
|
||||
| clearning.cpp:54:5:54:5 | x | AST only |
|
||||
| clearning.cpp:60:7:60:7 | s | IR only |
|
||||
| clearning.cpp:61:5:61:5 | x | AST only |
|
||||
| clearning.cpp:75:2:75:10 | access to array | AST only |
|
||||
| clearning.cpp:76:10:76:12 | s | IR only |
|
||||
| clearning.cpp:82:2:82:9 | access to array | AST only |
|
||||
| clearning.cpp:83:7:83:9 | val | AST only |
|
||||
| clearning.cpp:83:15:83:17 | s | IR only |
|
||||
| clearning.cpp:84:10:84:12 | s | IR only |
|
||||
| clearning.cpp:90:5:90:7 | val | AST only |
|
||||
| clearning.cpp:91:10:91:12 | s | IR only |
|
||||
| clearning.cpp:97:4:97:6 | val | AST only |
|
||||
| clearning.cpp:97:12:97:14 | s | IR only |
|
||||
| clearning.cpp:98:10:98:12 | s | IR only |
|
||||
| clearning.cpp:104:4:104:6 | val | AST only |
|
||||
| clearning.cpp:105:10:105:12 | s | IR only |
|
||||
| clearning.cpp:111:6:111:8 | val | AST only |
|
||||
| clearning.cpp:112:10:112:12 | s | IR only |
|
||||
| clearning.cpp:118:4:118:6 | val | AST only |
|
||||
| clearning.cpp:119:10:119:12 | s | IR only |
|
||||
| clearning.cpp:124:4:124:6 | val | AST only |
|
||||
| clearning.cpp:125:4:125:6 | val | AST only |
|
||||
| clearning.cpp:131:4:131:6 | val | AST only |
|
||||
| clearning.cpp:132:4:132:6 | val | AST only |
|
||||
| clearning.cpp:138:4:138:6 | val | AST only |
|
||||
| clearning.cpp:139:6:139:8 | val | AST only |
|
||||
| clearning.cpp:151:5:151:7 | val | AST only |
|
||||
| clearning.cpp:152:10:152:12 | s | IR only |
|
||||
| clearning.cpp:157:5:157:7 | val | AST only |
|
||||
| clearning.cpp:158:5:158:7 | val | AST only |
|
||||
| clearning.cpp:159:10:159:12 | s | IR only |
|
||||
| clearning.cpp:164:5:164:7 | val | AST only |
|
||||
| clearning.cpp:165:5:165:7 | val | AST only |
|
||||
| clearning.cpp:166:10:166:12 | s | IR only |
|
||||
| clearning.cpp:171:5:171:7 | val | AST only |
|
||||
| clearning.cpp:172:5:172:7 | val | AST only |
|
||||
| clearning.cpp:173:10:173:12 | s | IR only |
|
||||
| clearning.cpp:178:5:178:7 | val | AST only |
|
||||
| clearning.cpp:179:5:179:7 | val | AST only |
|
||||
| clearning.cpp:179:13:179:15 | s | IR only |
|
||||
| clearning.cpp:180:10:180:12 | s | IR only |
|
||||
| complex.cpp:9:20:9:21 | this | IR only |
|
||||
| complex.cpp:10:20:10:21 | this | IR only |
|
||||
| complex.cpp:11:22:11:23 | a_ | AST only |
|
||||
|
||||
@@ -408,6 +408,90 @@
|
||||
| by_reference.cpp:135:27:135:27 | a |
|
||||
| by_reference.cpp:136:8:136:13 | pouter |
|
||||
| by_reference.cpp:136:16:136:16 | a |
|
||||
| clearning.cpp:18:5:18:5 | s |
|
||||
| clearning.cpp:19:4:19:4 | s |
|
||||
| clearning.cpp:20:10:20:10 | s |
|
||||
| clearning.cpp:25:5:25:5 | s |
|
||||
| clearning.cpp:26:5:26:5 | s |
|
||||
| clearning.cpp:27:10:27:10 | s |
|
||||
| clearning.cpp:32:4:32:4 | s |
|
||||
| clearning.cpp:33:5:33:5 | s |
|
||||
| clearning.cpp:34:8:34:11 | * ... |
|
||||
| clearning.cpp:34:9:34:9 | s |
|
||||
| clearning.cpp:39:4:39:4 | s |
|
||||
| clearning.cpp:40:3:40:3 | s |
|
||||
| clearning.cpp:41:8:41:11 | * ... |
|
||||
| clearning.cpp:41:9:41:9 | s |
|
||||
| clearning.cpp:46:5:46:5 | s |
|
||||
| clearning.cpp:47:3:47:3 | s |
|
||||
| clearning.cpp:48:8:48:11 | * ... |
|
||||
| clearning.cpp:48:9:48:9 | s |
|
||||
| clearning.cpp:53:4:53:4 | s |
|
||||
| clearning.cpp:54:3:54:3 | s |
|
||||
| clearning.cpp:55:8:55:8 | s |
|
||||
| clearning.cpp:55:10:55:10 | x |
|
||||
| clearning.cpp:60:5:60:5 | s |
|
||||
| clearning.cpp:61:3:61:3 | s |
|
||||
| clearning.cpp:62:8:62:8 | s |
|
||||
| clearning.cpp:62:10:62:10 | x |
|
||||
| clearning.cpp:74:18:74:18 | s |
|
||||
| clearning.cpp:74:20:74:22 | val |
|
||||
| clearning.cpp:75:2:75:2 | s |
|
||||
| clearning.cpp:76:8:76:8 | s |
|
||||
| clearning.cpp:81:18:81:18 | s |
|
||||
| clearning.cpp:81:20:81:22 | val |
|
||||
| clearning.cpp:82:2:82:2 | s |
|
||||
| clearning.cpp:83:5:83:5 | s |
|
||||
| clearning.cpp:83:13:83:13 | s |
|
||||
| clearning.cpp:84:8:84:8 | s |
|
||||
| clearning.cpp:89:18:89:18 | s |
|
||||
| clearning.cpp:89:20:89:22 | val |
|
||||
| clearning.cpp:90:3:90:3 | s |
|
||||
| clearning.cpp:91:8:91:8 | s |
|
||||
| clearning.cpp:96:18:96:18 | s |
|
||||
| clearning.cpp:96:20:96:22 | val |
|
||||
| clearning.cpp:97:2:97:2 | s |
|
||||
| clearning.cpp:97:10:97:10 | s |
|
||||
| clearning.cpp:98:8:98:8 | s |
|
||||
| clearning.cpp:103:18:103:18 | s |
|
||||
| clearning.cpp:103:20:103:22 | val |
|
||||
| clearning.cpp:104:2:104:2 | s |
|
||||
| clearning.cpp:105:8:105:8 | s |
|
||||
| clearning.cpp:110:18:110:18 | s |
|
||||
| clearning.cpp:110:20:110:22 | val |
|
||||
| clearning.cpp:111:4:111:4 | s |
|
||||
| clearning.cpp:112:8:112:8 | s |
|
||||
| clearning.cpp:117:18:117:18 | s |
|
||||
| clearning.cpp:117:20:117:22 | val |
|
||||
| clearning.cpp:118:2:118:2 | s |
|
||||
| clearning.cpp:119:8:119:8 | s |
|
||||
| clearning.cpp:124:2:124:2 | s |
|
||||
| clearning.cpp:125:2:125:2 | s |
|
||||
| clearning.cpp:126:7:126:7 | s |
|
||||
| clearning.cpp:126:9:126:11 | val |
|
||||
| clearning.cpp:131:2:131:2 | s |
|
||||
| clearning.cpp:132:2:132:2 | s |
|
||||
| clearning.cpp:133:7:133:7 | s |
|
||||
| clearning.cpp:133:9:133:11 | val |
|
||||
| clearning.cpp:138:2:138:2 | s |
|
||||
| clearning.cpp:139:4:139:4 | s |
|
||||
| clearning.cpp:140:7:140:7 | s |
|
||||
| clearning.cpp:140:9:140:11 | val |
|
||||
| clearning.cpp:151:3:151:3 | s |
|
||||
| clearning.cpp:152:8:152:8 | s |
|
||||
| clearning.cpp:157:3:157:3 | s |
|
||||
| clearning.cpp:158:3:158:3 | s |
|
||||
| clearning.cpp:159:8:159:8 | s |
|
||||
| clearning.cpp:164:3:164:3 | s |
|
||||
| clearning.cpp:165:3:165:3 | s |
|
||||
| clearning.cpp:166:8:166:8 | s |
|
||||
| clearning.cpp:171:3:171:3 | s |
|
||||
| clearning.cpp:172:3:172:3 | s |
|
||||
| clearning.cpp:173:8:173:8 | s |
|
||||
| clearning.cpp:178:3:178:3 | s |
|
||||
| clearning.cpp:179:3:179:3 | s |
|
||||
| clearning.cpp:179:11:179:11 | s |
|
||||
| clearning.cpp:180:8:180:8 | s |
|
||||
| complex.cpp:9:20:9:21 | this |
|
||||
| complex.cpp:10:20:10:21 | this |
|
||||
| complex.cpp:11:22:11:23 | this |
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (partial-definition.ql:6,8-51)
|
||||
| A.cpp:25:7:25:10 | this |
|
||||
| A.cpp:25:13:25:13 | c |
|
||||
| A.cpp:27:22:27:25 | this |
|
||||
@@ -348,6 +349,92 @@
|
||||
| by_reference.cpp:135:27:135:27 | a |
|
||||
| by_reference.cpp:136:8:136:13 | pouter |
|
||||
| by_reference.cpp:136:16:136:16 | a |
|
||||
| clearning.cpp:19:3:19:6 | * ... |
|
||||
| clearning.cpp:19:4:19:4 | s |
|
||||
| clearning.cpp:32:3:32:6 | * ... |
|
||||
| clearning.cpp:32:4:32:4 | s |
|
||||
| clearning.cpp:39:3:39:6 | * ... |
|
||||
| clearning.cpp:39:4:39:4 | s |
|
||||
| clearning.cpp:40:3:40:3 | s |
|
||||
| clearning.cpp:40:5:40:5 | x |
|
||||
| clearning.cpp:47:3:47:3 | s |
|
||||
| clearning.cpp:47:5:47:5 | x |
|
||||
| clearning.cpp:53:3:53:6 | * ... |
|
||||
| clearning.cpp:53:4:53:4 | s |
|
||||
| clearning.cpp:54:3:54:3 | s |
|
||||
| clearning.cpp:54:5:54:5 | x |
|
||||
| clearning.cpp:55:8:55:8 | s |
|
||||
| clearning.cpp:55:10:55:10 | x |
|
||||
| clearning.cpp:61:3:61:3 | s |
|
||||
| clearning.cpp:61:5:61:5 | x |
|
||||
| clearning.cpp:62:8:62:8 | s |
|
||||
| clearning.cpp:62:10:62:10 | x |
|
||||
| clearning.cpp:74:18:74:18 | s |
|
||||
| clearning.cpp:74:20:74:22 | val |
|
||||
| clearning.cpp:75:2:75:2 | s |
|
||||
| clearning.cpp:75:2:75:10 | access to array |
|
||||
| clearning.cpp:81:18:81:18 | s |
|
||||
| clearning.cpp:81:20:81:22 | val |
|
||||
| clearning.cpp:82:2:82:2 | s |
|
||||
| clearning.cpp:82:2:82:9 | access to array |
|
||||
| clearning.cpp:83:5:83:5 | s |
|
||||
| clearning.cpp:83:7:83:9 | val |
|
||||
| clearning.cpp:89:18:89:18 | s |
|
||||
| clearning.cpp:89:20:89:22 | val |
|
||||
| clearning.cpp:90:3:90:3 | s |
|
||||
| clearning.cpp:90:5:90:7 | val |
|
||||
| clearning.cpp:96:18:96:18 | s |
|
||||
| clearning.cpp:96:20:96:22 | val |
|
||||
| clearning.cpp:97:2:97:2 | s |
|
||||
| clearning.cpp:97:4:97:6 | val |
|
||||
| clearning.cpp:103:18:103:18 | s |
|
||||
| clearning.cpp:103:20:103:22 | val |
|
||||
| clearning.cpp:104:2:104:2 | s |
|
||||
| clearning.cpp:104:4:104:6 | val |
|
||||
| clearning.cpp:110:18:110:18 | s |
|
||||
| clearning.cpp:110:20:110:22 | val |
|
||||
| clearning.cpp:111:4:111:4 | s |
|
||||
| clearning.cpp:111:6:111:8 | val |
|
||||
| clearning.cpp:117:18:117:18 | s |
|
||||
| clearning.cpp:117:20:117:22 | val |
|
||||
| clearning.cpp:118:2:118:2 | s |
|
||||
| clearning.cpp:118:4:118:6 | val |
|
||||
| clearning.cpp:124:2:124:2 | s |
|
||||
| clearning.cpp:124:4:124:6 | val |
|
||||
| clearning.cpp:125:2:125:2 | s |
|
||||
| clearning.cpp:125:4:125:6 | val |
|
||||
| clearning.cpp:126:7:126:7 | s |
|
||||
| clearning.cpp:126:9:126:11 | val |
|
||||
| clearning.cpp:131:2:131:2 | s |
|
||||
| clearning.cpp:131:4:131:6 | val |
|
||||
| clearning.cpp:132:2:132:2 | s |
|
||||
| clearning.cpp:132:4:132:6 | val |
|
||||
| clearning.cpp:133:7:133:7 | s |
|
||||
| clearning.cpp:133:9:133:11 | val |
|
||||
| clearning.cpp:138:2:138:2 | s |
|
||||
| clearning.cpp:138:4:138:6 | val |
|
||||
| clearning.cpp:139:4:139:4 | s |
|
||||
| clearning.cpp:139:6:139:8 | val |
|
||||
| clearning.cpp:140:7:140:7 | s |
|
||||
| clearning.cpp:140:9:140:11 | val |
|
||||
| clearning.cpp:151:3:151:3 | s |
|
||||
| clearning.cpp:151:5:151:7 | val |
|
||||
| clearning.cpp:157:3:157:3 | s |
|
||||
| clearning.cpp:157:5:157:7 | val |
|
||||
| clearning.cpp:158:3:158:3 | s |
|
||||
| clearning.cpp:158:5:158:7 | val |
|
||||
| clearning.cpp:164:3:164:3 | s |
|
||||
| clearning.cpp:164:5:164:7 | val |
|
||||
| clearning.cpp:165:3:165:3 | s |
|
||||
| clearning.cpp:165:5:165:7 | val |
|
||||
| clearning.cpp:171:3:171:3 | s |
|
||||
| clearning.cpp:171:5:171:7 | val |
|
||||
| clearning.cpp:172:3:172:3 | s |
|
||||
| clearning.cpp:172:5:172:7 | val |
|
||||
| clearning.cpp:178:3:178:3 | s |
|
||||
| clearning.cpp:178:5:178:7 | val |
|
||||
| clearning.cpp:179:3:179:3 | s |
|
||||
| clearning.cpp:179:5:179:7 | val |
|
||||
| complex.cpp:11:22:11:23 | a_ |
|
||||
| complex.cpp:11:22:11:23 | this |
|
||||
| complex.cpp:12:22:12:23 | b_ |
|
||||
|
||||
@@ -9,7 +9,9 @@ edges
|
||||
| A.cpp:31:14:31:21 | call to B [c] | A.cpp:31:14:31:21 | new [c] |
|
||||
| A.cpp:31:20:31:20 | c | A.cpp:23:10:23:10 | c |
|
||||
| A.cpp:31:20:31:20 | c | A.cpp:31:14:31:21 | call to B [c] |
|
||||
| A.cpp:41:15:41:21 | new | A.cpp:43:10:43:12 | & ... |
|
||||
| A.cpp:41:5:41:6 | ref arg ct | A.cpp:43:11:43:12 | ct |
|
||||
| A.cpp:41:15:41:21 | new | A.cpp:41:5:41:6 | ref arg ct |
|
||||
| A.cpp:43:11:43:12 | ct | A.cpp:43:10:43:12 | & ... |
|
||||
| A.cpp:47:12:47:18 | new | A.cpp:48:20:48:20 | c |
|
||||
| A.cpp:48:12:48:18 | call to make [c] | A.cpp:49:10:49:10 | b [c] |
|
||||
| A.cpp:48:20:48:20 | c | A.cpp:29:23:29:23 | c |
|
||||
@@ -207,11 +209,12 @@ edges
|
||||
| E.cpp:28:21:28:23 | ref arg raw | E.cpp:31:10:31:12 | raw |
|
||||
| E.cpp:29:21:29:21 | b [post update] [buffer] | E.cpp:32:10:32:10 | b [buffer] |
|
||||
| E.cpp:29:24:29:29 | ref arg buffer | E.cpp:29:21:29:21 | b [post update] [buffer] |
|
||||
| E.cpp:30:21:30:21 | p [post update] [data, buffer] | E.cpp:33:18:33:19 | & ... [data, buffer] |
|
||||
| E.cpp:30:21:30:21 | p [post update] [data, buffer] | E.cpp:33:19:33:19 | p [data, buffer] |
|
||||
| E.cpp:30:23:30:26 | data [post update] [buffer] | E.cpp:30:21:30:21 | p [post update] [data, buffer] |
|
||||
| E.cpp:30:28:30:33 | ref arg buffer | E.cpp:30:23:30:26 | data [post update] [buffer] |
|
||||
| E.cpp:32:10:32:10 | b [buffer] | E.cpp:32:13:32:18 | buffer |
|
||||
| E.cpp:33:18:33:19 | & ... [data, buffer] | E.cpp:19:27:19:27 | p [data, buffer] |
|
||||
| E.cpp:33:19:33:19 | p [data, buffer] | E.cpp:33:18:33:19 | & ... [data, buffer] |
|
||||
| aliasing.cpp:8:23:8:23 | s [m1] | aliasing.cpp:25:17:25:19 | ref arg & ... [m1] |
|
||||
| aliasing.cpp:9:3:9:3 | s [post update] [m1] | aliasing.cpp:8:23:8:23 | s [m1] |
|
||||
| aliasing.cpp:9:3:9:3 | s [post update] [m1] | aliasing.cpp:25:17:25:19 | ref arg & ... [m1] |
|
||||
@@ -362,11 +365,12 @@ edges
|
||||
| by_reference.cpp:62:25:62:34 | call to user_input | by_reference.cpp:62:3:62:3 | ref arg s [a] |
|
||||
| by_reference.cpp:63:8:63:8 | s [a] | by_reference.cpp:43:9:43:27 | this [a] |
|
||||
| by_reference.cpp:63:8:63:8 | s [a] | by_reference.cpp:63:10:63:28 | call to getThroughNonMember |
|
||||
| by_reference.cpp:68:17:68:18 | ref arg & ... [a] | by_reference.cpp:69:22:69:23 | & ... [a] |
|
||||
| by_reference.cpp:68:17:68:18 | ref arg & ... [a] | by_reference.cpp:69:23:69:23 | s [a] |
|
||||
| by_reference.cpp:68:21:68:30 | call to user_input | by_reference.cpp:11:48:11:52 | value |
|
||||
| by_reference.cpp:68:21:68:30 | call to user_input | by_reference.cpp:68:17:68:18 | ref arg & ... [a] |
|
||||
| by_reference.cpp:69:22:69:23 | & ... [a] | by_reference.cpp:31:46:31:46 | s [a] |
|
||||
| by_reference.cpp:69:22:69:23 | & ... [a] | by_reference.cpp:69:8:69:20 | call to nonMemberGetA |
|
||||
| by_reference.cpp:69:23:69:23 | s [a] | by_reference.cpp:69:22:69:23 | & ... [a] |
|
||||
| by_reference.cpp:83:31:83:35 | inner [a] | by_reference.cpp:102:21:102:39 | ref arg & ... [a] |
|
||||
| by_reference.cpp:83:31:83:35 | inner [a] | by_reference.cpp:103:27:103:35 | ref arg inner_ptr [a] |
|
||||
| by_reference.cpp:83:31:83:35 | inner [a] | by_reference.cpp:106:21:106:41 | ref arg & ... [a] |
|
||||
@@ -448,6 +452,42 @@ edges
|
||||
| by_reference.cpp:135:8:135:13 | pouter [inner_ptr, a] | by_reference.cpp:135:16:135:24 | inner_ptr [a] |
|
||||
| by_reference.cpp:135:16:135:24 | inner_ptr [a] | by_reference.cpp:135:27:135:27 | a |
|
||||
| by_reference.cpp:136:8:136:13 | pouter [a] | by_reference.cpp:136:16:136:16 | a |
|
||||
| clearning.cpp:53:4:53:4 | s [post update] [x] | clearning.cpp:55:8:55:8 | s [x] |
|
||||
| clearning.cpp:53:6:53:6 | x [inner post update] | clearning.cpp:53:4:53:4 | s [post update] [x] |
|
||||
| clearning.cpp:53:10:53:19 | call to user_input | clearning.cpp:53:6:53:6 | x [inner post update] |
|
||||
| clearning.cpp:55:8:55:8 | s [x] | clearning.cpp:55:10:55:10 | x |
|
||||
| clearning.cpp:124:2:124:2 | s [post update] [val] | clearning.cpp:126:7:126:7 | s [val] |
|
||||
| clearning.cpp:124:2:124:25 | ... = ... | clearning.cpp:124:2:124:2 | s [post update] [val] |
|
||||
| clearning.cpp:124:10:124:19 | call to user_input | clearning.cpp:124:2:124:25 | ... = ... |
|
||||
| clearning.cpp:126:7:126:7 | s [val] | clearning.cpp:126:9:126:11 | val |
|
||||
| clearning.cpp:131:2:131:2 | s [post update] [val] | clearning.cpp:133:7:133:7 | s [val] |
|
||||
| clearning.cpp:131:2:131:25 | ... = ... | clearning.cpp:131:2:131:2 | s [post update] [val] |
|
||||
| clearning.cpp:131:10:131:19 | call to user_input | clearning.cpp:131:2:131:25 | ... = ... |
|
||||
| clearning.cpp:133:7:133:7 | s [val] | clearning.cpp:133:9:133:11 | val |
|
||||
| clearning.cpp:138:2:138:2 | s [post update] [val] | clearning.cpp:140:7:140:7 | s [val] |
|
||||
| clearning.cpp:138:2:138:25 | ... = ... | clearning.cpp:138:2:138:2 | s [post update] [val] |
|
||||
| clearning.cpp:138:10:138:19 | call to user_input | clearning.cpp:138:2:138:25 | ... = ... |
|
||||
| clearning.cpp:140:7:140:7 | s [val] | clearning.cpp:140:9:140:11 | val |
|
||||
| clearning.cpp:151:3:151:3 | s [post update] [val] | clearning.cpp:152:8:152:8 | s [val] |
|
||||
| clearning.cpp:151:3:151:22 | ... = ... | clearning.cpp:151:3:151:3 | s [post update] [val] |
|
||||
| clearning.cpp:151:11:151:20 | call to user_input | clearning.cpp:151:3:151:22 | ... = ... |
|
||||
| clearning.cpp:152:8:152:8 | s [val] | clearning.cpp:152:10:152:12 | val |
|
||||
| clearning.cpp:157:3:157:3 | s [post update] [val] | clearning.cpp:159:8:159:8 | s [val] |
|
||||
| clearning.cpp:157:3:157:22 | ... = ... | clearning.cpp:157:3:157:3 | s [post update] [val] |
|
||||
| clearning.cpp:157:11:157:20 | call to user_input | clearning.cpp:157:3:157:22 | ... = ... |
|
||||
| clearning.cpp:159:8:159:8 | s [val] | clearning.cpp:159:10:159:12 | val |
|
||||
| clearning.cpp:164:3:164:3 | s [post update] [val] | clearning.cpp:166:8:166:8 | s [val] |
|
||||
| clearning.cpp:164:3:164:22 | ... = ... | clearning.cpp:164:3:164:3 | s [post update] [val] |
|
||||
| clearning.cpp:164:11:164:20 | call to user_input | clearning.cpp:164:3:164:22 | ... = ... |
|
||||
| clearning.cpp:166:8:166:8 | s [val] | clearning.cpp:166:10:166:12 | val |
|
||||
| clearning.cpp:171:3:171:3 | s [post update] [val] | clearning.cpp:173:8:173:8 | s [val] |
|
||||
| clearning.cpp:171:3:171:22 | ... = ... | clearning.cpp:171:3:171:3 | s [post update] [val] |
|
||||
| clearning.cpp:171:11:171:20 | call to user_input | clearning.cpp:171:3:171:22 | ... = ... |
|
||||
| clearning.cpp:173:8:173:8 | s [val] | clearning.cpp:173:10:173:12 | val |
|
||||
| clearning.cpp:178:3:178:3 | s [post update] [val] | clearning.cpp:180:8:180:8 | s [val] |
|
||||
| clearning.cpp:178:3:178:22 | ... = ... | clearning.cpp:178:3:178:3 | s [post update] [val] |
|
||||
| clearning.cpp:178:11:178:20 | call to user_input | clearning.cpp:178:3:178:22 | ... = ... |
|
||||
| clearning.cpp:180:8:180:8 | s [val] | clearning.cpp:180:10:180:12 | val |
|
||||
| complex.cpp:9:7:9:7 | this [a_] | complex.cpp:9:20:9:21 | this [a_] |
|
||||
| complex.cpp:9:20:9:21 | this [a_] | complex.cpp:9:20:9:21 | a_ |
|
||||
| complex.cpp:10:7:10:7 | this [b_] | complex.cpp:10:20:10:21 | this [b_] |
|
||||
@@ -665,25 +705,27 @@ edges
|
||||
| struct_init.c:15:12:15:12 | a | struct_init.c:15:12:15:12 | ref arg a |
|
||||
| struct_init.c:15:12:15:12 | ref arg a | struct_init.c:15:8:15:9 | ab [post update] [a] |
|
||||
| struct_init.c:20:17:20:36 | {...} [a] | struct_init.c:22:8:22:9 | ab [a] |
|
||||
| struct_init.c:20:17:20:36 | {...} [a] | struct_init.c:24:10:24:12 | & ... [a] |
|
||||
| struct_init.c:20:17:20:36 | {...} [a] | struct_init.c:28:5:28:7 | & ... [a] |
|
||||
| struct_init.c:20:17:20:36 | {...} [a] | struct_init.c:24:11:24:12 | ab [a] |
|
||||
| struct_init.c:20:17:20:36 | {...} [a] | struct_init.c:28:6:28:7 | ab [a] |
|
||||
| struct_init.c:20:20:20:29 | call to user_input | struct_init.c:20:17:20:36 | {...} [a] |
|
||||
| struct_init.c:22:8:22:9 | ab [a] | struct_init.c:22:11:22:11 | a |
|
||||
| struct_init.c:22:8:22:9 | ab [a] | struct_init.c:22:11:22:11 | a |
|
||||
| struct_init.c:22:8:22:9 | ab [post update] [a] | struct_init.c:24:10:24:12 | & ... [a] |
|
||||
| struct_init.c:22:8:22:9 | ab [post update] [a] | struct_init.c:28:5:28:7 | & ... [a] |
|
||||
| struct_init.c:22:8:22:9 | ab [post update] [a] | struct_init.c:24:11:24:12 | ab [a] |
|
||||
| struct_init.c:22:8:22:9 | ab [post update] [a] | struct_init.c:28:6:28:7 | ab [a] |
|
||||
| struct_init.c:22:11:22:11 | a | realistic.cpp:41:17:41:17 | o |
|
||||
| struct_init.c:22:11:22:11 | a | struct_init.c:22:11:22:11 | ref arg a |
|
||||
| struct_init.c:22:11:22:11 | ref arg a | struct_init.c:22:8:22:9 | ab [post update] [a] |
|
||||
| struct_init.c:24:10:24:12 | & ... [a] | struct_init.c:14:24:14:25 | ab [a] |
|
||||
| struct_init.c:24:10:24:12 | & ... [a] | struct_init.c:24:10:24:12 | ref arg & ... [a] |
|
||||
| struct_init.c:24:10:24:12 | ref arg & ... [a] | struct_init.c:28:5:28:7 | & ... [a] |
|
||||
| struct_init.c:24:10:24:12 | ref arg & ... [a] | struct_init.c:28:6:28:7 | ab [a] |
|
||||
| struct_init.c:24:11:24:12 | ab [a] | struct_init.c:24:10:24:12 | & ... [a] |
|
||||
| struct_init.c:26:23:29:3 | {...} [nestedAB, a] | struct_init.c:31:8:31:12 | outer [nestedAB, a] |
|
||||
| struct_init.c:26:23:29:3 | {...} [nestedAB, a] | struct_init.c:36:11:36:15 | outer [nestedAB, a] |
|
||||
| struct_init.c:26:23:29:3 | {...} [pointerAB, a] | struct_init.c:33:8:33:12 | outer [pointerAB, a] |
|
||||
| struct_init.c:27:5:27:23 | {...} [a] | struct_init.c:26:23:29:3 | {...} [nestedAB, a] |
|
||||
| struct_init.c:27:7:27:16 | call to user_input | struct_init.c:27:5:27:23 | {...} [a] |
|
||||
| struct_init.c:28:5:28:7 | & ... [a] | struct_init.c:26:23:29:3 | {...} [pointerAB, a] |
|
||||
| struct_init.c:28:6:28:7 | ab [a] | struct_init.c:28:5:28:7 | & ... [a] |
|
||||
| struct_init.c:31:8:31:12 | outer [nestedAB, a] | struct_init.c:31:14:31:21 | nestedAB [a] |
|
||||
| struct_init.c:31:8:31:12 | outer [post update] [nestedAB, a] | struct_init.c:36:11:36:15 | outer [nestedAB, a] |
|
||||
| struct_init.c:31:14:31:21 | nestedAB [a] | struct_init.c:31:23:31:23 | a |
|
||||
@@ -697,10 +739,11 @@ edges
|
||||
| struct_init.c:36:10:36:24 | & ... [a] | struct_init.c:14:24:14:25 | ab [a] |
|
||||
| struct_init.c:36:11:36:15 | outer [nestedAB, a] | struct_init.c:36:17:36:24 | nestedAB [a] |
|
||||
| struct_init.c:36:17:36:24 | nestedAB [a] | struct_init.c:36:10:36:24 | & ... [a] |
|
||||
| struct_init.c:40:17:40:36 | {...} [a] | struct_init.c:43:5:43:7 | & ... [a] |
|
||||
| struct_init.c:40:17:40:36 | {...} [a] | struct_init.c:43:6:43:7 | ab [a] |
|
||||
| struct_init.c:40:20:40:29 | call to user_input | struct_init.c:40:17:40:36 | {...} [a] |
|
||||
| struct_init.c:41:23:44:3 | {...} [pointerAB, a] | struct_init.c:46:10:46:14 | outer [pointerAB, a] |
|
||||
| struct_init.c:43:5:43:7 | & ... [a] | struct_init.c:41:23:44:3 | {...} [pointerAB, a] |
|
||||
| struct_init.c:43:6:43:7 | ab [a] | struct_init.c:43:5:43:7 | & ... [a] |
|
||||
| struct_init.c:46:10:46:14 | outer [pointerAB, a] | struct_init.c:46:16:46:24 | pointerAB [a] |
|
||||
| struct_init.c:46:16:46:24 | pointerAB [a] | struct_init.c:14:24:14:25 | ab [a] |
|
||||
nodes
|
||||
@@ -717,8 +760,10 @@ nodes
|
||||
| A.cpp:31:14:31:21 | call to B [c] | semmle.label | call to B [c] |
|
||||
| A.cpp:31:14:31:21 | new [c] | semmle.label | new [c] |
|
||||
| A.cpp:31:20:31:20 | c | semmle.label | c |
|
||||
| A.cpp:41:5:41:6 | ref arg ct | semmle.label | ref arg ct |
|
||||
| A.cpp:41:15:41:21 | new | semmle.label | new |
|
||||
| A.cpp:43:10:43:12 | & ... | semmle.label | & ... |
|
||||
| A.cpp:43:11:43:12 | ct | semmle.label | ct |
|
||||
| A.cpp:47:12:47:18 | new | semmle.label | new |
|
||||
| A.cpp:48:12:48:18 | call to make [c] | semmle.label | call to make [c] |
|
||||
| A.cpp:48:20:48:20 | c | semmle.label | c |
|
||||
@@ -927,6 +972,7 @@ nodes
|
||||
| E.cpp:32:10:32:10 | b [buffer] | semmle.label | b [buffer] |
|
||||
| E.cpp:32:13:32:18 | buffer | semmle.label | buffer |
|
||||
| E.cpp:33:18:33:19 | & ... [data, buffer] | semmle.label | & ... [data, buffer] |
|
||||
| E.cpp:33:19:33:19 | p [data, buffer] | semmle.label | p [data, buffer] |
|
||||
| aliasing.cpp:8:23:8:23 | s [m1] | semmle.label | s [m1] |
|
||||
| aliasing.cpp:9:3:9:3 | s [post update] [m1] | semmle.label | s [post update] [m1] |
|
||||
| aliasing.cpp:9:3:9:22 | ... = ... | semmle.label | ... = ... |
|
||||
@@ -1080,6 +1126,7 @@ nodes
|
||||
| by_reference.cpp:68:21:68:30 | call to user_input | semmle.label | call to user_input |
|
||||
| by_reference.cpp:69:8:69:20 | call to nonMemberGetA | semmle.label | call to nonMemberGetA |
|
||||
| by_reference.cpp:69:22:69:23 | & ... [a] | semmle.label | & ... [a] |
|
||||
| by_reference.cpp:69:23:69:23 | s [a] | semmle.label | s [a] |
|
||||
| by_reference.cpp:83:31:83:35 | inner [a] | semmle.label | inner [a] |
|
||||
| by_reference.cpp:84:3:84:7 | inner [post update] [a] | semmle.label | inner [post update] [a] |
|
||||
| by_reference.cpp:84:3:84:25 | ... = ... | semmle.label | ... = ... |
|
||||
@@ -1155,6 +1202,51 @@ nodes
|
||||
| by_reference.cpp:135:27:135:27 | a | semmle.label | a |
|
||||
| by_reference.cpp:136:8:136:13 | pouter [a] | semmle.label | pouter [a] |
|
||||
| by_reference.cpp:136:16:136:16 | a | semmle.label | a |
|
||||
| clearning.cpp:53:4:53:4 | s [post update] [x] | semmle.label | s [post update] [x] |
|
||||
| clearning.cpp:53:6:53:6 | x [inner post update] | semmle.label | x [inner post update] |
|
||||
| clearning.cpp:53:10:53:19 | call to user_input | semmle.label | call to user_input |
|
||||
| clearning.cpp:55:8:55:8 | s [x] | semmle.label | s [x] |
|
||||
| clearning.cpp:55:10:55:10 | x | semmle.label | x |
|
||||
| clearning.cpp:124:2:124:2 | s [post update] [val] | semmle.label | s [post update] [val] |
|
||||
| clearning.cpp:124:2:124:25 | ... = ... | semmle.label | ... = ... |
|
||||
| clearning.cpp:124:10:124:19 | call to user_input | semmle.label | call to user_input |
|
||||
| clearning.cpp:126:7:126:7 | s [val] | semmle.label | s [val] |
|
||||
| clearning.cpp:126:9:126:11 | val | semmle.label | val |
|
||||
| clearning.cpp:131:2:131:2 | s [post update] [val] | semmle.label | s [post update] [val] |
|
||||
| clearning.cpp:131:2:131:25 | ... = ... | semmle.label | ... = ... |
|
||||
| clearning.cpp:131:10:131:19 | call to user_input | semmle.label | call to user_input |
|
||||
| clearning.cpp:133:7:133:7 | s [val] | semmle.label | s [val] |
|
||||
| clearning.cpp:133:9:133:11 | val | semmle.label | val |
|
||||
| clearning.cpp:138:2:138:2 | s [post update] [val] | semmle.label | s [post update] [val] |
|
||||
| clearning.cpp:138:2:138:25 | ... = ... | semmle.label | ... = ... |
|
||||
| clearning.cpp:138:10:138:19 | call to user_input | semmle.label | call to user_input |
|
||||
| clearning.cpp:140:7:140:7 | s [val] | semmle.label | s [val] |
|
||||
| clearning.cpp:140:9:140:11 | val | semmle.label | val |
|
||||
| clearning.cpp:151:3:151:3 | s [post update] [val] | semmle.label | s [post update] [val] |
|
||||
| clearning.cpp:151:3:151:22 | ... = ... | semmle.label | ... = ... |
|
||||
| clearning.cpp:151:11:151:20 | call to user_input | semmle.label | call to user_input |
|
||||
| clearning.cpp:152:8:152:8 | s [val] | semmle.label | s [val] |
|
||||
| clearning.cpp:152:10:152:12 | val | semmle.label | val |
|
||||
| clearning.cpp:157:3:157:3 | s [post update] [val] | semmle.label | s [post update] [val] |
|
||||
| clearning.cpp:157:3:157:22 | ... = ... | semmle.label | ... = ... |
|
||||
| clearning.cpp:157:11:157:20 | call to user_input | semmle.label | call to user_input |
|
||||
| clearning.cpp:159:8:159:8 | s [val] | semmle.label | s [val] |
|
||||
| clearning.cpp:159:10:159:12 | val | semmle.label | val |
|
||||
| clearning.cpp:164:3:164:3 | s [post update] [val] | semmle.label | s [post update] [val] |
|
||||
| clearning.cpp:164:3:164:22 | ... = ... | semmle.label | ... = ... |
|
||||
| clearning.cpp:164:11:164:20 | call to user_input | semmle.label | call to user_input |
|
||||
| clearning.cpp:166:8:166:8 | s [val] | semmle.label | s [val] |
|
||||
| clearning.cpp:166:10:166:12 | val | semmle.label | val |
|
||||
| clearning.cpp:171:3:171:3 | s [post update] [val] | semmle.label | s [post update] [val] |
|
||||
| clearning.cpp:171:3:171:22 | ... = ... | semmle.label | ... = ... |
|
||||
| clearning.cpp:171:11:171:20 | call to user_input | semmle.label | call to user_input |
|
||||
| clearning.cpp:173:8:173:8 | s [val] | semmle.label | s [val] |
|
||||
| clearning.cpp:173:10:173:12 | val | semmle.label | val |
|
||||
| clearning.cpp:178:3:178:3 | s [post update] [val] | semmle.label | s [post update] [val] |
|
||||
| clearning.cpp:178:3:178:22 | ... = ... | semmle.label | ... = ... |
|
||||
| clearning.cpp:178:11:178:20 | call to user_input | semmle.label | call to user_input |
|
||||
| clearning.cpp:180:8:180:8 | s [val] | semmle.label | s [val] |
|
||||
| clearning.cpp:180:10:180:12 | val | semmle.label | val |
|
||||
| complex.cpp:9:7:9:7 | this [a_] | semmle.label | this [a_] |
|
||||
| complex.cpp:9:20:9:21 | a_ | semmle.label | a_ |
|
||||
| complex.cpp:9:20:9:21 | this [a_] | semmle.label | this [a_] |
|
||||
@@ -1393,11 +1485,13 @@ nodes
|
||||
| struct_init.c:22:11:22:11 | ref arg a | semmle.label | ref arg a |
|
||||
| struct_init.c:24:10:24:12 | & ... [a] | semmle.label | & ... [a] |
|
||||
| struct_init.c:24:10:24:12 | ref arg & ... [a] | semmle.label | ref arg & ... [a] |
|
||||
| struct_init.c:24:11:24:12 | ab [a] | semmle.label | ab [a] |
|
||||
| struct_init.c:26:23:29:3 | {...} [nestedAB, a] | semmle.label | {...} [nestedAB, a] |
|
||||
| struct_init.c:26:23:29:3 | {...} [pointerAB, a] | semmle.label | {...} [pointerAB, a] |
|
||||
| struct_init.c:27:5:27:23 | {...} [a] | semmle.label | {...} [a] |
|
||||
| struct_init.c:27:7:27:16 | call to user_input | semmle.label | call to user_input |
|
||||
| struct_init.c:28:5:28:7 | & ... [a] | semmle.label | & ... [a] |
|
||||
| struct_init.c:28:6:28:7 | ab [a] | semmle.label | ab [a] |
|
||||
| struct_init.c:31:8:31:12 | outer [nestedAB, a] | semmle.label | outer [nestedAB, a] |
|
||||
| struct_init.c:31:8:31:12 | outer [post update] [nestedAB, a] | semmle.label | outer [post update] [nestedAB, a] |
|
||||
| struct_init.c:31:14:31:21 | nestedAB [a] | semmle.label | nestedAB [a] |
|
||||
@@ -1415,6 +1509,7 @@ nodes
|
||||
| struct_init.c:40:20:40:29 | call to user_input | semmle.label | call to user_input |
|
||||
| struct_init.c:41:23:44:3 | {...} [pointerAB, a] | semmle.label | {...} [pointerAB, a] |
|
||||
| struct_init.c:43:5:43:7 | & ... [a] | semmle.label | & ... [a] |
|
||||
| struct_init.c:43:6:43:7 | ab [a] | semmle.label | ab [a] |
|
||||
| struct_init.c:46:10:46:14 | outer [pointerAB, a] | semmle.label | outer [pointerAB, a] |
|
||||
| struct_init.c:46:16:46:24 | pointerAB [a] | semmle.label | pointerAB [a] |
|
||||
subpaths
|
||||
@@ -1551,6 +1646,15 @@ subpaths
|
||||
| by_reference.cpp:134:29:134:29 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:134:29:134:29 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input |
|
||||
| by_reference.cpp:135:27:135:27 | a | by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:135:27:135:27 | a | a flows from $@ | by_reference.cpp:88:13:88:22 | call to user_input | call to user_input |
|
||||
| by_reference.cpp:136:16:136:16 | a | by_reference.cpp:96:8:96:17 | call to user_input | by_reference.cpp:136:16:136:16 | a | a flows from $@ | by_reference.cpp:96:8:96:17 | call to user_input | call to user_input |
|
||||
| clearning.cpp:55:10:55:10 | x | clearning.cpp:53:10:53:19 | call to user_input | clearning.cpp:55:10:55:10 | x | x flows from $@ | clearning.cpp:53:10:53:19 | call to user_input | call to user_input |
|
||||
| clearning.cpp:126:9:126:11 | val | clearning.cpp:124:10:124:19 | call to user_input | clearning.cpp:126:9:126:11 | val | val flows from $@ | clearning.cpp:124:10:124:19 | call to user_input | call to user_input |
|
||||
| clearning.cpp:133:9:133:11 | val | clearning.cpp:131:10:131:19 | call to user_input | clearning.cpp:133:9:133:11 | val | val flows from $@ | clearning.cpp:131:10:131:19 | call to user_input | call to user_input |
|
||||
| clearning.cpp:140:9:140:11 | val | clearning.cpp:138:10:138:19 | call to user_input | clearning.cpp:140:9:140:11 | val | val flows from $@ | clearning.cpp:138:10:138:19 | call to user_input | call to user_input |
|
||||
| clearning.cpp:152:10:152:12 | val | clearning.cpp:151:11:151:20 | call to user_input | clearning.cpp:152:10:152:12 | val | val flows from $@ | clearning.cpp:151:11:151:20 | call to user_input | call to user_input |
|
||||
| clearning.cpp:159:10:159:12 | val | clearning.cpp:157:11:157:20 | call to user_input | clearning.cpp:159:10:159:12 | val | val flows from $@ | clearning.cpp:157:11:157:20 | call to user_input | call to user_input |
|
||||
| clearning.cpp:166:10:166:12 | val | clearning.cpp:164:11:164:20 | call to user_input | clearning.cpp:166:10:166:12 | val | val flows from $@ | clearning.cpp:164:11:164:20 | call to user_input | call to user_input |
|
||||
| clearning.cpp:173:10:173:12 | val | clearning.cpp:171:11:171:20 | call to user_input | clearning.cpp:173:10:173:12 | val | val flows from $@ | clearning.cpp:171:11:171:20 | call to user_input | call to user_input |
|
||||
| clearning.cpp:180:10:180:12 | val | clearning.cpp:178:11:178:20 | call to user_input | clearning.cpp:180:10:180:12 | val | val flows from $@ | clearning.cpp:178:11:178:20 | call to user_input | call to user_input |
|
||||
| complex.cpp:42:18:42:18 | call to a | complex.cpp:53:19:53:28 | call to user_input | complex.cpp:42:18:42:18 | call to a | call to a flows from $@ | complex.cpp:53:19:53:28 | call to user_input | call to user_input |
|
||||
| complex.cpp:42:18:42:18 | call to a | complex.cpp:55:19:55:28 | call to user_input | complex.cpp:42:18:42:18 | call to a | call to a flows from $@ | complex.cpp:55:19:55:28 | call to user_input | call to user_input |
|
||||
| complex.cpp:43:18:43:18 | call to b | complex.cpp:54:19:54:28 | call to user_input | complex.cpp:43:18:43:18 | call to b | call to b flows from $@ | complex.cpp:54:19:54:28 | call to user_input | call to user_input |
|
||||
|
||||
@@ -1,2 +1,6 @@
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (taint.ql:6,48-56)
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (taint.ql:7,24-32)
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (taint.ql:11,22-30)
|
||||
WARNING: Module TaintTracking has been deprecated and may be removed in future (taint.ql:19,20-33)
|
||||
failures
|
||||
testFailures
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (localTaint.ql:4,6-14)
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (localTaint.ql:4,31-39)
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (localTaint.ql:7,6-14)
|
||||
WARNING: Module TaintTracking has been deprecated and may be removed in future (localTaint.ql:6,3-16)
|
||||
| arrayassignment.cpp:9:9:9:10 | 0 | arrayassignment.cpp:10:14:10:14 | x | |
|
||||
| arrayassignment.cpp:9:9:9:10 | 0 | arrayassignment.cpp:11:15:11:15 | x | |
|
||||
| arrayassignment.cpp:9:9:9:10 | 0 | arrayassignment.cpp:12:13:12:13 | x | |
|
||||
|
||||
@@ -1,2 +1,7 @@
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (taint.ql:46,45-53)
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (taint.ql:47,24-32)
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (taint.ql:61,22-30)
|
||||
WARNING: Module DataFlow has been deprecated and may be removed in future (taint.ql:68,25-33)
|
||||
WARNING: Module TaintTracking has been deprecated and may be removed in future (taint.ql:73,20-33)
|
||||
failures
|
||||
testFailures
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user