Merge tag 'codeql-cli/latest'

Compatible with the latest released version of the CodeQL CLI
This commit is contained in:
Dilan
2023-07-28 12:01:37 +00:00
680 changed files with 18936 additions and 4857 deletions

View File

@@ -1,3 +1,23 @@
## 0.8.1
### Deprecated APIs
* The library `semmle.code.cpp.dataflow.DataFlow` has been deprecated. Please use `semmle.code.cpp.dataflow.new.DataFlow` instead.
### New Features
* 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.
### Minor Analysis Improvements
* 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.
* The `IRGuards` library has improved handling of pointer addition and subtraction operations.
## 0.8.0
### New Features

View File

@@ -0,0 +1,19 @@
## 0.8.1
### Deprecated APIs
* The library `semmle.code.cpp.dataflow.DataFlow` has been deprecated. Please use `semmle.code.cpp.dataflow.new.DataFlow` instead.
### New Features
* 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.
### Minor Analysis Improvements
* 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.
* The `IRGuards` library has improved handling of pointer addition and subtraction operations.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.8.0
lastReleaseVersion: 0.8.1

View File

@@ -1,5 +1,5 @@
name: codeql/cpp-all
version: 0.8.0
version: 0.8.1
groups: cpp
dbscheme: semmlecode.cpp.dbscheme
extractor: cpp

View File

@@ -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() + ")"

View File

@@ -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. */

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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
}

View File

@@ -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

View File

@@ -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`.
*/
@@ -2019,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())
}
}
@@ -2108,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
(
@@ -2123,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
@@ -2160,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)
}
}
@@ -2703,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
@@ -2755,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 |
@@ -3089,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() }
@@ -3097,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()
}
/**

View File

@@ -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() }

View File

@@ -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() }

View File

@@ -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() }

View File

@@ -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() }

View File

@@ -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() }

View File

@@ -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())

View File

@@ -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

View File

@@ -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`.
*/
@@ -2019,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())
}
}
@@ -2108,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
(
@@ -2123,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
@@ -2160,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)
}
}
@@ -2703,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
@@ -2755,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 |
@@ -3089,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() }
@@ -3097,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()
}
/**

View File

@@ -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() }

View File

@@ -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() }

View File

@@ -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() }

View File

@@ -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() }

View File

@@ -448,6 +448,8 @@ module TaintedWithPath {
}
predicate isBarrierIn(DataFlow::Node node) { nodeIsBarrierIn(node) }
predicate neverSkip(Node node) { none() }
}
private module AdjustedFlow = TaintTracking::Global<AdjustedConfig>;

View File

@@ -297,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;

View File

@@ -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())
}
}
/**

View File

@@ -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 |

View File

@@ -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)
)
}

View File

@@ -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
)
}

View File

@@ -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;

View File

@@ -1,3 +1,9 @@
## 0.7.1
### Minor Analysis Improvements
* 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.
## 0.7.0
### Minor Analysis Improvements

View File

@@ -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>

View File

@@ -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()
}
}
/**

View File

@@ -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())

View File

@@ -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
}

View File

@@ -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
) {

View File

@@ -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>;

View File

@@ -0,0 +1,5 @@
## 0.7.1
### Minor Analysis Improvements
* 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.

View File

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

View File

@@ -168,8 +168,6 @@ module ArrayAddressToDerefConfig 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, _) }

View File

@@ -16,561 +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.ir.ValueNumbering
import semmle.code.cpp.controlflow.IRGuards
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
)
}
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 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 = AllocToInvalidPointerConfig::FlowState2;
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, _)
module FinalConfig implements DataFlow::StateConfigSig {
newtype FlowState =
additional TInitial() or
additional TPointerArith(PointerArithmeticInstruction pai) {
operationIsOffBy(_, pai, _, _, _, _, _)
}
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, _, _, _) }
predicate isSource(DataFlow::Node source, FlowState state) {
state = TInitial() and
operationIsOffBy(source, _, _, _, _, _, _)
}
private import DataFlow::Global<BarrierConfig2>
private FlowState2 getAFlowStateForNode(DataFlow::Node node) {
exists(DataFlow::Node source |
flow(source, node) and
hasSize(_, source, result)
predicate isSink(DataFlow::Node sink, FlowState state) {
exists(PointerArithmeticInstruction pai |
operationIsOffBy(_, pai, _, _, _, sink, _) and
state = TPointerArith(pai)
)
}
private predicate operandGuardChecks(
IRGuardCondition g, Operand left, Operand right, FlowState2 state, boolean edge
predicate isAdditionalFlowStep(
DataFlow::Node node1, FlowState state1, DataFlow::Node node2, FlowState state2
) {
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
// 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)
)
}
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)
)
}
DataFlow::Node getABarrierNode(FlowState2 state) {
result.asOperand() = getABarrierInstruction(state).getAUse()
}
IRBlock getABarrierBlock(FlowState2 state) {
result.getAnInstruction() = getABarrierInstruction(state)
}
}
/**
* 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 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`.
isSinkImpl(_, 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)
}
}
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
) {
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
bounded1(right, instr2, delta) and
not right = Barrier2::getABarrierInstruction(delta) and
not instr2 = Barrier2::getABarrierInstruction(delta)
)
}
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>
predicate isInteresting(PointerAddInstruction pai) {
exists(DataFlow::Node n |
n.asInstruction() = pai.getLeft() and
flowTo(n)
)
}
}
/**
* 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, IRBlock b |
s = sink.asInstruction() and
boundedImpl(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"
)
// 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 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 import DataFlow::Global<BarrierConfig>
private int getInvalidPointerToDerefSourceDelta(DataFlow::Node node) {
exists(DataFlow::Node source |
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) }
}
module FinalFlow = DataFlow::GlobalWithState<FinalConfig>;
/**
* 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)
or
node = InvalidPointerToDerefBarrier::getABarrierNode()
}
}
module InvalidPointerToDerefFlow = DataFlow::Global<InvalidPointerToDerefConfig>;
/**
* 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 p1, AllocToInvalidPointerFlow::PathNode2 p2,
DataFlow::Node sink1, DataFlow::Node sink2, int delta0
|
pragma[only_bind_out](p1.getNode()) = sink1 and
pragma[only_bind_out](p2.getNode()) = sink2 and
AllocToInvalidPointerFlow::flowPath(_, _, pragma[only_bind_into](p1), pragma[only_bind_into](p2)) and
// 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.
isSinkImpl(pai, sink1, sink2, delta0) and
bounded2(source.asInstruction(), pai, delta) and
delta >= 0 and
not source.getBasicBlock() = Barrier2::getABarrierBlock(delta0)
)
}
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(pragma[only_bind_into](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()

View File

@@ -1,5 +1,5 @@
name: codeql/cpp-queries
version: 0.7.0
version: 0.7.1
groups:
- cpp
- queries

View File

@@ -55,6 +55,26 @@ edges
| 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 |
@@ -131,6 +151,27 @@ nodes
| 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 |
@@ -149,3 +190,10 @@ subpaths
| 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 |

View File

@@ -288,3 +288,67 @@ void test_call_use2() {
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];
}

View File

@@ -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>

View File

@@ -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>

View File

@@ -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,16 +353,16 @@ 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;
@@ -375,18 +375,18 @@ void test26(unsigned size) {
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];
char *end = &xs[size]; // $ alloc=L388
if (xs >= end)
return;
xs++;
@@ -397,7 +397,7 @@ void test28(unsigned size) {
void test28_simple(unsigned size) {
char *xs = new char[size];
char *end = &xs[size];
char *end = &xs[size]; // $ alloc=L399
if (xs < end) {
xs++;
if (xs < end) {
@@ -408,46 +408,46 @@ void test28_simple(unsigned size) {
void test28_simple2(unsigned size) {
char *xs = new char[size];
char *end = &xs[size];
char *end = &xs[size]; // $ alloc=L410
if (xs < end) {
xs++;
if (xs < end + 1) {
xs[0] = 0; // BAD
xs[0] = 0; // $ deref=L415 // BAD
}
}
}
void test28_simple3(unsigned size) {
char *xs = new char[size];
char *end = &xs[size];
char *end = &xs[size]; // $ alloc=L421
if (xs < end) {
xs++;
if (xs - 1 < end) {
xs[0] = 0; // BAD
xs[0] = 0; // $ deref=L426 // BAD
}
}
}
void test28_simple4(unsigned size) {
char *xs = new char[size];
char *end = &xs[size];
char *end = &xs[size]; // $ alloc=L432
if (xs < end) {
end++;
xs++;
if (xs < end) {
xs[0] = 0; // BAD
xs[0] = 0; // $ deref=L438 // BAD
}
}
}
void test28_simple5(unsigned size) {
char *xs = new char[size];
char *end = &xs[size];
char *end = &xs[size]; // $ alloc=L444
end++;
if (xs < end) {
xs++;
if (xs < end) {
xs[0] = 0; // BAD
xs[0] = 0; // $ deref=L450 // BAD
}
}
}
@@ -466,7 +466,7 @@ void test28_simple6(unsigned size) {
void test28_simple7(unsigned size) {
char *xs = new char[size];
char *end = &xs[size];
char *end = &xs[size]; // $ alloc=L468
end++;
if (xs < end) {
xs++;
@@ -478,12 +478,12 @@ void test28_simple7(unsigned size) {
void test28_simple8(unsigned size) {
char *xs = new char[size];
char *end = &xs[size];
char *end = &xs[size]; // $ alloc=L480
end += 500;
if (xs < end) {
xs++;
if (xs < end - 1) {
xs[0] = 0; // BAD
xs[0] = 0; // $ deref=L486+498 // BAD
}
}
}
@@ -545,7 +545,7 @@ void test31_simple2(unsigned size, unsigned src_pos)
src_pos = size;
}
if (src_pos < size + 1) {
xs[src_pos] = 0; // BAD
xs[src_pos] = 0; // $ alloc=L543 deref=L548 // BAD
}
}
@@ -556,7 +556,7 @@ void test31_simple3(unsigned size, unsigned src_pos)
src_pos = size;
}
if (src_pos - 1 < size) {
xs[src_pos] = 0; // BAD
xs[src_pos] = 0; // $ alloc=L554 deref=L559 // BAD
}
}
@@ -644,13 +644,13 @@ void test31_simple1_sub1(unsigned size, unsigned src_pos)
src_pos = size;
}
if (src_pos < size) {
xs[src_pos] = 0; // BAD
xs[src_pos] = 0; // $ alloc=L642-1 deref=L647 // BAD
}
}
void test32(unsigned size) {
char *xs = new char[size];
char *end = &xs[size];
char *end = &xs[size]; // $ alloc=L652
if (xs >= end)
return;
xs++;
@@ -659,7 +659,7 @@ void test32(unsigned size) {
xs++;
if (xs >= end)
return;
xs[0] = 0; // GOOD [FALSE POSITIVE]
xs[0] = 0; // $ deref=L656->L662+1 deref=L657->L662+1 GOOD [FALSE POSITIVE]
}
void test33(unsigned size, unsigned src_pos)
@@ -672,6 +672,21 @@ void test33(unsigned size, unsigned src_pos)
while (dst_pos < size - 1) {
dst_pos++;
if (true)
xs[dst_pos++] = 0; // GOOD [FALSE POSITIVE]
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
}

View File

@@ -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;
}

View File

@@ -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 |

View File

@@ -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 | ... = ... |

View File

@@ -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 | ... = ... |

View File

@@ -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

View File

@@ -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 |

View File

@@ -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

View File

@@ -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

View File

@@ -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 |
@@ -1049,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 |

View File

@@ -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 |

View File

@@ -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 |

View File

@@ -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] |
@@ -701,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 |
@@ -733,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
@@ -753,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 |
@@ -963,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 | ... = ... |
@@ -1116,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 | ... = ... |
@@ -1474,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] |
@@ -1496,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

View File

@@ -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

View File

@@ -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 | |

View File

@@ -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

View File

@@ -14562,6 +14562,332 @@ ir.cpp:
# 1930| Value = [Literal] 40
# 1930| ValueCategory = prvalue
# 1931| getStmt(2): [ReturnStmt] return ...
# 1933| [TopLevelFunction] void test_assign_with_assign_operation()
# 1933| <params>:
# 1933| getEntryPoint(): [BlockStmt] { ... }
# 1934| getStmt(0): [DeclStmt] declaration
# 1934| getDeclarationEntry(0): [VariableDeclarationEntry] definition of i
# 1934| Type = [IntType] int
# 1934| getDeclarationEntry(1): [VariableDeclarationEntry] definition of j
# 1934| Type = [IntType] int
# 1934| getVariable().getInitializer(): [Initializer] initializer for j
# 1934| getExpr(): [Literal] 0
# 1934| Type = [IntType] int
# 1934| Value = [Literal] 0
# 1934| ValueCategory = prvalue
# 1935| getStmt(1): [ExprStmt] ExprStmt
# 1935| getExpr(): [AssignExpr] ... = ...
# 1935| Type = [IntType] int
# 1935| ValueCategory = lvalue
# 1935| getLValue(): [VariableAccess] i
# 1935| Type = [IntType] int
# 1935| ValueCategory = lvalue
# 1935| getRValue(): [AssignAddExpr] ... += ...
# 1935| Type = [IntType] int
# 1935| ValueCategory = prvalue
# 1935| getLValue(): [VariableAccess] j
# 1935| Type = [IntType] int
# 1935| ValueCategory = lvalue
# 1935| getRValue(): [Literal] 40
# 1935| Type = [IntType] int
# 1935| Value = [Literal] 40
# 1935| ValueCategory = prvalue
# 1935| getRValue().getFullyConverted(): [ParenthesisExpr] (...)
# 1935| Type = [IntType] int
# 1935| ValueCategory = prvalue
# 1936| getStmt(2): [ReturnStmt] return ...
# 1938| [CopyAssignmentOperator] D& D::operator=(D const&)
# 1938| <params>:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
#-----| Type = [LValueReferenceType] const D &
# 1938| [MoveAssignmentOperator] D& D::operator=(D&&)
# 1938| <params>:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
#-----| Type = [RValueReferenceType] D &&
# 1942| [MemberFunction] D& D::ReferenceStaticMemberFunction()
# 1942| <params>:
# 1942| getEntryPoint(): [BlockStmt] { ... }
# 1943| getStmt(0): [ReturnStmt] return ...
# 1943| getExpr(): [VariableAccess] x
# 1943| Type = [Class] D
# 1943| ValueCategory = lvalue
# 1943| getExpr().getFullyConverted(): [ReferenceToExpr] (reference to)
# 1943| Type = [LValueReferenceType] D &
# 1943| ValueCategory = prvalue
# 1945| [MemberFunction] D D::ObjectStaticMemberFunction()
# 1945| <params>:
# 1945| getEntryPoint(): [BlockStmt] { ... }
# 1946| getStmt(0): [ReturnStmt] return ...
# 1946| getExpr(): [VariableAccess] x
# 1946| Type = [Class] D
# 1946| ValueCategory = prvalue(load)
# 1950| [TopLevelFunction] void test_static_member_functions_with_reference_return()
# 1950| <params>:
# 1950| getEntryPoint(): [BlockStmt] { ... }
# 1951| getStmt(0): [DeclStmt] declaration
# 1951| getDeclarationEntry(0): [VariableDeclarationEntry] definition of d
# 1951| Type = [Class] D
# 1953| getStmt(1): [ExprStmt] ExprStmt
# 1953| getExpr(): [FunctionCall] call to ReferenceStaticMemberFunction
# 1953| Type = [LValueReferenceType] D &
# 1953| ValueCategory = prvalue
# 1953| getQualifier(): [VariableAccess] d
# 1953| Type = [Class] D
# 1953| ValueCategory = lvalue
# 1953| getExpr().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
# 1953| Type = [Class] D
# 1953| ValueCategory = lvalue
# 1954| getStmt(2): [ExprStmt] ExprStmt
# 1954| getExpr(): [FunctionCall] call to ReferenceStaticMemberFunction
# 1954| Type = [LValueReferenceType] D &
# 1954| ValueCategory = prvalue
# 1954| getExpr().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
# 1954| Type = [Class] D
# 1954| ValueCategory = lvalue
# 1955| getStmt(3): [ExprStmt] ExprStmt
# 1955| getExpr(): [FunctionCall] call to ObjectStaticMemberFunction
# 1955| Type = [Class] D
# 1955| ValueCategory = prvalue
# 1955| getQualifier(): [VariableAccess] d
# 1955| Type = [Class] D
# 1955| ValueCategory = lvalue
# 1956| getStmt(4): [ExprStmt] ExprStmt
# 1956| getExpr(): [FunctionCall] call to ObjectStaticMemberFunction
# 1956| Type = [Class] D
# 1956| ValueCategory = prvalue
# 1958| getStmt(5): [DeclStmt] declaration
# 1958| getDeclarationEntry(0): [VariableDeclarationEntry] definition of x
# 1958| Type = [Class] D
# 1959| getStmt(6): [ExprStmt] ExprStmt
# 1959| getExpr(): [AssignExpr] ... = ...
# 1959| Type = [Class] D
# 1959| ValueCategory = lvalue
# 1959| getLValue(): [VariableAccess] x
# 1959| Type = [Class] D
# 1959| ValueCategory = lvalue
# 1959| getRValue(): [FunctionCall] call to ReferenceStaticMemberFunction
# 1959| Type = [LValueReferenceType] D &
# 1959| ValueCategory = prvalue
# 1959| getQualifier(): [VariableAccess] d
# 1959| Type = [Class] D
# 1959| ValueCategory = lvalue
# 1959| getRValue().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
# 1959| Type = [Class] D
# 1959| ValueCategory = prvalue(load)
# 1960| getStmt(7): [DeclStmt] declaration
# 1960| getDeclarationEntry(0): [VariableDeclarationEntry] definition of y
# 1960| Type = [Class] D
# 1961| getStmt(8): [ExprStmt] ExprStmt
# 1961| getExpr(): [AssignExpr] ... = ...
# 1961| Type = [Class] D
# 1961| ValueCategory = lvalue
# 1961| getLValue(): [VariableAccess] y
# 1961| Type = [Class] D
# 1961| ValueCategory = lvalue
# 1961| getRValue(): [FunctionCall] call to ReferenceStaticMemberFunction
# 1961| Type = [LValueReferenceType] D &
# 1961| ValueCategory = prvalue
# 1961| getRValue().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
# 1961| Type = [Class] D
# 1961| ValueCategory = prvalue(load)
# 1962| getStmt(9): [DeclStmt] declaration
# 1962| getDeclarationEntry(0): [VariableDeclarationEntry] definition of j
# 1962| Type = [Class] D
# 1963| getStmt(10): [ExprStmt] ExprStmt
# 1963| getExpr(): [AssignExpr] ... = ...
# 1963| Type = [Class] D
# 1963| ValueCategory = lvalue
# 1963| getLValue(): [VariableAccess] j
# 1963| Type = [Class] D
# 1963| ValueCategory = lvalue
# 1963| getRValue(): [FunctionCall] call to ObjectStaticMemberFunction
# 1963| Type = [Class] D
# 1963| ValueCategory = prvalue
# 1963| getQualifier(): [VariableAccess] d
# 1963| Type = [Class] D
# 1963| ValueCategory = lvalue
# 1964| getStmt(11): [DeclStmt] declaration
# 1964| getDeclarationEntry(0): [VariableDeclarationEntry] definition of k
# 1964| Type = [Class] D
# 1965| getStmt(12): [ExprStmt] ExprStmt
# 1965| getExpr(): [AssignExpr] ... = ...
# 1965| Type = [Class] D
# 1965| ValueCategory = lvalue
# 1965| getLValue(): [VariableAccess] k
# 1965| Type = [Class] D
# 1965| ValueCategory = lvalue
# 1965| getRValue(): [FunctionCall] call to ObjectStaticMemberFunction
# 1965| Type = [Class] D
# 1965| ValueCategory = prvalue
# 1966| getStmt(13): [ReturnStmt] return ...
# 1968| [TopLevelFunction] void test_volatile()
# 1968| <params>:
# 1968| getEntryPoint(): [BlockStmt] { ... }
# 1969| getStmt(0): [DeclStmt] declaration
# 1969| getDeclarationEntry(0): [VariableDeclarationEntry] definition of x
# 1969| Type = [SpecifiedType] volatile int
# 1970| getStmt(1): [ExprStmt] ExprStmt
# 1970| getExpr(): [VariableAccess] x
# 1970| Type = [IntType] int
# 1970| ValueCategory = prvalue(load)
# 1971| getStmt(2): [ReturnStmt] return ...
# 1973| [CopyAssignmentOperator] ValCat& ValCat::operator=(ValCat const&)
# 1973| <params>:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
#-----| Type = [LValueReferenceType] const ValCat &
# 1973| [MoveAssignmentOperator] ValCat& ValCat::operator=(ValCat&&)
# 1973| <params>:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
#-----| Type = [RValueReferenceType] ValCat &&
# 1974| [MemberFunction] ValCat& ValCat::lvalue()
# 1974| <params>:
# 1975| [MemberFunction] ValCat&& ValCat::xvalue()
# 1975| <params>:
# 1976| [MemberFunction] ValCat ValCat::prvalue()
# 1976| <params>:
# 1979| [TopLevelFunction] void value_category_test()
# 1979| <params>:
# 1979| getEntryPoint(): [BlockStmt] { ... }
# 1980| getStmt(0): [DeclStmt] declaration
# 1980| getDeclarationEntry(0): [VariableDeclarationEntry] definition of c
# 1980| Type = [Struct] ValCat
# 1982| getStmt(1): [ExprStmt] ExprStmt
# 1982| getExpr(): [AssignExpr] ... = ...
# 1982| Type = [Struct] ValCat
# 1982| ValueCategory = lvalue
# 1982| getLValue(): [FunctionCall] call to lvalue
# 1982| Type = [LValueReferenceType] ValCat &
# 1982| ValueCategory = prvalue
# 1982| getQualifier(): [VariableAccess] c
# 1982| Type = [Struct] ValCat
# 1982| ValueCategory = lvalue
# 1982| getRValue(): [ClassAggregateLiteral] {...}
# 1982| Type = [Struct] ValCat
# 1982| ValueCategory = prvalue
# 1982| getLValue().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
# 1982| Type = [Struct] ValCat
# 1982| ValueCategory = lvalue
#-----| getRValue().getFullyConverted(): [TemporaryObjectExpr] temporary object
#-----| Type = [Struct] ValCat
#-----| ValueCategory = prvalue(load)
# 1983| getStmt(2): [ExprStmt] ExprStmt
# 1983| getExpr(): [AssignExpr] ... = ...
# 1983| Type = [Struct] ValCat
# 1983| ValueCategory = lvalue
# 1983| getLValue(): [FunctionCall] call to xvalue
# 1983| Type = [RValueReferenceType] ValCat &&
# 1983| ValueCategory = prvalue
# 1983| getQualifier(): [VariableAccess] c
# 1983| Type = [Struct] ValCat
# 1983| ValueCategory = lvalue
# 1983| getRValue(): [ClassAggregateLiteral] {...}
# 1983| Type = [Struct] ValCat
# 1983| ValueCategory = prvalue
# 1983| getLValue().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
# 1983| Type = [Struct] ValCat
# 1983| ValueCategory = lvalue
#-----| getRValue().getFullyConverted(): [TemporaryObjectExpr] temporary object
#-----| Type = [Struct] ValCat
#-----| ValueCategory = prvalue(load)
# 1984| getStmt(3): [ExprStmt] ExprStmt
# 1984| getExpr(): [AssignExpr] ... = ...
# 1984| Type = [Struct] ValCat
# 1984| ValueCategory = lvalue
# 1984| getLValue(): [FunctionCall] call to prvalue
# 1984| Type = [Struct] ValCat
# 1984| ValueCategory = prvalue
# 1984| getQualifier(): [VariableAccess] c
# 1984| Type = [Struct] ValCat
# 1984| ValueCategory = lvalue
# 1984| getRValue(): [ClassAggregateLiteral] {...}
# 1984| Type = [Struct] ValCat
# 1984| ValueCategory = prvalue
# 1984| getLValue().getFullyConverted(): [TemporaryObjectExpr] temporary object
# 1984| Type = [Struct] ValCat
# 1984| ValueCategory = lvalue
#-----| getRValue().getFullyConverted(): [TemporaryObjectExpr] temporary object
#-----| Type = [Struct] ValCat
#-----| ValueCategory = prvalue(load)
# 1985| getStmt(4): [ExprStmt] ExprStmt
# 1985| getExpr(): [AssignExpr] ... = ...
# 1985| Type = [Struct] ValCat
# 1985| ValueCategory = lvalue
# 1985| getLValue(): [FunctionCall] call to lvalue
# 1985| Type = [LValueReferenceType] ValCat &
# 1985| ValueCategory = prvalue
# 1985| getRValue(): [ClassAggregateLiteral] {...}
# 1985| Type = [Struct] ValCat
# 1985| ValueCategory = prvalue
# 1985| getLValue().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
# 1985| Type = [Struct] ValCat
# 1985| ValueCategory = lvalue
#-----| getRValue().getFullyConverted(): [TemporaryObjectExpr] temporary object
#-----| Type = [Struct] ValCat
#-----| ValueCategory = prvalue(load)
# 1986| getStmt(5): [ExprStmt] ExprStmt
# 1986| getExpr(): [AssignExpr] ... = ...
# 1986| Type = [Struct] ValCat
# 1986| ValueCategory = lvalue
# 1986| getLValue(): [FunctionCall] call to xvalue
# 1986| Type = [RValueReferenceType] ValCat &&
# 1986| ValueCategory = prvalue
# 1986| getRValue(): [ClassAggregateLiteral] {...}
# 1986| Type = [Struct] ValCat
# 1986| ValueCategory = prvalue
# 1986| getLValue().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
# 1986| Type = [Struct] ValCat
# 1986| ValueCategory = lvalue
#-----| getRValue().getFullyConverted(): [TemporaryObjectExpr] temporary object
#-----| Type = [Struct] ValCat
#-----| ValueCategory = prvalue(load)
# 1987| getStmt(6): [ExprStmt] ExprStmt
# 1987| getExpr(): [AssignExpr] ... = ...
# 1987| Type = [Struct] ValCat
# 1987| ValueCategory = lvalue
# 1987| getLValue(): [FunctionCall] call to prvalue
# 1987| Type = [Struct] ValCat
# 1987| ValueCategory = prvalue
# 1987| getRValue(): [ClassAggregateLiteral] {...}
# 1987| Type = [Struct] ValCat
# 1987| ValueCategory = prvalue
# 1987| getLValue().getFullyConverted(): [TemporaryObjectExpr] temporary object
# 1987| Type = [Struct] ValCat
# 1987| ValueCategory = lvalue
#-----| getRValue().getFullyConverted(): [TemporaryObjectExpr] temporary object
#-----| Type = [Struct] ValCat
#-----| ValueCategory = prvalue(load)
# 1988| getStmt(7): [ReturnStmt] return ...
# 1990| [TopLevelFunction] void SetStaticFuncPtr()
# 1990| <params>:
# 1990| getEntryPoint(): [BlockStmt] { ... }
# 1991| getStmt(0): [DeclStmt] declaration
# 1991| getDeclarationEntry(0): [VariableDeclarationEntry] definition of c
# 1991| Type = [Class] C
# 1991| getVariable().getInitializer(): [Initializer] initializer for c
# 1991| getExpr(): [ConstructorCall] call to C
# 1991| Type = [VoidType] void
# 1991| ValueCategory = prvalue
# 1992| getStmt(1): [DeclStmt] declaration
# 1992| getDeclarationEntry(0): [VariableDeclarationEntry] definition of pfn
# 1992| Type = [FunctionPointerType] ..(*)(..)
# 1992| getVariable().getInitializer(): [Initializer] initializer for pfn
# 1992| getExpr(): [FunctionAccess] StaticMemberFunction
# 1992| Type = [FunctionPointerType] ..(*)(..)
# 1992| ValueCategory = prvalue(load)
# 1993| getStmt(2): [ExprStmt] ExprStmt
# 1993| getExpr(): [AssignExpr] ... = ...
# 1993| Type = [FunctionPointerType] ..(*)(..)
# 1993| ValueCategory = lvalue
# 1993| getLValue(): [VariableAccess] pfn
# 1993| Type = [FunctionPointerType] ..(*)(..)
# 1993| ValueCategory = lvalue
# 1993| getRValue(): [FunctionAccess] StaticMemberFunction
# 1993| Type = [FunctionPointerType] ..(*)(..)
# 1993| ValueCategory = prvalue
# 1993| getQualifier(): [VariableAccess] c
# 1993| Type = [Class] C
# 1993| ValueCategory = lvalue
# 1994| getStmt(3): [ReturnStmt] return ...
perf-regression.cpp:
# 4| [CopyAssignmentOperator] Big& Big::operator=(Big const&)
# 4| <params>:

View File

@@ -1930,4 +1930,67 @@ void test_double_assign() {
i = j = 40;
}
void test_assign_with_assign_operation() {
int i, j = 0;
i = (j += 40);
}
class D {
static D x;
public:
static D& ReferenceStaticMemberFunction() {
return x;
}
static D ObjectStaticMemberFunction() {
return x;
}
};
void test_static_member_functions_with_reference_return() {
D d;
d.ReferenceStaticMemberFunction();
D::ReferenceStaticMemberFunction();
d.ObjectStaticMemberFunction();
D::ObjectStaticMemberFunction();
D x;
x = d.ReferenceStaticMemberFunction();
D y;
y = D::ReferenceStaticMemberFunction();
D j;
j = d.ObjectStaticMemberFunction();
D k;
k = D::ObjectStaticMemberFunction();
}
void test_volatile() {
volatile int x;
x;
}
struct ValCat {
static ValCat& lvalue();
static ValCat&& xvalue();
static ValCat prvalue();
};
void value_category_test() {
ValCat c;
c.lvalue() = {};
c.xvalue() = {};
c.prvalue() = {};
ValCat::lvalue() = {};
ValCat::xvalue() = {};
ValCat::prvalue() = {};
}
void SetStaticFuncPtr() {
C c;
int (*pfn)(int) = C::StaticMemberFunction;
pfn = c.StaticMemberFunction;
}
// semmle-extractor-options: -std=c++17 --clang

View File

@@ -678,6 +678,8 @@
| file://:0:0:0:0 | Address | &:r0_1 |
| file://:0:0:0:0 | Address | &:r0_1 |
| file://:0:0:0:0 | Address | &:r0_1 |
| file://:0:0:0:0 | Address | &:r0_1 |
| file://:0:0:0:0 | Address | &:r0_1 |
| file://:0:0:0:0 | Address | &:r0_2 |
| file://:0:0:0:0 | Address | &:r0_3 |
| file://:0:0:0:0 | Address | &:r0_3 |
@@ -702,6 +704,8 @@
| file://:0:0:0:0 | Address | &:r0_3 |
| file://:0:0:0:0 | Address | &:r0_3 |
| file://:0:0:0:0 | Address | &:r0_3 |
| file://:0:0:0:0 | Address | &:r0_4 |
| file://:0:0:0:0 | Address | &:r0_4 |
| file://:0:0:0:0 | Address | &:r0_5 |
| file://:0:0:0:0 | Address | &:r0_5 |
| file://:0:0:0:0 | Address | &:r0_5 |
@@ -714,6 +718,8 @@
| file://:0:0:0:0 | Address | &:r0_6 |
| file://:0:0:0:0 | Address | &:r0_7 |
| file://:0:0:0:0 | Address | &:r0_7 |
| file://:0:0:0:0 | Address | &:r0_7 |
| file://:0:0:0:0 | Address | &:r0_7 |
| file://:0:0:0:0 | Address | &:r0_8 |
| file://:0:0:0:0 | Address | &:r0_8 |
| file://:0:0:0:0 | Address | &:r0_8 |
@@ -724,16 +730,22 @@
| file://:0:0:0:0 | Address | &:r0_9 |
| file://:0:0:0:0 | Address | &:r0_9 |
| file://:0:0:0:0 | Address | &:r0_10 |
| file://:0:0:0:0 | Address | &:r0_10 |
| file://:0:0:0:0 | Address | &:r0_10 |
| file://:0:0:0:0 | Address | &:r0_11 |
| file://:0:0:0:0 | Address | &:r0_11 |
| file://:0:0:0:0 | Address | &:r0_11 |
| file://:0:0:0:0 | Address | &:r0_13 |
| file://:0:0:0:0 | Address | &:r0_13 |
| file://:0:0:0:0 | Address | &:r0_13 |
| file://:0:0:0:0 | Address | &:r0_15 |
| file://:0:0:0:0 | Address | &:r0_15 |
| file://:0:0:0:0 | Address | &:r0_15 |
| file://:0:0:0:0 | Address | &:r0_15 |
| file://:0:0:0:0 | Address | &:r0_16 |
| file://:0:0:0:0 | Address | &:r0_16 |
| file://:0:0:0:0 | Address | &:r0_16 |
| file://:0:0:0:0 | Address | &:r0_16 |
| file://:0:0:0:0 | Address | &:r0_17 |
| file://:0:0:0:0 | Address | &:r0_18 |
| file://:0:0:0:0 | Address | &:r0_18 |
@@ -786,6 +798,12 @@
| file://:0:0:0:0 | Load | m0_2 |
| file://:0:0:0:0 | Load | m0_2 |
| file://:0:0:0:0 | Load | m0_2 |
| file://:0:0:0:0 | Load | m0_2 |
| file://:0:0:0:0 | Load | m0_5 |
| file://:0:0:0:0 | Load | m0_8 |
| file://:0:0:0:0 | Load | m0_11 |
| file://:0:0:0:0 | Load | m0_14 |
| file://:0:0:0:0 | Load | m0_17 |
| file://:0:0:0:0 | Load | m745_6 |
| file://:0:0:0:0 | Load | m754_6 |
| file://:0:0:0:0 | Load | m763_6 |
@@ -843,14 +861,20 @@
| file://:0:0:0:0 | StoreValue | r0_1 |
| file://:0:0:0:0 | StoreValue | r0_1 |
| file://:0:0:0:0 | StoreValue | r0_3 |
| file://:0:0:0:0 | StoreValue | r0_3 |
| file://:0:0:0:0 | StoreValue | r0_4 |
| file://:0:0:0:0 | StoreValue | r0_4 |
| file://:0:0:0:0 | StoreValue | r0_6 |
| file://:0:0:0:0 | StoreValue | r0_6 |
| file://:0:0:0:0 | StoreValue | r0_7 |
| file://:0:0:0:0 | StoreValue | r0_9 |
| file://:0:0:0:0 | StoreValue | r0_9 |
| file://:0:0:0:0 | StoreValue | r0_12 |
| file://:0:0:0:0 | StoreValue | r0_12 |
| file://:0:0:0:0 | StoreValue | r0_13 |
| file://:0:0:0:0 | StoreValue | r0_13 |
| file://:0:0:0:0 | StoreValue | r0_15 |
| file://:0:0:0:0 | StoreValue | r0_18 |
| file://:0:0:0:0 | StoreValue | r0_19 |
| file://:0:0:0:0 | StoreValue | r0_20 |
| file://:0:0:0:0 | StoreValue | r0_22 |
@@ -8877,6 +8901,163 @@
| ir.cpp:1930:7:1930:12 | StoreValue | r1930_4 |
| ir.cpp:1930:11:1930:12 | StoreValue | r1930_1 |
| ir.cpp:1930:11:1930:12 | Unary | r1930_1 |
| ir.cpp:1933:6:1933:38 | ChiPartial | partial:m1933_3 |
| ir.cpp:1933:6:1933:38 | ChiTotal | total:m1933_2 |
| ir.cpp:1933:6:1933:38 | SideEffect | m1933_3 |
| ir.cpp:1934:7:1934:7 | Address | &:r1934_1 |
| ir.cpp:1934:10:1934:10 | Address | &:r1934_3 |
| ir.cpp:1934:13:1934:14 | StoreValue | r1934_4 |
| ir.cpp:1935:3:1935:3 | Address | &:r1935_6 |
| ir.cpp:1935:8:1935:8 | Address | &:r1935_2 |
| ir.cpp:1935:8:1935:8 | Address | &:r1935_2 |
| ir.cpp:1935:8:1935:8 | Left | r1935_3 |
| ir.cpp:1935:8:1935:8 | Load | m1934_5 |
| ir.cpp:1935:8:1935:14 | StoreValue | r1935_4 |
| ir.cpp:1935:8:1935:14 | StoreValue | r1935_4 |
| ir.cpp:1935:13:1935:14 | Right | r1935_1 |
| ir.cpp:1942:15:1942:43 | Address | &:r1942_5 |
| ir.cpp:1942:15:1942:43 | ChiPartial | partial:m1942_3 |
| ir.cpp:1942:15:1942:43 | ChiTotal | total:m1942_2 |
| ir.cpp:1942:15:1942:43 | Load | m1943_4 |
| ir.cpp:1942:15:1942:43 | SideEffect | m1942_3 |
| ir.cpp:1943:9:1943:17 | Address | &:r1943_1 |
| ir.cpp:1943:16:1943:16 | StoreValue | r1943_3 |
| ir.cpp:1943:16:1943:16 | Unary | r1943_2 |
| ir.cpp:1945:14:1945:39 | Address | &:r1945_5 |
| ir.cpp:1945:14:1945:39 | ChiPartial | partial:m1945_3 |
| ir.cpp:1945:14:1945:39 | ChiTotal | total:m1945_2 |
| ir.cpp:1945:14:1945:39 | Load | m1946_4 |
| ir.cpp:1945:14:1945:39 | SideEffect | m1945_3 |
| ir.cpp:1946:9:1946:17 | Address | &:r1946_1 |
| ir.cpp:1946:16:1946:16 | Address | &:r1946_2 |
| ir.cpp:1946:16:1946:16 | Load | ~m1945_3 |
| ir.cpp:1946:16:1946:16 | StoreValue | r1946_3 |
| ir.cpp:1950:6:1950:55 | ChiPartial | partial:m1950_3 |
| ir.cpp:1950:6:1950:55 | ChiTotal | total:m1950_2 |
| ir.cpp:1950:6:1950:55 | SideEffect | ~m1965_4 |
| ir.cpp:1951:7:1951:7 | Address | &:r1951_1 |
| ir.cpp:1953:7:1953:35 | CallTarget | func:r1953_2 |
| ir.cpp:1953:7:1953:35 | ChiPartial | partial:m1953_4 |
| ir.cpp:1953:7:1953:35 | ChiTotal | total:m1950_4 |
| ir.cpp:1953:7:1953:35 | SideEffect | ~m1950_4 |
| ir.cpp:1953:7:1953:35 | Unary | r1953_3 |
| ir.cpp:1954:5:1954:36 | CallTarget | func:r1954_1 |
| ir.cpp:1954:5:1954:36 | ChiPartial | partial:m1954_3 |
| ir.cpp:1954:5:1954:36 | ChiTotal | total:m1953_5 |
| ir.cpp:1954:5:1954:36 | SideEffect | ~m1953_5 |
| ir.cpp:1954:5:1954:36 | Unary | r1954_2 |
| ir.cpp:1955:7:1955:32 | CallTarget | func:r1955_2 |
| ir.cpp:1955:7:1955:32 | ChiPartial | partial:m1955_4 |
| ir.cpp:1955:7:1955:32 | ChiTotal | total:m1954_4 |
| ir.cpp:1955:7:1955:32 | SideEffect | ~m1954_4 |
| ir.cpp:1956:5:1956:33 | CallTarget | func:r1956_1 |
| ir.cpp:1956:5:1956:33 | ChiPartial | partial:m1956_3 |
| ir.cpp:1956:5:1956:33 | ChiTotal | total:m1955_5 |
| ir.cpp:1956:5:1956:33 | SideEffect | ~m1955_5 |
| ir.cpp:1958:7:1958:7 | Address | &:r1958_1 |
| ir.cpp:1959:5:1959:5 | Address | &:r1959_7 |
| ir.cpp:1959:11:1959:39 | Address | &:r1959_3 |
| ir.cpp:1959:11:1959:39 | CallTarget | func:r1959_2 |
| ir.cpp:1959:11:1959:39 | ChiPartial | partial:m1959_4 |
| ir.cpp:1959:11:1959:39 | ChiTotal | total:m1956_4 |
| ir.cpp:1959:11:1959:39 | SideEffect | ~m1956_4 |
| ir.cpp:1959:40:1959:42 | Load | ~m1959_5 |
| ir.cpp:1959:40:1959:42 | StoreValue | r1959_6 |
| ir.cpp:1960:7:1960:7 | Address | &:r1960_1 |
| ir.cpp:1961:5:1961:5 | Address | &:r1961_6 |
| ir.cpp:1961:9:1961:40 | Address | &:r1961_2 |
| ir.cpp:1961:9:1961:40 | CallTarget | func:r1961_1 |
| ir.cpp:1961:9:1961:40 | ChiPartial | partial:m1961_3 |
| ir.cpp:1961:9:1961:40 | ChiTotal | total:m1959_5 |
| ir.cpp:1961:9:1961:40 | SideEffect | ~m1959_5 |
| ir.cpp:1961:41:1961:43 | Load | ~m1961_4 |
| ir.cpp:1961:41:1961:43 | StoreValue | r1961_5 |
| ir.cpp:1962:7:1962:7 | Address | &:r1962_1 |
| ir.cpp:1963:5:1963:5 | Address | &:r1963_6 |
| ir.cpp:1963:11:1963:36 | CallTarget | func:r1963_2 |
| ir.cpp:1963:11:1963:36 | ChiPartial | partial:m1963_4 |
| ir.cpp:1963:11:1963:36 | ChiTotal | total:m1961_4 |
| ir.cpp:1963:11:1963:36 | SideEffect | ~m1961_4 |
| ir.cpp:1963:11:1963:36 | StoreValue | r1963_3 |
| ir.cpp:1964:7:1964:7 | Address | &:r1964_1 |
| ir.cpp:1965:5:1965:5 | Address | &:r1965_5 |
| ir.cpp:1965:9:1965:37 | CallTarget | func:r1965_1 |
| ir.cpp:1965:9:1965:37 | ChiPartial | partial:m1965_3 |
| ir.cpp:1965:9:1965:37 | ChiTotal | total:m1963_5 |
| ir.cpp:1965:9:1965:37 | SideEffect | ~m1963_5 |
| ir.cpp:1965:9:1965:37 | StoreValue | r1965_2 |
| ir.cpp:1968:6:1968:18 | ChiPartial | partial:m1968_3 |
| ir.cpp:1968:6:1968:18 | ChiTotal | total:m1968_2 |
| ir.cpp:1968:6:1968:18 | SideEffect | m1968_3 |
| ir.cpp:1969:18:1969:18 | Address | &:r1969_1 |
| ir.cpp:1970:5:1970:5 | Address | &:r1970_1 |
| ir.cpp:1970:5:1970:5 | Load | m1969_2 |
| ir.cpp:1979:6:1979:24 | ChiPartial | partial:m1979_3 |
| ir.cpp:1979:6:1979:24 | ChiTotal | total:m1979_2 |
| ir.cpp:1979:6:1979:24 | SideEffect | ~m1987_5 |
| ir.cpp:1980:12:1980:12 | Address | &:r1980_1 |
| ir.cpp:1982:5:1982:19 | ChiPartial | partial:m1982_7 |
| ir.cpp:1982:5:1982:19 | ChiTotal | total:m1982_5 |
| ir.cpp:1982:7:1982:12 | CallTarget | func:r1982_2 |
| ir.cpp:1982:7:1982:12 | ChiPartial | partial:m1982_4 |
| ir.cpp:1982:7:1982:12 | ChiTotal | total:m1979_4 |
| ir.cpp:1982:7:1982:12 | SideEffect | ~m1979_4 |
| ir.cpp:1982:7:1982:12 | Unary | r1982_3 |
| ir.cpp:1982:13:1982:16 | Address | &:r1982_6 |
| ir.cpp:1983:5:1983:19 | ChiPartial | partial:m1983_7 |
| ir.cpp:1983:5:1983:19 | ChiTotal | total:m1983_5 |
| ir.cpp:1983:7:1983:12 | CallTarget | func:r1983_2 |
| ir.cpp:1983:7:1983:12 | ChiPartial | partial:m1983_4 |
| ir.cpp:1983:7:1983:12 | ChiTotal | total:m1982_8 |
| ir.cpp:1983:7:1983:12 | SideEffect | ~m1982_8 |
| ir.cpp:1983:7:1983:12 | Unary | r1983_3 |
| ir.cpp:1983:13:1983:16 | Address | &:r1983_6 |
| ir.cpp:1984:5:1984:15 | Address | &:r1984_1 |
| ir.cpp:1984:5:1984:15 | Address | &:r1984_1 |
| ir.cpp:1984:7:1984:13 | CallTarget | func:r1984_3 |
| ir.cpp:1984:7:1984:13 | ChiPartial | partial:m1984_5 |
| ir.cpp:1984:7:1984:13 | ChiTotal | total:m1983_8 |
| ir.cpp:1984:7:1984:13 | SideEffect | ~m1983_8 |
| ir.cpp:1984:7:1984:13 | StoreValue | r1984_4 |
| ir.cpp:1985:5:1985:18 | CallTarget | func:r1985_1 |
| ir.cpp:1985:5:1985:18 | ChiPartial | partial:m1985_3 |
| ir.cpp:1985:5:1985:18 | ChiTotal | total:m1984_6 |
| ir.cpp:1985:5:1985:18 | SideEffect | ~m1984_6 |
| ir.cpp:1985:5:1985:18 | Unary | r1985_2 |
| ir.cpp:1985:5:1985:25 | ChiPartial | partial:m1985_6 |
| ir.cpp:1985:5:1985:25 | ChiTotal | total:m1985_4 |
| ir.cpp:1985:19:1985:22 | Address | &:r1985_5 |
| ir.cpp:1986:5:1986:18 | CallTarget | func:r1986_1 |
| ir.cpp:1986:5:1986:18 | ChiPartial | partial:m1986_3 |
| ir.cpp:1986:5:1986:18 | ChiTotal | total:m1985_7 |
| ir.cpp:1986:5:1986:18 | SideEffect | ~m1985_7 |
| ir.cpp:1986:5:1986:18 | Unary | r1986_2 |
| ir.cpp:1986:5:1986:25 | ChiPartial | partial:m1986_6 |
| ir.cpp:1986:5:1986:25 | ChiTotal | total:m1986_4 |
| ir.cpp:1986:19:1986:22 | Address | &:r1986_5 |
| ir.cpp:1987:5:1987:19 | CallTarget | func:r1987_2 |
| ir.cpp:1987:5:1987:19 | ChiPartial | partial:m1987_4 |
| ir.cpp:1987:5:1987:19 | ChiTotal | total:m1986_7 |
| ir.cpp:1987:5:1987:19 | SideEffect | ~m1986_7 |
| ir.cpp:1987:5:1987:19 | StoreValue | r1987_3 |
| ir.cpp:1987:5:1987:21 | Address | &:r1987_1 |
| ir.cpp:1987:5:1987:21 | Address | &:r1987_1 |
| ir.cpp:1990:6:1990:21 | ChiPartial | partial:m1990_3 |
| ir.cpp:1990:6:1990:21 | ChiTotal | total:m1990_2 |
| ir.cpp:1990:6:1990:21 | SideEffect | ~m1991_6 |
| ir.cpp:1991:7:1991:7 | Address | &:r1991_1 |
| ir.cpp:1991:7:1991:7 | Address | &:r1991_1 |
| ir.cpp:1991:7:1991:7 | Arg(this) | this:r1991_1 |
| ir.cpp:1991:7:1991:7 | CallTarget | func:r1991_3 |
| ir.cpp:1991:7:1991:7 | ChiPartial | partial:m1991_5 |
| ir.cpp:1991:7:1991:7 | ChiPartial | partial:m1991_7 |
| ir.cpp:1991:7:1991:7 | ChiTotal | total:m1990_4 |
| ir.cpp:1991:7:1991:7 | ChiTotal | total:m1991_2 |
| ir.cpp:1991:7:1991:7 | SideEffect | ~m1990_4 |
| ir.cpp:1992:11:1992:13 | Address | &:r1992_1 |
| ir.cpp:1992:23:1992:45 | StoreValue | r1992_2 |
| ir.cpp:1993:5:1993:7 | Address | &:r1993_3 |
| ir.cpp:1993:13:1993:32 | StoreValue | r1993_2 |
| perf-regression.cpp:6:3:6:5 | Address | &:r6_5 |
| perf-regression.cpp:6:3:6:5 | Address | &:r6_5 |
| perf-regression.cpp:6:3:6:5 | Address | &:r6_7 |

View File

@@ -10244,6 +10244,218 @@ ir.cpp:
# 1928| v1928_5(void) = AliasedUse : ~m?
# 1928| v1928_6(void) = ExitFunction :
# 1933| void test_assign_with_assign_operation()
# 1933| Block 0
# 1933| v1933_1(void) = EnterFunction :
# 1933| mu1933_2(unknown) = AliasedDefinition :
# 1933| mu1933_3(unknown) = InitializeNonLocal :
# 1934| r1934_1(glval<int>) = VariableAddress[i] :
# 1934| mu1934_2(int) = Uninitialized[i] : &:r1934_1
# 1934| r1934_3(glval<int>) = VariableAddress[j] :
# 1934| r1934_4(int) = Constant[0] :
# 1934| mu1934_5(int) = Store[j] : &:r1934_3, r1934_4
# 1935| r1935_1(int) = Constant[40] :
# 1935| r1935_2(glval<int>) = VariableAddress[j] :
# 1935| r1935_3(int) = Load[j] : &:r1935_2, ~m?
# 1935| r1935_4(int) = Add : r1935_3, r1935_1
# 1935| mu1935_5(int) = Store[j] : &:r1935_2, r1935_4
# 1935| r1935_6(glval<int>) = VariableAddress[i] :
# 1935| mu1935_7(int) = Store[i] : &:r1935_6, r1935_4
# 1936| v1936_1(void) = NoOp :
# 1933| v1933_4(void) = ReturnVoid :
# 1933| v1933_5(void) = AliasedUse : ~m?
# 1933| v1933_6(void) = ExitFunction :
# 1942| D& D::ReferenceStaticMemberFunction()
# 1942| Block 0
# 1942| v1942_1(void) = EnterFunction :
# 1942| mu1942_2(unknown) = AliasedDefinition :
# 1942| mu1942_3(unknown) = InitializeNonLocal :
# 1943| r1943_1(glval<D &>) = VariableAddress[#return] :
# 1943| r1943_2(glval<D>) = VariableAddress[x] :
# 1943| r1943_3(D &) = CopyValue : r1943_2
# 1943| mu1943_4(D &) = Store[#return] : &:r1943_1, r1943_3
# 1942| r1942_4(glval<D &>) = VariableAddress[#return] :
# 1942| v1942_5(void) = ReturnValue : &:r1942_4, ~m?
# 1942| v1942_6(void) = AliasedUse : ~m?
# 1942| v1942_7(void) = ExitFunction :
# 1945| D D::ObjectStaticMemberFunction()
# 1945| Block 0
# 1945| v1945_1(void) = EnterFunction :
# 1945| mu1945_2(unknown) = AliasedDefinition :
# 1945| mu1945_3(unknown) = InitializeNonLocal :
# 1946| r1946_1(glval<D>) = VariableAddress[#return] :
# 1946| r1946_2(glval<D>) = VariableAddress[x] :
# 1946| r1946_3(D) = Load[x] : &:r1946_2, ~m?
# 1946| mu1946_4(D) = Store[#return] : &:r1946_1, r1946_3
# 1945| r1945_4(glval<D>) = VariableAddress[#return] :
# 1945| v1945_5(void) = ReturnValue : &:r1945_4, ~m?
# 1945| v1945_6(void) = AliasedUse : ~m?
# 1945| v1945_7(void) = ExitFunction :
# 1950| void test_static_member_functions_with_reference_return()
# 1950| Block 0
# 1950| v1950_1(void) = EnterFunction :
# 1950| mu1950_2(unknown) = AliasedDefinition :
# 1950| mu1950_3(unknown) = InitializeNonLocal :
# 1951| r1951_1(glval<D>) = VariableAddress[d] :
# 1951| mu1951_2(D) = Uninitialized[d] : &:r1951_1
# 1953| r1953_1(glval<D>) = VariableAddress[d] :
# 1953| r1953_2(glval<unknown>) = FunctionAddress[ReferenceStaticMemberFunction] :
# 1953| r1953_3(D &) = Call[ReferenceStaticMemberFunction] : func:r1953_2
# 1953| mu1953_4(unknown) = ^CallSideEffect : ~m?
# 1953| r1953_5(glval<D>) = CopyValue : r1953_3
# 1954| r1954_1(glval<unknown>) = FunctionAddress[ReferenceStaticMemberFunction] :
# 1954| r1954_2(D &) = Call[ReferenceStaticMemberFunction] : func:r1954_1
# 1954| mu1954_3(unknown) = ^CallSideEffect : ~m?
# 1954| r1954_4(glval<D>) = CopyValue : r1954_2
# 1955| r1955_1(glval<D>) = VariableAddress[d] :
# 1955| r1955_2(glval<unknown>) = FunctionAddress[ObjectStaticMemberFunction] :
# 1955| r1955_3(D) = Call[ObjectStaticMemberFunction] : func:r1955_2
# 1955| mu1955_4(unknown) = ^CallSideEffect : ~m?
# 1956| r1956_1(glval<unknown>) = FunctionAddress[ObjectStaticMemberFunction] :
# 1956| r1956_2(D) = Call[ObjectStaticMemberFunction] : func:r1956_1
# 1956| mu1956_3(unknown) = ^CallSideEffect : ~m?
# 1958| r1958_1(glval<D>) = VariableAddress[x] :
# 1958| mu1958_2(D) = Uninitialized[x] : &:r1958_1
# 1959| r1959_1(glval<D>) = VariableAddress[d] :
# 1959| r1959_2(glval<unknown>) = FunctionAddress[ReferenceStaticMemberFunction] :
# 1959| r1959_3(D &) = Call[ReferenceStaticMemberFunction] : func:r1959_2
# 1959| mu1959_4(unknown) = ^CallSideEffect : ~m?
# 1959| r1959_5(D) = Load[?] : &:r1959_3, ~m?
# 1959| r1959_6(glval<D>) = VariableAddress[x] :
# 1959| mu1959_7(D) = Store[x] : &:r1959_6, r1959_5
# 1960| r1960_1(glval<D>) = VariableAddress[y] :
# 1960| mu1960_2(D) = Uninitialized[y] : &:r1960_1
# 1961| r1961_1(glval<unknown>) = FunctionAddress[ReferenceStaticMemberFunction] :
# 1961| r1961_2(D &) = Call[ReferenceStaticMemberFunction] : func:r1961_1
# 1961| mu1961_3(unknown) = ^CallSideEffect : ~m?
# 1961| r1961_4(D) = Load[?] : &:r1961_2, ~m?
# 1961| r1961_5(glval<D>) = VariableAddress[y] :
# 1961| mu1961_6(D) = Store[y] : &:r1961_5, r1961_4
# 1962| r1962_1(glval<D>) = VariableAddress[j] :
# 1962| mu1962_2(D) = Uninitialized[j] : &:r1962_1
# 1963| r1963_1(glval<D>) = VariableAddress[d] :
# 1963| r1963_2(glval<unknown>) = FunctionAddress[ObjectStaticMemberFunction] :
# 1963| r1963_3(D) = Call[ObjectStaticMemberFunction] : func:r1963_2
# 1963| mu1963_4(unknown) = ^CallSideEffect : ~m?
# 1963| r1963_5(glval<D>) = VariableAddress[j] :
# 1963| mu1963_6(D) = Store[j] : &:r1963_5, r1963_3
# 1964| r1964_1(glval<D>) = VariableAddress[k] :
# 1964| mu1964_2(D) = Uninitialized[k] : &:r1964_1
# 1965| r1965_1(glval<unknown>) = FunctionAddress[ObjectStaticMemberFunction] :
# 1965| r1965_2(D) = Call[ObjectStaticMemberFunction] : func:r1965_1
# 1965| mu1965_3(unknown) = ^CallSideEffect : ~m?
# 1965| r1965_4(glval<D>) = VariableAddress[k] :
# 1965| mu1965_5(D) = Store[k] : &:r1965_4, r1965_2
# 1966| v1966_1(void) = NoOp :
# 1950| v1950_4(void) = ReturnVoid :
# 1950| v1950_5(void) = AliasedUse : ~m?
# 1950| v1950_6(void) = ExitFunction :
# 1968| void test_volatile()
# 1968| Block 0
# 1968| v1968_1(void) = EnterFunction :
# 1968| mu1968_2(unknown) = AliasedDefinition :
# 1968| mu1968_3(unknown) = InitializeNonLocal :
# 1969| r1969_1(glval<int>) = VariableAddress[x] :
# 1969| mu1969_2(int) = Uninitialized[x] : &:r1969_1
# 1970| r1970_1(glval<int>) = VariableAddress[x] :
# 1970| r1970_2(int) = Load[x] : &:r1970_1, ~m?
# 1971| v1971_1(void) = NoOp :
# 1968| v1968_4(void) = ReturnVoid :
# 1968| v1968_5(void) = AliasedUse : ~m?
# 1968| v1968_6(void) = ExitFunction :
# 1979| void value_category_test()
# 1979| Block 0
# 1979| v1979_1(void) = EnterFunction :
# 1979| mu1979_2(unknown) = AliasedDefinition :
# 1979| mu1979_3(unknown) = InitializeNonLocal :
# 1980| r1980_1(glval<ValCat>) = VariableAddress[c] :
# 1980| mu1980_2(ValCat) = Uninitialized[c] : &:r1980_1
#-----| r0_1(glval<ValCat>) = VariableAddress[#temp0:0] :
#-----| mu0_2(ValCat) = Uninitialized[#temp0:0] : &:r0_1
#-----| r0_3(ValCat) = Load[#temp0:0] : &:r0_1, ~m?
# 1982| r1982_1(glval<ValCat>) = VariableAddress[c] :
# 1982| r1982_2(glval<unknown>) = FunctionAddress[lvalue] :
# 1982| r1982_3(ValCat &) = Call[lvalue] : func:r1982_2
# 1982| mu1982_4(unknown) = ^CallSideEffect : ~m?
# 1982| r1982_5(glval<ValCat>) = CopyValue : r1982_3
# 1982| mu1982_6(ValCat) = Store[?] : &:r1982_5, r0_3
#-----| r0_4(glval<ValCat>) = VariableAddress[#temp0:0] :
#-----| mu0_5(ValCat) = Uninitialized[#temp0:0] : &:r0_4
#-----| r0_6(ValCat) = Load[#temp0:0] : &:r0_4, ~m?
# 1983| r1983_1(glval<ValCat>) = VariableAddress[c] :
# 1983| r1983_2(glval<unknown>) = FunctionAddress[xvalue] :
# 1983| r1983_3(ValCat &&) = Call[xvalue] : func:r1983_2
# 1983| mu1983_4(unknown) = ^CallSideEffect : ~m?
# 1983| r1983_5(glval<ValCat>) = CopyValue : r1983_3
# 1983| mu1983_6(ValCat) = Store[?] : &:r1983_5, r0_6
#-----| r0_7(glval<ValCat>) = VariableAddress[#temp0:0] :
#-----| mu0_8(ValCat) = Uninitialized[#temp0:0] : &:r0_7
#-----| r0_9(ValCat) = Load[#temp0:0] : &:r0_7, ~m?
# 1984| r1984_1(glval<ValCat>) = VariableAddress[#temp1984:5] :
# 1984| r1984_2(glval<ValCat>) = VariableAddress[c] :
# 1984| r1984_3(glval<unknown>) = FunctionAddress[prvalue] :
# 1984| r1984_4(ValCat) = Call[prvalue] : func:r1984_3
# 1984| mu1984_5(unknown) = ^CallSideEffect : ~m?
# 1984| mu1984_6(ValCat) = Store[#temp1984:5] : &:r1984_1, r1984_4
# 1984| mu1984_7(ValCat) = Store[#temp1984:5] : &:r1984_1, r0_9
#-----| r0_10(glval<ValCat>) = VariableAddress[#temp0:0] :
#-----| mu0_11(ValCat) = Uninitialized[#temp0:0] : &:r0_10
#-----| r0_12(ValCat) = Load[#temp0:0] : &:r0_10, ~m?
# 1985| r1985_1(glval<unknown>) = FunctionAddress[lvalue] :
# 1985| r1985_2(ValCat &) = Call[lvalue] : func:r1985_1
# 1985| mu1985_3(unknown) = ^CallSideEffect : ~m?
# 1985| r1985_4(glval<ValCat>) = CopyValue : r1985_2
# 1985| mu1985_5(ValCat) = Store[?] : &:r1985_4, r0_12
#-----| r0_13(glval<ValCat>) = VariableAddress[#temp0:0] :
#-----| mu0_14(ValCat) = Uninitialized[#temp0:0] : &:r0_13
#-----| r0_15(ValCat) = Load[#temp0:0] : &:r0_13, ~m?
# 1986| r1986_1(glval<unknown>) = FunctionAddress[xvalue] :
# 1986| r1986_2(ValCat &&) = Call[xvalue] : func:r1986_1
# 1986| mu1986_3(unknown) = ^CallSideEffect : ~m?
# 1986| r1986_4(glval<ValCat>) = CopyValue : r1986_2
# 1986| mu1986_5(ValCat) = Store[?] : &:r1986_4, r0_15
#-----| r0_16(glval<ValCat>) = VariableAddress[#temp0:0] :
#-----| mu0_17(ValCat) = Uninitialized[#temp0:0] : &:r0_16
#-----| r0_18(ValCat) = Load[#temp0:0] : &:r0_16, ~m?
# 1987| r1987_1(glval<ValCat>) = VariableAddress[#temp1987:5] :
# 1987| r1987_2(glval<unknown>) = FunctionAddress[prvalue] :
# 1987| r1987_3(ValCat) = Call[prvalue] : func:r1987_2
# 1987| mu1987_4(unknown) = ^CallSideEffect : ~m?
# 1987| mu1987_5(ValCat) = Store[#temp1987:5] : &:r1987_1, r1987_3
# 1987| mu1987_6(ValCat) = Store[#temp1987:5] : &:r1987_1, r0_18
# 1988| v1988_1(void) = NoOp :
# 1979| v1979_4(void) = ReturnVoid :
# 1979| v1979_5(void) = AliasedUse : ~m?
# 1979| v1979_6(void) = ExitFunction :
# 1990| void SetStaticFuncPtr()
# 1990| Block 0
# 1990| v1990_1(void) = EnterFunction :
# 1990| mu1990_2(unknown) = AliasedDefinition :
# 1990| mu1990_3(unknown) = InitializeNonLocal :
# 1991| r1991_1(glval<C>) = VariableAddress[c] :
# 1991| mu1991_2(C) = Uninitialized[c] : &:r1991_1
# 1991| r1991_3(glval<unknown>) = FunctionAddress[C] :
# 1991| v1991_4(void) = Call[C] : func:r1991_3, this:r1991_1
# 1991| mu1991_5(unknown) = ^CallSideEffect : ~m?
# 1991| mu1991_6(C) = ^IndirectMayWriteSideEffect[-1] : &:r1991_1
# 1992| r1992_1(glval<..(*)(..)>) = VariableAddress[pfn] :
# 1992| r1992_2(..(*)(..)) = FunctionAddress[StaticMemberFunction] :
# 1992| mu1992_3(..(*)(..)) = Store[pfn] : &:r1992_1, r1992_2
# 1993| r1993_1(glval<C>) = VariableAddress[c] :
# 1993| r1993_2(..(*)(..)) = FunctionAddress[StaticMemberFunction] :
# 1993| r1993_3(glval<..(*)(..)>) = VariableAddress[pfn] :
# 1993| mu1993_4(..(*)(..)) = Store[pfn] : &:r1993_3, r1993_2
# 1994| v1994_1(void) = NoOp :
# 1990| v1990_4(void) = ReturnVoid :
# 1990| v1990_5(void) = AliasedUse : ~m?
# 1990| v1990_6(void) = ExitFunction :
perf-regression.cpp:
# 6| void Big::Big()
# 6| Block 0

View File

@@ -22,7 +22,8 @@ edges
| test.cpp:113:20:113:25 | call to getenv | test.cpp:114:19:114:22 | path indirection |
| test.cpp:113:20:113:38 | call to getenv indirection | test.cpp:114:19:114:22 | path indirection |
| test.cpp:114:10:114:23 | call to operator+ | test.cpp:114:25:114:29 | call to c_str indirection |
| test.cpp:114:17:114:17 | call to operator+ | test.cpp:114:25:114:29 | call to c_str indirection |
| test.cpp:114:10:114:23 | call to operator+ | test.cpp:114:25:114:29 | call to c_str indirection |
| test.cpp:114:17:114:17 | call to operator+ | test.cpp:114:10:114:23 | call to operator+ |
| test.cpp:114:19:114:22 | path indirection | test.cpp:114:10:114:23 | call to operator+ |
| test.cpp:114:19:114:22 | path indirection | test.cpp:114:17:114:17 | call to operator+ |
| test.cpp:119:20:119:25 | call to getenv | test.cpp:120:19:120:22 | path indirection |
@@ -33,18 +34,23 @@ edges
| test.cpp:142:11:142:17 | sprintf output argument | test.cpp:143:10:143:16 | command indirection |
| test.cpp:142:31:142:33 | str indirection | test.cpp:142:11:142:17 | sprintf output argument |
| test.cpp:174:9:174:16 | fread output argument | test.cpp:177:20:177:27 | filename indirection |
| test.cpp:174:9:174:16 | fread output argument | test.cpp:178:22:178:26 | flags indirection |
| test.cpp:174:9:174:16 | fread output argument | test.cpp:180:22:180:29 | filename indirection |
| test.cpp:177:13:177:17 | strncat output argument | test.cpp:183:32:183:38 | command indirection |
| test.cpp:177:13:177:17 | strncat output argument | test.cpp:178:22:178:26 | flags indirection |
| test.cpp:177:13:177:17 | strncat output argument | test.cpp:178:22:178:26 | flags indirection |
| test.cpp:177:20:177:27 | filename indirection | test.cpp:177:13:177:17 | strncat output argument |
| test.cpp:177:20:177:27 | filename indirection | test.cpp:177:13:177:17 | strncat output argument |
| test.cpp:178:13:178:19 | strncat output argument | test.cpp:183:32:183:38 | command indirection |
| test.cpp:178:13:178:19 | strncat output argument | test.cpp:183:32:183:38 | command indirection |
| test.cpp:178:22:178:26 | flags indirection | test.cpp:178:13:178:19 | strncat output argument |
| test.cpp:178:22:178:26 | flags indirection | test.cpp:178:13:178:19 | strncat output argument |
| test.cpp:180:13:180:19 | strncat output argument | test.cpp:183:32:183:38 | command indirection |
| test.cpp:180:22:180:29 | filename indirection | test.cpp:180:13:180:19 | strncat output argument |
| test.cpp:186:47:186:54 | filename indirection | test.cpp:187:18:187:25 | filename indirection |
| test.cpp:186:47:186:54 | filename indirection | test.cpp:188:20:188:24 | flags indirection |
| test.cpp:187:11:187:15 | strncat output argument | test.cpp:188:11:188:17 | strncat output argument |
| test.cpp:187:11:187:15 | strncat output argument | test.cpp:188:20:188:24 | flags indirection |
| test.cpp:187:11:187:15 | strncat output argument | test.cpp:188:20:188:24 | flags indirection |
| test.cpp:187:18:187:25 | filename indirection | test.cpp:187:11:187:15 | strncat output argument |
| test.cpp:187:18:187:25 | filename indirection | test.cpp:187:11:187:15 | strncat output argument |
| test.cpp:188:20:188:24 | flags indirection | test.cpp:188:11:188:17 | strncat output argument |
| test.cpp:188:20:188:24 | flags indirection | test.cpp:188:11:188:17 | strncat output argument |
| test.cpp:194:9:194:16 | fread output argument | test.cpp:196:26:196:33 | filename indirection |
| test.cpp:196:10:196:16 | concat output argument | test.cpp:198:32:198:38 | command indirection |
@@ -53,11 +59,16 @@ edges
| test.cpp:196:26:196:33 | filename indirection | test.cpp:196:10:196:16 | concat output argument |
| test.cpp:196:26:196:33 | filename indirection | test.cpp:196:10:196:16 | concat output argument |
| test.cpp:218:9:218:16 | fread output argument | test.cpp:220:19:220:26 | filename indirection |
| test.cpp:218:9:218:16 | fread output argument | test.cpp:220:19:220:26 | filename indirection |
| test.cpp:220:10:220:16 | strncat output argument | test.cpp:220:10:220:16 | strncat output argument |
| test.cpp:220:10:220:16 | strncat output argument | test.cpp:220:10:220:16 | strncat output argument |
| test.cpp:220:10:220:16 | strncat output argument | test.cpp:220:10:220:16 | strncat output argument |
| test.cpp:220:10:220:16 | strncat output argument | test.cpp:222:32:222:38 | command indirection |
| test.cpp:220:10:220:16 | strncat output argument | test.cpp:222:32:222:38 | command indirection |
| test.cpp:220:10:220:16 | strncat output argument | test.cpp:222:32:222:38 | command indirection |
| test.cpp:220:10:220:16 | strncat output argument | test.cpp:222:32:222:38 | command indirection |
| test.cpp:220:19:220:26 | filename indirection | test.cpp:220:10:220:16 | strncat output argument |
| test.cpp:220:19:220:26 | filename indirection | test.cpp:220:10:220:16 | strncat output argument |
| test.cpp:220:19:220:26 | filename indirection | test.cpp:220:19:220:26 | filename indirection |
nodes
| test.cpp:15:27:15:30 | argv indirection | semmle.label | argv indirection |
| test.cpp:15:27:15:30 | argv indirection | semmle.label | argv indirection |
@@ -88,6 +99,7 @@ nodes
| test.cpp:113:20:113:25 | call to getenv | semmle.label | call to getenv |
| test.cpp:113:20:113:38 | call to getenv indirection | semmle.label | call to getenv indirection |
| test.cpp:114:10:114:23 | call to operator+ | semmle.label | call to operator+ |
| test.cpp:114:10:114:23 | call to operator+ | semmle.label | call to operator+ |
| test.cpp:114:17:114:17 | call to operator+ | semmle.label | call to operator+ |
| test.cpp:114:19:114:22 | path indirection | semmle.label | path indirection |
| test.cpp:114:25:114:29 | call to c_str indirection | semmle.label | call to c_str indirection |
@@ -103,8 +115,11 @@ nodes
| test.cpp:143:10:143:16 | command indirection | semmle.label | command indirection |
| test.cpp:174:9:174:16 | fread output argument | semmle.label | fread output argument |
| test.cpp:177:13:177:17 | strncat output argument | semmle.label | strncat output argument |
| test.cpp:177:13:177:17 | strncat output argument | semmle.label | strncat output argument |
| test.cpp:177:20:177:27 | filename indirection | semmle.label | filename indirection |
| test.cpp:178:13:178:19 | strncat output argument | semmle.label | strncat output argument |
| test.cpp:178:13:178:19 | strncat output argument | semmle.label | strncat output argument |
| test.cpp:178:22:178:26 | flags indirection | semmle.label | flags indirection |
| test.cpp:178:22:178:26 | flags indirection | semmle.label | flags indirection |
| test.cpp:180:13:180:19 | strncat output argument | semmle.label | strncat output argument |
| test.cpp:180:22:180:29 | filename indirection | semmle.label | filename indirection |
@@ -113,10 +128,12 @@ nodes
| test.cpp:183:32:183:38 | command indirection | semmle.label | command indirection |
| test.cpp:186:47:186:54 | filename indirection | semmle.label | filename indirection |
| test.cpp:187:11:187:15 | strncat output argument | semmle.label | strncat output argument |
| test.cpp:187:11:187:15 | strncat output argument | semmle.label | strncat output argument |
| test.cpp:187:18:187:25 | filename indirection | semmle.label | filename indirection |
| test.cpp:188:11:188:17 | strncat output argument | semmle.label | strncat output argument |
| test.cpp:188:11:188:17 | strncat output argument | semmle.label | strncat output argument |
| test.cpp:188:20:188:24 | flags indirection | semmle.label | flags indirection |
| test.cpp:188:20:188:24 | flags indirection | semmle.label | flags indirection |
| test.cpp:194:9:194:16 | fread output argument | semmle.label | fread output argument |
| test.cpp:196:10:196:16 | concat output argument | semmle.label | concat output argument |
| test.cpp:196:10:196:16 | concat output argument | semmle.label | concat output argument |
@@ -126,6 +143,8 @@ nodes
| test.cpp:218:9:218:16 | fread output argument | semmle.label | fread output argument |
| test.cpp:220:10:220:16 | strncat output argument | semmle.label | strncat output argument |
| test.cpp:220:10:220:16 | strncat output argument | semmle.label | strncat output argument |
| test.cpp:220:10:220:16 | strncat output argument | semmle.label | strncat output argument |
| test.cpp:220:10:220:16 | strncat output argument | semmle.label | strncat output argument |
| test.cpp:220:19:220:26 | filename indirection | semmle.label | filename indirection |
| test.cpp:220:19:220:26 | filename indirection | semmle.label | filename indirection |
| test.cpp:222:32:222:38 | command indirection | semmle.label | command indirection |

View File

@@ -14,3 +14,7 @@
| test.cpp:378:9:378:11 | val | The variable $@ may not be initialized at this access. | test.cpp:359:6:359:8 | val | val |
| test.cpp:417:10:417:10 | j | The variable $@ may not be initialized at this access. | test.cpp:414:9:414:9 | j | j |
| test.cpp:436:9:436:9 | j | The variable $@ may not be initialized at this access. | test.cpp:431:9:431:9 | j | j |
| test.cpp:454:2:454:2 | x | The variable $@ may not be initialized at this access. | test.cpp:452:6:452:6 | x | x |
| test.cpp:460:7:460:7 | x | The variable $@ may not be initialized at this access. | test.cpp:458:6:458:6 | x | x |
| test.cpp:467:2:467:2 | x | The variable $@ may not be initialized at this access. | test.cpp:464:6:464:6 | x | x |
| test.cpp:474:7:474:7 | x | The variable $@ may not be initialized at this access. | test.cpp:471:6:471:6 | x | x |

View File

@@ -435,3 +435,41 @@ int test38() {
return j; // BAD
}
void test39() {
int x;
x; // GOOD, in void context
}
void test40() {
int x;
(void)x; // GOOD, explicitly cast to void
}
void test41() {
int x;
x++; // BAD
}
void test42() {
int x;
void(x++); // BAD
}
void test43() {
int x;
int y = 1;
x + y; // BAD
}
void test44() {
int x;
int y = 1;
void(x + y); // BAD
}