mirror of
https://github.com/github/codeql.git
synced 2025-12-22 19:56:32 +01:00
Merge branch 'main' into rdmarsh2/cpp/cobo-array-vars
This commit is contained in:
@@ -1,3 +1,27 @@
|
||||
## 0.7.3
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Deleted the deprecated `hasCopyConstructor` predicate from the `Class` class in `Class.qll`.
|
||||
* Deleted many deprecated predicates and classes with uppercase `AST`, `SSA`, `CFG`, `API`, etc. in their names. Use the PascalCased versions instead.
|
||||
* Deleted the deprecated `CodeDuplication.qll` file.
|
||||
|
||||
## 0.7.2
|
||||
|
||||
### New Features
|
||||
|
||||
* Added an AST-based interface (`semmle.code.cpp.rangeanalysis.new.RangeAnalysis`) for the relative range analysis library.
|
||||
* A new predicate `BarrierGuard::getAnIndirectBarrierNode` has been added to the new dataflow library (`semmle.code.cpp.dataflow.new.DataFlow`) to mark indirect expressions as barrier nodes using the `BarrierGuard` API.
|
||||
|
||||
### Major Analysis Improvements
|
||||
|
||||
* In the intermediate representation, handling of control flow after non-returning calls has been improved. This should remove false positives in queries that use the intermedite representation or libraries based on it, including the new data flow library.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The `StdNamespace` class now also includes all inline namespaces that are children of `std` namespace.
|
||||
* The new dataflow (`semmle.code.cpp.dataflow.new.DataFlow`) and taint-tracking libraries (`semmle.code.cpp.dataflow.new.TaintTracking`) now support tracking flow through static local variables.
|
||||
|
||||
## 0.7.1
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: feature
|
||||
---
|
||||
* A new predicate `BarrierGuard::getAnIndirectBarrierNode` has been added to the new dataflow library (`semmle.code.cpp.dataflow.new.DataFlow`) to mark indirect expressions as barrier nodes using the `BarrierGuard` API.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The new dataflow (`semmle.code.cpp.dataflow.new.DataFlow`) and taint-tracking libraries (`semmle.code.cpp.dataflow.new.TaintTracking`) now support tracking flow through static local variables.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: majorAnalysis
|
||||
---
|
||||
* In the intermediate representation, handling of control flow after non-returning calls has been improved. This should remove false positives in queries that use the intermedite representation or libraries based on it, including the new data flow library.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: feature
|
||||
---
|
||||
* Added an AST-based interface (`semmle.code.cpp.rangeanalysis.new.RangeAnalysis`) for the relative range analysis library.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The `StdNamespace` class now also includes all inline namespaces that are children of `std` namespace.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Deleted the deprecated `getURL` predicate from the `Container`, `Folder`, and `File` classes. Use the `getLocation` predicate instead.
|
||||
15
cpp/ql/lib/change-notes/released/0.7.2.md
Normal file
15
cpp/ql/lib/change-notes/released/0.7.2.md
Normal file
@@ -0,0 +1,15 @@
|
||||
## 0.7.2
|
||||
|
||||
### New Features
|
||||
|
||||
* Added an AST-based interface (`semmle.code.cpp.rangeanalysis.new.RangeAnalysis`) for the relative range analysis library.
|
||||
* A new predicate `BarrierGuard::getAnIndirectBarrierNode` has been added to the new dataflow library (`semmle.code.cpp.dataflow.new.DataFlow`) to mark indirect expressions as barrier nodes using the `BarrierGuard` API.
|
||||
|
||||
### Major Analysis Improvements
|
||||
|
||||
* In the intermediate representation, handling of control flow after non-returning calls has been improved. This should remove false positives in queries that use the intermedite representation or libraries based on it, including the new data flow library.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The `StdNamespace` class now also includes all inline namespaces that are children of `std` namespace.
|
||||
* The new dataflow (`semmle.code.cpp.dataflow.new.DataFlow`) and taint-tracking libraries (`semmle.code.cpp.dataflow.new.TaintTracking`) now support tracking flow through static local variables.
|
||||
7
cpp/ql/lib/change-notes/released/0.7.3.md
Normal file
7
cpp/ql/lib/change-notes/released/0.7.3.md
Normal file
@@ -0,0 +1,7 @@
|
||||
## 0.7.3
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Deleted the deprecated `hasCopyConstructor` predicate from the `Class` class in `Class.qll`.
|
||||
* Deleted many deprecated predicates and classes with uppercase `AST`, `SSA`, `CFG`, `API`, etc. in their names. Use the PascalCased versions instead.
|
||||
* Deleted the deprecated `CodeDuplication.qll` file.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.7.1
|
||||
lastReleaseVersion: 0.7.3
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-all
|
||||
version: 0.7.2-dev
|
||||
version: 0.7.4-dev
|
||||
groups: cpp
|
||||
dbscheme: semmlecode.cpp.dbscheme
|
||||
extractor: cpp
|
||||
|
||||
@@ -176,20 +176,6 @@ class Class extends UserType {
|
||||
/** Holds if this class, struct or union has a constructor. */
|
||||
predicate hasConstructor() { exists(this.getAConstructor()) }
|
||||
|
||||
/**
|
||||
* Holds if this class has a copy constructor that is either explicitly
|
||||
* declared (though possibly `= delete`) or is auto-generated, non-trivial
|
||||
* and called from somewhere.
|
||||
*
|
||||
* DEPRECATED: There is more than one reasonable definition of what it means
|
||||
* to have a copy constructor, and we do not want to promote one particular
|
||||
* definition by naming it with this predicate. Having a copy constructor
|
||||
* could mean that such a member is declared or defined in the source or that
|
||||
* it is callable by a particular caller. For C++11, there's also a question
|
||||
* of whether to include members that are defaulted or deleted.
|
||||
*/
|
||||
deprecated predicate hasCopyConstructor() { this.getAMemberFunction() instanceof CopyConstructor }
|
||||
|
||||
/**
|
||||
* Like accessOfBaseMember but returns multiple results if there are multiple
|
||||
* paths to `base` through the inheritance graph.
|
||||
|
||||
@@ -34,14 +34,6 @@ class Container extends Locatable, @container {
|
||||
*/
|
||||
string getAbsolutePath() { none() } // overridden by subclasses
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `getLocation` instead.
|
||||
* Gets a URL representing the location of this container.
|
||||
*
|
||||
* For more information see [Providing URLs](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/#providing-urls).
|
||||
*/
|
||||
deprecated string getURL() { none() } // overridden by subclasses
|
||||
|
||||
/**
|
||||
* Gets the relative path of this file or folder from the root folder of the
|
||||
* analyzed source location. The relative path of the root folder itself is
|
||||
@@ -183,12 +175,6 @@ class Folder extends Container, @folder {
|
||||
}
|
||||
|
||||
override string getAPrimaryQlClass() { result = "Folder" }
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `getLocation` instead.
|
||||
* Gets the URL of this folder.
|
||||
*/
|
||||
deprecated override string getURL() { result = "file://" + this.getAbsolutePath() + ":0:0:0:0" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -213,12 +199,6 @@ class File extends Container, @file {
|
||||
result.hasLocationInfo(_, 0, 0, 0, 0)
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `getLocation` instead.
|
||||
* Gets the URL of this file.
|
||||
*/
|
||||
deprecated override string getURL() { result = "file://" + this.getAbsolutePath() + ":0:0:0:0" }
|
||||
|
||||
/** Holds if this file was compiled as C (at any point). */
|
||||
predicate compiledAsC() { fileannotations(underlyingElement(this), 1, "compiled as c", "1") }
|
||||
|
||||
|
||||
@@ -34,7 +34,7 @@ class Macro extends PreprocessorDirective, @ppd_define {
|
||||
* Gets the name of the macro. For example, `MAX` in
|
||||
* `#define MAX(x,y) (((x)>(y))?(x):(y))`.
|
||||
*/
|
||||
string getName() { result = this.getHead().splitAt("(", 0) }
|
||||
string getName() { result = this.getHead().regexpCapture("([^(]*+).*", 1) }
|
||||
|
||||
/** Holds if the macro has name `name`. */
|
||||
predicate hasName(string name) { this.getName() = name }
|
||||
|
||||
@@ -27,9 +27,6 @@ class PrintAstConfiguration extends TPrintAstConfiguration {
|
||||
predicate shouldPrintFunction(Function func) { any() }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for PrintAstConfiguration */
|
||||
deprecated class PrintASTConfiguration = PrintAstConfiguration;
|
||||
|
||||
private predicate shouldPrintFunction(Function func) {
|
||||
exists(PrintAstConfiguration config | config.shouldPrintFunction(func))
|
||||
}
|
||||
@@ -239,9 +236,6 @@ class PrintAstNode extends TPrintAstNode {
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for PrintAstNode */
|
||||
deprecated class PrintASTNode = PrintAstNode;
|
||||
|
||||
/**
|
||||
* Class that restricts the elements that we compute `qlClass` for.
|
||||
*/
|
||||
@@ -286,9 +280,6 @@ abstract class BaseAstNode extends PrintAstNode {
|
||||
deprecated Locatable getAST() { result = this.getAst() }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for BaseAstNode */
|
||||
deprecated class BaseASTNode = BaseAstNode;
|
||||
|
||||
/**
|
||||
* A node representing an AST node other than a `DeclarationEntry`.
|
||||
*/
|
||||
@@ -296,9 +287,6 @@ abstract class AstNode extends BaseAstNode, TAstNode {
|
||||
AstNode() { this = TAstNode(ast) }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for AstNode */
|
||||
deprecated class ASTNode = AstNode;
|
||||
|
||||
/**
|
||||
* A node representing an `Expr`.
|
||||
*/
|
||||
|
||||
@@ -14,9 +14,6 @@ library class StandardSsa extends SsaHelper {
|
||||
StandardSsa() { this = 0 }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for StandardSsa */
|
||||
deprecated class StandardSSA = StandardSsa;
|
||||
|
||||
/**
|
||||
* A definition of one or more SSA variables, including phi node definitions.
|
||||
* An _SSA variable_, as defined in the literature, is effectively the pair of
|
||||
|
||||
@@ -312,6 +312,3 @@ library class SsaHelper extends int {
|
||||
ssa_use(v, result, _, _)
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for SsaHelper */
|
||||
deprecated class SSAHelper = SsaHelper;
|
||||
|
||||
@@ -1385,9 +1385,6 @@ private module Cached {
|
||||
conditionalSuccessor(n1, _, n2)
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for qlCfgSuccessor */
|
||||
deprecated predicate qlCFGSuccessor = qlCfgSuccessor/2;
|
||||
|
||||
/**
|
||||
* Holds if `n2` is a control-flow node such that the control-flow
|
||||
* edge `(n1, n2)` may be taken when `n1` is an expression that is true.
|
||||
@@ -1398,9 +1395,6 @@ private module Cached {
|
||||
not conditionalSuccessor(n1, false, n2)
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for qlCfgTrueSuccessor */
|
||||
deprecated predicate qlCFGTrueSuccessor = qlCfgTrueSuccessor/2;
|
||||
|
||||
/**
|
||||
* Holds if `n2` is a control-flow node such that the control-flow
|
||||
* edge `(n1, n2)` may be taken when `n1` is an expression that is false.
|
||||
@@ -1410,7 +1404,4 @@ private module Cached {
|
||||
conditionalSuccessor(n1, false, n2) and
|
||||
not conditionalSuccessor(n1, true, n2)
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for qlCfgFalseSuccessor */
|
||||
deprecated predicate qlCFGFalseSuccessor = qlCfgFalseSuccessor/2;
|
||||
}
|
||||
|
||||
@@ -1135,8 +1135,8 @@ module Impl<FullStateConfigSig Config> {
|
||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow
|
||||
);
|
||||
|
||||
bindingset[node, state, t, ap]
|
||||
predicate filter(NodeEx node, FlowState state, Typ t, Ap ap);
|
||||
bindingset[node, state, t0, ap]
|
||||
predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t);
|
||||
|
||||
bindingset[typ, contentType]
|
||||
predicate typecheckStore(Typ typ, DataFlowType contentType);
|
||||
@@ -1199,17 +1199,21 @@ module Impl<FullStateConfigSig Config> {
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT,
|
||||
ApOption argAp, Typ t, Ap ap, ApApprox apa
|
||||
) {
|
||||
fwdFlow0(node, state, cc, summaryCtx, argT, argAp, t, ap, apa) and
|
||||
PrevStage::revFlow(node, state, apa) and
|
||||
filter(node, state, t, ap)
|
||||
fwdFlow1(node, state, cc, summaryCtx, argT, argAp, _, t, ap, apa)
|
||||
}
|
||||
|
||||
pragma[inline]
|
||||
additional predicate fwdFlow(
|
||||
private predicate fwdFlow1(
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT,
|
||||
ApOption argAp, Typ t, Ap ap
|
||||
ApOption argAp, Typ t0, Typ t, Ap ap, ApApprox apa
|
||||
) {
|
||||
fwdFlow(node, state, cc, summaryCtx, argT, argAp, t, ap, _)
|
||||
fwdFlow0(node, state, cc, summaryCtx, argT, argAp, t0, ap, apa) and
|
||||
PrevStage::revFlow(node, state, apa) and
|
||||
filter(node, state, t0, ap, t)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate typeStrengthen(Typ t0, Ap ap, Typ t) {
|
||||
fwdFlow1(_, _, _, _, _, _, t0, t, ap, _) and t0 != t
|
||||
}
|
||||
|
||||
pragma[assume_small_delta]
|
||||
@@ -1339,6 +1343,11 @@ module Impl<FullStateConfigSig Config> {
|
||||
private predicate fwdFlowConsCand(Typ t2, Ap cons, Content c, Typ t1, Ap tail) {
|
||||
fwdFlowStore(_, t1, tail, c, t2, _, _, _, _, _, _) and
|
||||
cons = apCons(c, t1, tail)
|
||||
or
|
||||
exists(Typ t0 |
|
||||
typeStrengthen(t0, cons, t2) and
|
||||
fwdFlowConsCand(t0, cons, c, t1, tail)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -1359,7 +1368,7 @@ module Impl<FullStateConfigSig Config> {
|
||||
ParamNodeOption summaryCtx, TypOption argT, ApOption argAp
|
||||
) {
|
||||
exists(ApHeadContent apc |
|
||||
fwdFlow(node1, state, cc, summaryCtx, argT, argAp, t, ap) and
|
||||
fwdFlow(node1, state, cc, summaryCtx, argT, argAp, t, ap, _) and
|
||||
apc = getHeadContent(ap) and
|
||||
readStepCand0(node1, apc, c, node2)
|
||||
)
|
||||
@@ -1520,14 +1529,14 @@ module Impl<FullStateConfigSig Config> {
|
||||
NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
||||
) {
|
||||
revFlow0(node, state, returnCtx, returnAp, ap) and
|
||||
fwdFlow(node, state, _, _, _, _, _, ap)
|
||||
fwdFlow(node, state, _, _, _, _, _, ap, _)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlow0(
|
||||
NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
||||
) {
|
||||
fwdFlow(node, state, _, _, _, _, _, ap) and
|
||||
fwdFlow(node, state, _, _, _, _, _, ap, _) and
|
||||
sinkNode(node, state) and
|
||||
(
|
||||
if hasSinkCallCtx()
|
||||
@@ -1780,13 +1789,13 @@ module Impl<FullStateConfigSig Config> {
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples
|
||||
) {
|
||||
fwd = true and
|
||||
nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, _, _)) and
|
||||
nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, _, _, _)) and
|
||||
fields = count(Content f0 | fwdConsCand(f0, _, _)) and
|
||||
conscand = count(Content f0, Typ t, Ap ap | fwdConsCand(f0, t, ap)) and
|
||||
states = count(FlowState state | fwdFlow(_, state, _, _, _, _, _, _)) and
|
||||
states = count(FlowState state | fwdFlow(_, state, _, _, _, _, _, _, _)) and
|
||||
tuples =
|
||||
count(NodeEx n, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT,
|
||||
ApOption argAp, Typ t, Ap ap | fwdFlow(n, state, cc, summaryCtx, argT, argAp, t, ap))
|
||||
ApOption argAp, Typ t, Ap ap | fwdFlow(n, state, cc, summaryCtx, argT, argAp, t, ap, _))
|
||||
or
|
||||
fwd = false and
|
||||
nodes = count(NodeEx node | revFlow(node, _, _, _, _)) and
|
||||
@@ -1963,10 +1972,10 @@ module Impl<FullStateConfigSig Config> {
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[node, state, t, ap]
|
||||
predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) {
|
||||
bindingset[node, state, t0, ap]
|
||||
predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) {
|
||||
PrevStage::revFlowState(state) and
|
||||
exists(t) and
|
||||
t0 = t and
|
||||
exists(ap) and
|
||||
not stateBarrier(node, state) and
|
||||
(
|
||||
@@ -2012,7 +2021,8 @@ module Impl<FullStateConfigSig Config> {
|
||||
FlowCheckNode() {
|
||||
castNode(this.asNode()) or
|
||||
clearsContentCached(this.asNode(), _) or
|
||||
expectsContentCached(this.asNode(), _)
|
||||
expectsContentCached(this.asNode(), _) or
|
||||
neverSkipInPathGraph(this.asNode())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2197,8 +2207,8 @@ module Impl<FullStateConfigSig Config> {
|
||||
import BooleanCallContext
|
||||
|
||||
predicate localStep(
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||
DataFlowType t, LocalCc lcc
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, Typ t,
|
||||
LocalCc lcc
|
||||
) {
|
||||
localFlowBigStep(node1, state1, node2, state2, preservesValue, t, _) and
|
||||
exists(lcc)
|
||||
@@ -2218,10 +2228,16 @@ module Impl<FullStateConfigSig Config> {
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[node, state, t, ap]
|
||||
predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) {
|
||||
bindingset[node, state, t0, ap]
|
||||
predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) {
|
||||
exists(state) and
|
||||
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) and
|
||||
// We can get away with not using type strengthening here, since we aren't
|
||||
// going to use the tracked types in the construction of Stage 4 access
|
||||
// paths. For Stage 4 and onwards, the tracked types must be consistent as
|
||||
// the cons candidates including types are used to construct subsequent
|
||||
// access path approximations.
|
||||
t0 = t and
|
||||
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t0) else any()) and
|
||||
(
|
||||
notExpectsContent(node)
|
||||
or
|
||||
@@ -2241,6 +2257,16 @@ module Impl<FullStateConfigSig Config> {
|
||||
import MkStage<Stage2>::Stage<Stage3Param>
|
||||
}
|
||||
|
||||
bindingset[node, t0]
|
||||
private predicate strengthenType(NodeEx node, DataFlowType t0, DataFlowType t) {
|
||||
if castingNodeEx(node)
|
||||
then
|
||||
exists(DataFlowType nt | nt = node.getDataFlowType() |
|
||||
if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0)
|
||||
)
|
||||
else t = t0
|
||||
}
|
||||
|
||||
private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||
private module PrevStage = Stage3;
|
||||
|
||||
@@ -2274,8 +2300,8 @@ module Impl<FullStateConfigSig Config> {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate localStep(
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||
DataFlowType t, LocalCc lcc
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, Typ t,
|
||||
LocalCc lcc
|
||||
) {
|
||||
localFlowBigStep(node1, state1, node2, state2, preservesValue, t, _) and
|
||||
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _) and
|
||||
@@ -2333,11 +2359,11 @@ module Impl<FullStateConfigSig Config> {
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[node, state, t, ap]
|
||||
predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) {
|
||||
bindingset[node, state, t0, ap]
|
||||
predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) {
|
||||
exists(state) and
|
||||
not clear(node, ap) and
|
||||
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) and
|
||||
strengthenType(node, t0, t) and
|
||||
(
|
||||
notExpectsContent(node)
|
||||
or
|
||||
@@ -2365,7 +2391,7 @@ module Impl<FullStateConfigSig Config> {
|
||||
exists(AccessPathFront apf |
|
||||
Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf) and
|
||||
Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, _, TAccessPathFrontSome(argApf), _,
|
||||
apf)
|
||||
apf, _)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2579,8 +2605,8 @@ module Impl<FullStateConfigSig Config> {
|
||||
import LocalCallContext
|
||||
|
||||
predicate localStep(
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||
DataFlowType t, LocalCc lcc
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, Typ t,
|
||||
LocalCc lcc
|
||||
) {
|
||||
localFlowBigStep(node1, state1, node2, state2, preservesValue, t, lcc) and
|
||||
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _) and
|
||||
@@ -2609,9 +2635,9 @@ module Impl<FullStateConfigSig Config> {
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[node, state, t, ap]
|
||||
predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) {
|
||||
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) and
|
||||
bindingset[node, state, t0, ap]
|
||||
predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) {
|
||||
strengthenType(node, t0, t) and
|
||||
exists(state) and
|
||||
exists(ap)
|
||||
}
|
||||
@@ -2632,7 +2658,7 @@ module Impl<FullStateConfigSig Config> {
|
||||
Stage5::parameterMayFlowThrough(p, _) and
|
||||
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0) and
|
||||
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParamNodeSome(p.asNode()), _,
|
||||
TAccessPathApproxSome(apa), _, apa0)
|
||||
TAccessPathApproxSome(apa), _, apa0, _)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2649,7 +2675,7 @@ module Impl<FullStateConfigSig Config> {
|
||||
TSummaryCtxSome(ParamNodeEx p, FlowState state, DataFlowType t, AccessPath ap) {
|
||||
exists(AccessPathApprox apa | ap.getApprox() = apa |
|
||||
Stage5::parameterMayFlowThrough(p, apa) and
|
||||
Stage5::fwdFlow(p, state, _, _, _, _, t, apa) and
|
||||
Stage5::fwdFlow(p, state, _, _, Option<DataFlowType>::some(t), _, _, apa, _) and
|
||||
Stage5::revFlow(p, state, _)
|
||||
)
|
||||
}
|
||||
@@ -2820,9 +2846,7 @@ module Impl<FullStateConfigSig Config> {
|
||||
ap = TAccessPathNil()
|
||||
or
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
pathStep(_, node, state, cc, sc, t, ap) and
|
||||
Stage5::revFlow(node, state, ap.getApprox()) and
|
||||
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any())
|
||||
pathStep(_, node, state, cc, sc, t, ap)
|
||||
} or
|
||||
TPathNodeSink(NodeEx node, FlowState state) {
|
||||
exists(PathNodeMid sink |
|
||||
@@ -3340,13 +3364,24 @@ module Impl<FullStateConfigSig Config> {
|
||||
ap = mid.getAp()
|
||||
}
|
||||
|
||||
private predicate pathStep(
|
||||
PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, DataFlowType t,
|
||||
AccessPath ap
|
||||
) {
|
||||
exists(DataFlowType t0 |
|
||||
pathStep0(mid, node, state, cc, sc, t0, ap) and
|
||||
Stage5::revFlow(node, state, ap.getApprox()) and
|
||||
strengthenType(node, t0, t)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `mid` to `node`. The last step in or out of
|
||||
* a callable is recorded by `cc`.
|
||||
*/
|
||||
pragma[assume_small_delta]
|
||||
pragma[nomagic]
|
||||
private predicate pathStep(
|
||||
private predicate pathStep0(
|
||||
PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, DataFlowType t,
|
||||
AccessPath ap
|
||||
) {
|
||||
@@ -3964,7 +3999,7 @@ module Impl<FullStateConfigSig Config> {
|
||||
ap = TPartialNil() and
|
||||
exists(explorationLimit())
|
||||
or
|
||||
partialPathNodeMk0(node, state, cc, sc1, sc2, sc3, sc4, t, ap) and
|
||||
partialPathStep(_, node, state, cc, sc1, sc2, sc3, sc4, t, ap) and
|
||||
distSrc(node.getEnclosingCallable()) <= explorationLimit()
|
||||
} or
|
||||
TPartialPathNodeRev(
|
||||
@@ -3990,11 +4025,20 @@ module Impl<FullStateConfigSig Config> {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate partialPathNodeMk0(
|
||||
NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
|
||||
TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap
|
||||
private predicate partialPathStep(
|
||||
PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1,
|
||||
TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap
|
||||
) {
|
||||
partialPathStep(_, node, state, cc, sc1, sc2, sc3, sc4, t, ap) and
|
||||
partialPathStep1(mid, node, state, cc, sc1, sc2, sc3, sc4, _, t, ap)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate partialPathStep1(
|
||||
PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1,
|
||||
TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t0, DataFlowType t,
|
||||
PartialAccessPath ap
|
||||
) {
|
||||
partialPathStep0(mid, node, state, cc, sc1, sc2, sc3, sc4, t0, ap) and
|
||||
not fullBarrier(node) and
|
||||
not stateBarrier(node, state) and
|
||||
not clearsContentEx(node, ap.getHead()) and
|
||||
@@ -4002,9 +4046,14 @@ module Impl<FullStateConfigSig Config> {
|
||||
notExpectsContent(node) or
|
||||
expectsContentEx(node, ap.getHead())
|
||||
) and
|
||||
if node.asNode() instanceof CastingNode
|
||||
then compatibleTypes(node.getDataFlowType(), t)
|
||||
else any()
|
||||
strengthenType(node, t0, t)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate partialPathTypeStrengthen(
|
||||
DataFlowType t0, PartialAccessPath ap, DataFlowType t
|
||||
) {
|
||||
partialPathStep1(_, _, _, _, _, _, _, _, t0, t, ap) and t0 != t
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -4183,7 +4232,8 @@ module Impl<FullStateConfigSig Config> {
|
||||
}
|
||||
}
|
||||
|
||||
private predicate partialPathStep(
|
||||
pragma[nomagic]
|
||||
private predicate partialPathStep0(
|
||||
PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1,
|
||||
TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap
|
||||
) {
|
||||
@@ -4309,6 +4359,11 @@ module Impl<FullStateConfigSig Config> {
|
||||
DataFlowType t1, PartialAccessPath ap1, Content c, DataFlowType t2, PartialAccessPath ap2
|
||||
) {
|
||||
partialPathStoreStep(_, t1, ap1, c, _, t2, ap2)
|
||||
or
|
||||
exists(DataFlowType t0 |
|
||||
partialPathTypeStrengthen(t0, ap2, t2) and
|
||||
apConsFwd(t1, ap1, c, t0, ap2)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
|
||||
@@ -205,6 +205,8 @@ predicate clearsContent(Node n, Content c) {
|
||||
*/
|
||||
predicate expectsContent(Node n, ContentSet c) { none() }
|
||||
|
||||
predicate typeStrongerThan(DataFlowType t1, DataFlowType t2) { none() }
|
||||
|
||||
/** Gets the type of `n` used for type pruning. */
|
||||
Type getNodeType(Node n) {
|
||||
suppressUnusedNode(n) and
|
||||
@@ -233,6 +235,12 @@ class CastNode extends Node {
|
||||
CastNode() { none() } // stub implementation
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n` should never be skipped over in the `PathGraph` and in path
|
||||
* explanations.
|
||||
*/
|
||||
predicate neverSkipInPathGraph(Node n) { none() }
|
||||
|
||||
class DataFlowCallable = Function;
|
||||
|
||||
class DataFlowExpr = Expr;
|
||||
|
||||
@@ -1135,8 +1135,8 @@ module Impl<FullStateConfigSig Config> {
|
||||
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow
|
||||
);
|
||||
|
||||
bindingset[node, state, t, ap]
|
||||
predicate filter(NodeEx node, FlowState state, Typ t, Ap ap);
|
||||
bindingset[node, state, t0, ap]
|
||||
predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t);
|
||||
|
||||
bindingset[typ, contentType]
|
||||
predicate typecheckStore(Typ typ, DataFlowType contentType);
|
||||
@@ -1199,17 +1199,21 @@ module Impl<FullStateConfigSig Config> {
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT,
|
||||
ApOption argAp, Typ t, Ap ap, ApApprox apa
|
||||
) {
|
||||
fwdFlow0(node, state, cc, summaryCtx, argT, argAp, t, ap, apa) and
|
||||
PrevStage::revFlow(node, state, apa) and
|
||||
filter(node, state, t, ap)
|
||||
fwdFlow1(node, state, cc, summaryCtx, argT, argAp, _, t, ap, apa)
|
||||
}
|
||||
|
||||
pragma[inline]
|
||||
additional predicate fwdFlow(
|
||||
private predicate fwdFlow1(
|
||||
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT,
|
||||
ApOption argAp, Typ t, Ap ap
|
||||
ApOption argAp, Typ t0, Typ t, Ap ap, ApApprox apa
|
||||
) {
|
||||
fwdFlow(node, state, cc, summaryCtx, argT, argAp, t, ap, _)
|
||||
fwdFlow0(node, state, cc, summaryCtx, argT, argAp, t0, ap, apa) and
|
||||
PrevStage::revFlow(node, state, apa) and
|
||||
filter(node, state, t0, ap, t)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate typeStrengthen(Typ t0, Ap ap, Typ t) {
|
||||
fwdFlow1(_, _, _, _, _, _, t0, t, ap, _) and t0 != t
|
||||
}
|
||||
|
||||
pragma[assume_small_delta]
|
||||
@@ -1339,6 +1343,11 @@ module Impl<FullStateConfigSig Config> {
|
||||
private predicate fwdFlowConsCand(Typ t2, Ap cons, Content c, Typ t1, Ap tail) {
|
||||
fwdFlowStore(_, t1, tail, c, t2, _, _, _, _, _, _) and
|
||||
cons = apCons(c, t1, tail)
|
||||
or
|
||||
exists(Typ t0 |
|
||||
typeStrengthen(t0, cons, t2) and
|
||||
fwdFlowConsCand(t0, cons, c, t1, tail)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -1359,7 +1368,7 @@ module Impl<FullStateConfigSig Config> {
|
||||
ParamNodeOption summaryCtx, TypOption argT, ApOption argAp
|
||||
) {
|
||||
exists(ApHeadContent apc |
|
||||
fwdFlow(node1, state, cc, summaryCtx, argT, argAp, t, ap) and
|
||||
fwdFlow(node1, state, cc, summaryCtx, argT, argAp, t, ap, _) and
|
||||
apc = getHeadContent(ap) and
|
||||
readStepCand0(node1, apc, c, node2)
|
||||
)
|
||||
@@ -1520,14 +1529,14 @@ module Impl<FullStateConfigSig Config> {
|
||||
NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
||||
) {
|
||||
revFlow0(node, state, returnCtx, returnAp, ap) and
|
||||
fwdFlow(node, state, _, _, _, _, _, ap)
|
||||
fwdFlow(node, state, _, _, _, _, _, ap, _)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate revFlow0(
|
||||
NodeEx node, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap
|
||||
) {
|
||||
fwdFlow(node, state, _, _, _, _, _, ap) and
|
||||
fwdFlow(node, state, _, _, _, _, _, ap, _) and
|
||||
sinkNode(node, state) and
|
||||
(
|
||||
if hasSinkCallCtx()
|
||||
@@ -1780,13 +1789,13 @@ module Impl<FullStateConfigSig Config> {
|
||||
boolean fwd, int nodes, int fields, int conscand, int states, int tuples
|
||||
) {
|
||||
fwd = true and
|
||||
nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, _, _)) and
|
||||
nodes = count(NodeEx node | fwdFlow(node, _, _, _, _, _, _, _, _)) and
|
||||
fields = count(Content f0 | fwdConsCand(f0, _, _)) and
|
||||
conscand = count(Content f0, Typ t, Ap ap | fwdConsCand(f0, t, ap)) and
|
||||
states = count(FlowState state | fwdFlow(_, state, _, _, _, _, _, _)) and
|
||||
states = count(FlowState state | fwdFlow(_, state, _, _, _, _, _, _, _)) and
|
||||
tuples =
|
||||
count(NodeEx n, FlowState state, Cc cc, ParamNodeOption summaryCtx, TypOption argT,
|
||||
ApOption argAp, Typ t, Ap ap | fwdFlow(n, state, cc, summaryCtx, argT, argAp, t, ap))
|
||||
ApOption argAp, Typ t, Ap ap | fwdFlow(n, state, cc, summaryCtx, argT, argAp, t, ap, _))
|
||||
or
|
||||
fwd = false and
|
||||
nodes = count(NodeEx node | revFlow(node, _, _, _, _)) and
|
||||
@@ -1963,10 +1972,10 @@ module Impl<FullStateConfigSig Config> {
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[node, state, t, ap]
|
||||
predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) {
|
||||
bindingset[node, state, t0, ap]
|
||||
predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) {
|
||||
PrevStage::revFlowState(state) and
|
||||
exists(t) and
|
||||
t0 = t and
|
||||
exists(ap) and
|
||||
not stateBarrier(node, state) and
|
||||
(
|
||||
@@ -2012,7 +2021,8 @@ module Impl<FullStateConfigSig Config> {
|
||||
FlowCheckNode() {
|
||||
castNode(this.asNode()) or
|
||||
clearsContentCached(this.asNode(), _) or
|
||||
expectsContentCached(this.asNode(), _)
|
||||
expectsContentCached(this.asNode(), _) or
|
||||
neverSkipInPathGraph(this.asNode())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2197,8 +2207,8 @@ module Impl<FullStateConfigSig Config> {
|
||||
import BooleanCallContext
|
||||
|
||||
predicate localStep(
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||
DataFlowType t, LocalCc lcc
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, Typ t,
|
||||
LocalCc lcc
|
||||
) {
|
||||
localFlowBigStep(node1, state1, node2, state2, preservesValue, t, _) and
|
||||
exists(lcc)
|
||||
@@ -2218,10 +2228,16 @@ module Impl<FullStateConfigSig Config> {
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[node, state, t, ap]
|
||||
predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) {
|
||||
bindingset[node, state, t0, ap]
|
||||
predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) {
|
||||
exists(state) and
|
||||
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) and
|
||||
// We can get away with not using type strengthening here, since we aren't
|
||||
// going to use the tracked types in the construction of Stage 4 access
|
||||
// paths. For Stage 4 and onwards, the tracked types must be consistent as
|
||||
// the cons candidates including types are used to construct subsequent
|
||||
// access path approximations.
|
||||
t0 = t and
|
||||
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t0) else any()) and
|
||||
(
|
||||
notExpectsContent(node)
|
||||
or
|
||||
@@ -2241,6 +2257,16 @@ module Impl<FullStateConfigSig Config> {
|
||||
import MkStage<Stage2>::Stage<Stage3Param>
|
||||
}
|
||||
|
||||
bindingset[node, t0]
|
||||
private predicate strengthenType(NodeEx node, DataFlowType t0, DataFlowType t) {
|
||||
if castingNodeEx(node)
|
||||
then
|
||||
exists(DataFlowType nt | nt = node.getDataFlowType() |
|
||||
if typeStrongerThan(nt, t0) then t = nt else (compatibleTypes(nt, t0) and t = t0)
|
||||
)
|
||||
else t = t0
|
||||
}
|
||||
|
||||
private module Stage4Param implements MkStage<Stage3>::StageParam {
|
||||
private module PrevStage = Stage3;
|
||||
|
||||
@@ -2274,8 +2300,8 @@ module Impl<FullStateConfigSig Config> {
|
||||
|
||||
pragma[nomagic]
|
||||
predicate localStep(
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||
DataFlowType t, LocalCc lcc
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, Typ t,
|
||||
LocalCc lcc
|
||||
) {
|
||||
localFlowBigStep(node1, state1, node2, state2, preservesValue, t, _) and
|
||||
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _) and
|
||||
@@ -2333,11 +2359,11 @@ module Impl<FullStateConfigSig Config> {
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[node, state, t, ap]
|
||||
predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) {
|
||||
bindingset[node, state, t0, ap]
|
||||
predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) {
|
||||
exists(state) and
|
||||
not clear(node, ap) and
|
||||
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) and
|
||||
strengthenType(node, t0, t) and
|
||||
(
|
||||
notExpectsContent(node)
|
||||
or
|
||||
@@ -2365,7 +2391,7 @@ module Impl<FullStateConfigSig Config> {
|
||||
exists(AccessPathFront apf |
|
||||
Stage4::revFlow(node, state, TReturnCtxMaybeFlowThrough(_), _, apf) and
|
||||
Stage4::fwdFlow(node, state, any(Stage4::CcCall ccc), _, _, TAccessPathFrontSome(argApf), _,
|
||||
apf)
|
||||
apf, _)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2579,8 +2605,8 @@ module Impl<FullStateConfigSig Config> {
|
||||
import LocalCallContext
|
||||
|
||||
predicate localStep(
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||
DataFlowType t, LocalCc lcc
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue, Typ t,
|
||||
LocalCc lcc
|
||||
) {
|
||||
localFlowBigStep(node1, state1, node2, state2, preservesValue, t, lcc) and
|
||||
PrevStage::revFlow(node1, pragma[only_bind_into](state1), _) and
|
||||
@@ -2609,9 +2635,9 @@ module Impl<FullStateConfigSig Config> {
|
||||
)
|
||||
}
|
||||
|
||||
bindingset[node, state, t, ap]
|
||||
predicate filter(NodeEx node, FlowState state, Typ t, Ap ap) {
|
||||
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any()) and
|
||||
bindingset[node, state, t0, ap]
|
||||
predicate filter(NodeEx node, FlowState state, Typ t0, Ap ap, Typ t) {
|
||||
strengthenType(node, t0, t) and
|
||||
exists(state) and
|
||||
exists(ap)
|
||||
}
|
||||
@@ -2632,7 +2658,7 @@ module Impl<FullStateConfigSig Config> {
|
||||
Stage5::parameterMayFlowThrough(p, _) and
|
||||
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0) and
|
||||
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParamNodeSome(p.asNode()), _,
|
||||
TAccessPathApproxSome(apa), _, apa0)
|
||||
TAccessPathApproxSome(apa), _, apa0, _)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2649,7 +2675,7 @@ module Impl<FullStateConfigSig Config> {
|
||||
TSummaryCtxSome(ParamNodeEx p, FlowState state, DataFlowType t, AccessPath ap) {
|
||||
exists(AccessPathApprox apa | ap.getApprox() = apa |
|
||||
Stage5::parameterMayFlowThrough(p, apa) and
|
||||
Stage5::fwdFlow(p, state, _, _, _, _, t, apa) and
|
||||
Stage5::fwdFlow(p, state, _, _, Option<DataFlowType>::some(t), _, _, apa, _) and
|
||||
Stage5::revFlow(p, state, _)
|
||||
)
|
||||
}
|
||||
@@ -2820,9 +2846,7 @@ module Impl<FullStateConfigSig Config> {
|
||||
ap = TAccessPathNil()
|
||||
or
|
||||
// ... or a step from an existing PathNode to another node.
|
||||
pathStep(_, node, state, cc, sc, t, ap) and
|
||||
Stage5::revFlow(node, state, ap.getApprox()) and
|
||||
(if castingNodeEx(node) then compatibleTypes(node.getDataFlowType(), t) else any())
|
||||
pathStep(_, node, state, cc, sc, t, ap)
|
||||
} or
|
||||
TPathNodeSink(NodeEx node, FlowState state) {
|
||||
exists(PathNodeMid sink |
|
||||
@@ -3340,13 +3364,24 @@ module Impl<FullStateConfigSig Config> {
|
||||
ap = mid.getAp()
|
||||
}
|
||||
|
||||
private predicate pathStep(
|
||||
PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, DataFlowType t,
|
||||
AccessPath ap
|
||||
) {
|
||||
exists(DataFlowType t0 |
|
||||
pathStep0(mid, node, state, cc, sc, t0, ap) and
|
||||
Stage5::revFlow(node, state, ap.getApprox()) and
|
||||
strengthenType(node, t0, t)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if data may flow from `mid` to `node`. The last step in or out of
|
||||
* a callable is recorded by `cc`.
|
||||
*/
|
||||
pragma[assume_small_delta]
|
||||
pragma[nomagic]
|
||||
private predicate pathStep(
|
||||
private predicate pathStep0(
|
||||
PathNodeMid mid, NodeEx node, FlowState state, CallContext cc, SummaryCtx sc, DataFlowType t,
|
||||
AccessPath ap
|
||||
) {
|
||||
@@ -3964,7 +3999,7 @@ module Impl<FullStateConfigSig Config> {
|
||||
ap = TPartialNil() and
|
||||
exists(explorationLimit())
|
||||
or
|
||||
partialPathNodeMk0(node, state, cc, sc1, sc2, sc3, sc4, t, ap) and
|
||||
partialPathStep(_, node, state, cc, sc1, sc2, sc3, sc4, t, ap) and
|
||||
distSrc(node.getEnclosingCallable()) <= explorationLimit()
|
||||
} or
|
||||
TPartialPathNodeRev(
|
||||
@@ -3990,11 +4025,20 @@ module Impl<FullStateConfigSig Config> {
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate partialPathNodeMk0(
|
||||
NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
|
||||
TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap
|
||||
private predicate partialPathStep(
|
||||
PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1,
|
||||
TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap
|
||||
) {
|
||||
partialPathStep(_, node, state, cc, sc1, sc2, sc3, sc4, t, ap) and
|
||||
partialPathStep1(mid, node, state, cc, sc1, sc2, sc3, sc4, _, t, ap)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate partialPathStep1(
|
||||
PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1,
|
||||
TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t0, DataFlowType t,
|
||||
PartialAccessPath ap
|
||||
) {
|
||||
partialPathStep0(mid, node, state, cc, sc1, sc2, sc3, sc4, t0, ap) and
|
||||
not fullBarrier(node) and
|
||||
not stateBarrier(node, state) and
|
||||
not clearsContentEx(node, ap.getHead()) and
|
||||
@@ -4002,9 +4046,14 @@ module Impl<FullStateConfigSig Config> {
|
||||
notExpectsContent(node) or
|
||||
expectsContentEx(node, ap.getHead())
|
||||
) and
|
||||
if node.asNode() instanceof CastingNode
|
||||
then compatibleTypes(node.getDataFlowType(), t)
|
||||
else any()
|
||||
strengthenType(node, t0, t)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate partialPathTypeStrengthen(
|
||||
DataFlowType t0, PartialAccessPath ap, DataFlowType t
|
||||
) {
|
||||
partialPathStep1(_, _, _, _, _, _, _, _, t0, t, ap) and t0 != t
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -4183,7 +4232,8 @@ module Impl<FullStateConfigSig Config> {
|
||||
}
|
||||
}
|
||||
|
||||
private predicate partialPathStep(
|
||||
pragma[nomagic]
|
||||
private predicate partialPathStep0(
|
||||
PartialPathNodeFwd mid, NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1,
|
||||
TSummaryCtx2 sc2, TSummaryCtx3 sc3, TSummaryCtx4 sc4, DataFlowType t, PartialAccessPath ap
|
||||
) {
|
||||
@@ -4309,6 +4359,11 @@ module Impl<FullStateConfigSig Config> {
|
||||
DataFlowType t1, PartialAccessPath ap1, Content c, DataFlowType t2, PartialAccessPath ap2
|
||||
) {
|
||||
partialPathStoreStep(_, t1, ap1, c, _, t2, ap2)
|
||||
or
|
||||
exists(DataFlowType t0 |
|
||||
partialPathTypeStrengthen(t0, ap2, t2) and
|
||||
apConsFwd(t1, ap1, c, t0, ap2)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
|
||||
@@ -193,86 +193,89 @@ private class SingleUseOperandNode0 extends OperandNode0, TSingleUseOperandNode0
|
||||
SingleUseOperandNode0() { this = TSingleUseOperandNode0(op) }
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*
|
||||
* A node that represents the indirect value of an operand in the IR
|
||||
* after `index` number of loads.
|
||||
*
|
||||
* Note: Unlike `RawIndirectOperand`, a value of type `IndirectOperand` may
|
||||
* be an `OperandNode`.
|
||||
*/
|
||||
class IndirectOperand extends Node {
|
||||
Operand operand;
|
||||
int indirectionIndex;
|
||||
|
||||
IndirectOperand() {
|
||||
this.(RawIndirectOperand).getOperand() = operand and
|
||||
this.(RawIndirectOperand).getIndirectionIndex() = indirectionIndex
|
||||
or
|
||||
nodeHasOperand(this, Ssa::getIRRepresentationOfIndirectOperand(operand, indirectionIndex),
|
||||
indirectionIndex - 1)
|
||||
private module IndirectOperands {
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*
|
||||
* A node that represents the indirect value of an operand in the IR
|
||||
* after `index` number of loads.
|
||||
*
|
||||
* Note: Unlike `RawIndirectOperand`, a value of type `IndirectOperand` may
|
||||
* be an `OperandNode`.
|
||||
*/
|
||||
abstract class IndirectOperand extends Node {
|
||||
/** Gets the underlying operand and the underlying indirection index. */
|
||||
abstract predicate hasOperandAndIndirectionIndex(Operand operand, int indirectionIndex);
|
||||
}
|
||||
|
||||
/** Gets the underlying operand. */
|
||||
Operand getOperand() { result = operand }
|
||||
private class IndirectOperandFromRaw extends IndirectOperand instanceof RawIndirectOperand {
|
||||
override predicate hasOperandAndIndirectionIndex(Operand operand, int indirectionIndex) {
|
||||
operand = RawIndirectOperand.super.getOperand() and
|
||||
indirectionIndex = RawIndirectOperand.super.getIndirectionIndex()
|
||||
}
|
||||
}
|
||||
|
||||
/** Gets the underlying indirection index. */
|
||||
int getIndirectionIndex() { result = indirectionIndex }
|
||||
private class IndirectOperandFromIRRepr extends IndirectOperand {
|
||||
Operand operand;
|
||||
int indirectionIndex;
|
||||
|
||||
/**
|
||||
* Holds if this `IndirectOperand` is represented directly in the IR instead of
|
||||
* a `RawIndirectionOperand` with operand `op` and indirection index `index`.
|
||||
*/
|
||||
predicate isIRRepresentationOf(Operand op, int index) {
|
||||
this instanceof OperandNode and
|
||||
(
|
||||
op = operand and
|
||||
index = indirectionIndex
|
||||
)
|
||||
IndirectOperandFromIRRepr() {
|
||||
exists(Operand repr |
|
||||
repr = Ssa::getIRRepresentationOfIndirectOperand(operand, indirectionIndex) and
|
||||
nodeHasOperand(this, repr, indirectionIndex - 1)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate hasOperandAndIndirectionIndex(Operand op, int index) {
|
||||
op = operand and index = indirectionIndex
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*
|
||||
* A node that represents the indirect value of an instruction in the IR
|
||||
* after `index` number of loads.
|
||||
*
|
||||
* Note: Unlike `RawIndirectInstruction`, a value of type `IndirectInstruction` may
|
||||
* be an `InstructionNode`.
|
||||
*/
|
||||
class IndirectInstruction extends Node {
|
||||
Instruction instr;
|
||||
int indirectionIndex;
|
||||
import IndirectOperands
|
||||
|
||||
IndirectInstruction() {
|
||||
this.(RawIndirectInstruction).getInstruction() = instr and
|
||||
this.(RawIndirectInstruction).getIndirectionIndex() = indirectionIndex
|
||||
or
|
||||
nodeHasInstruction(this, Ssa::getIRRepresentationOfIndirectInstruction(instr, indirectionIndex),
|
||||
indirectionIndex - 1)
|
||||
private module IndirectInstructions {
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*
|
||||
* A node that represents the indirect value of an instruction in the IR
|
||||
* after `index` number of loads.
|
||||
*
|
||||
* Note: Unlike `RawIndirectInstruction`, a value of type `IndirectInstruction` may
|
||||
* be an `InstructionNode`.
|
||||
*/
|
||||
abstract class IndirectInstruction extends Node {
|
||||
/** Gets the underlying operand and the underlying indirection index. */
|
||||
abstract predicate hasInstructionAndIndirectionIndex(Instruction instr, int index);
|
||||
}
|
||||
|
||||
/** Gets the underlying instruction. */
|
||||
Instruction getInstruction() { result = instr }
|
||||
private class IndirectInstructionFromRaw extends IndirectInstruction instanceof RawIndirectInstruction
|
||||
{
|
||||
override predicate hasInstructionAndIndirectionIndex(Instruction instr, int index) {
|
||||
instr = RawIndirectInstruction.super.getInstruction() and
|
||||
index = RawIndirectInstruction.super.getIndirectionIndex()
|
||||
}
|
||||
}
|
||||
|
||||
/** Gets the underlying indirection index. */
|
||||
int getIndirectionIndex() { result = indirectionIndex }
|
||||
private class IndirectInstructionFromIRRepr extends IndirectInstruction {
|
||||
Instruction instr;
|
||||
int indirectionIndex;
|
||||
|
||||
/**
|
||||
* Holds if this `IndirectInstruction` is represented directly in the IR instead of
|
||||
* a `RawIndirectionInstruction` with instruction `i` and indirection index `index`.
|
||||
*/
|
||||
predicate isIRRepresentationOf(Instruction i, int index) {
|
||||
this instanceof InstructionNode and
|
||||
(
|
||||
i = instr and
|
||||
index = indirectionIndex
|
||||
)
|
||||
IndirectInstructionFromIRRepr() {
|
||||
exists(Instruction repr |
|
||||
repr = Ssa::getIRRepresentationOfIndirectInstruction(instr, indirectionIndex) and
|
||||
nodeHasInstruction(this, repr, indirectionIndex - 1)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate hasInstructionAndIndirectionIndex(Instruction i, int index) {
|
||||
i = instr and index = indirectionIndex
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
import IndirectInstructions
|
||||
|
||||
/** Gets the callable in which this node occurs. */
|
||||
DataFlowCallable nodeGetEnclosingCallable(Node n) { result = n.getEnclosingCallable() }
|
||||
|
||||
@@ -320,7 +323,7 @@ private class SideEffectArgumentNode extends ArgumentNode, SideEffectOperandNode
|
||||
override predicate argumentOf(DataFlowCall dfCall, ArgumentPosition pos) {
|
||||
this.getCallInstruction() = dfCall and
|
||||
pos.(IndirectionPosition).getArgumentIndex() = this.getArgumentIndex() and
|
||||
pos.(IndirectionPosition).getIndirectionIndex() = super.getIndirectionIndex()
|
||||
super.hasAddressOperandAndIndirectionIndex(_, pos.(IndirectionPosition).getIndirectionIndex())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -753,6 +756,8 @@ predicate clearsContent(Node n, Content c) {
|
||||
*/
|
||||
predicate expectsContent(Node n, ContentSet c) { none() }
|
||||
|
||||
predicate typeStrongerThan(DataFlowType t1, DataFlowType t2) { none() }
|
||||
|
||||
/** Gets the type of `n` used for type pruning. */
|
||||
DataFlowType getNodeType(Node n) {
|
||||
suppressUnusedNode(n) and
|
||||
@@ -781,6 +786,12 @@ class CastNode extends Node {
|
||||
CastNode() { none() } // stub implementation
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `n` should never be skipped over in the `PathGraph` and in path
|
||||
* explanations.
|
||||
*/
|
||||
predicate neverSkipInPathGraph(Node n) { none() }
|
||||
|
||||
/**
|
||||
* A function that may contain code or a variable that may contain itself. When
|
||||
* flow crosses from one _enclosing callable_ to another, the interprocedural
|
||||
@@ -837,7 +848,7 @@ predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preserves
|
||||
* One example would be to allow flow like `p.foo = p.bar;`, which is disallowed
|
||||
* by default as a heuristic.
|
||||
*/
|
||||
predicate allowParameterReturnInSelf(ParameterNode p) { none() }
|
||||
predicate allowParameterReturnInSelf(ParameterNode p) { p instanceof IndirectParameterNode }
|
||||
|
||||
private predicate fieldHasApproxName(Field f, string s) {
|
||||
s = f.getName().charAt(0) and
|
||||
|
||||
@@ -274,7 +274,7 @@ class Node extends TIRDataFlowNode {
|
||||
* represents the value of `**x` going into `f`.
|
||||
*/
|
||||
Expr asIndirectArgument(int index) {
|
||||
this.(SideEffectOperandNode).getIndirectionIndex() = index and
|
||||
this.(SideEffectOperandNode).hasAddressOperandAndIndirectionIndex(_, index) and
|
||||
result = this.(SideEffectOperandNode).getArgument()
|
||||
}
|
||||
|
||||
@@ -317,7 +317,7 @@ class Node extends TIRDataFlowNode {
|
||||
index = 0 and
|
||||
result = this.(ExplicitParameterNode).getParameter()
|
||||
or
|
||||
this.(IndirectParameterNode).getIndirectionIndex() = index and
|
||||
this.(IndirectParameterNode).hasInstructionAndIndirectionIndex(_, index) and
|
||||
result = this.(IndirectParameterNode).getParameter()
|
||||
}
|
||||
|
||||
@@ -577,15 +577,20 @@ class SsaPhiNode extends Node, TSsaPhiNode {
|
||||
*
|
||||
* A node representing a value after leaving a function.
|
||||
*/
|
||||
class SideEffectOperandNode extends Node, IndirectOperand {
|
||||
class SideEffectOperandNode extends Node instanceof IndirectOperand {
|
||||
CallInstruction call;
|
||||
int argumentIndex;
|
||||
|
||||
SideEffectOperandNode() { operand = call.getArgumentOperand(argumentIndex) }
|
||||
SideEffectOperandNode() {
|
||||
IndirectOperand.super.hasOperandAndIndirectionIndex(call.getArgumentOperand(argumentIndex), _)
|
||||
}
|
||||
|
||||
CallInstruction getCallInstruction() { result = call }
|
||||
|
||||
Operand getAddressOperand() { result = operand }
|
||||
/** Gets the underlying operand and the underlying indirection index. */
|
||||
predicate hasAddressOperandAndIndirectionIndex(Operand operand, int indirectionIndex) {
|
||||
IndirectOperand.super.hasOperandAndIndirectionIndex(operand, indirectionIndex)
|
||||
}
|
||||
|
||||
int getArgumentIndex() { result = argumentIndex }
|
||||
|
||||
@@ -665,10 +670,10 @@ class InitialGlobalValue extends Node, TInitialGlobalValue {
|
||||
*
|
||||
* A node representing an indirection of a parameter.
|
||||
*/
|
||||
class IndirectParameterNode extends Node, IndirectInstruction {
|
||||
class IndirectParameterNode extends Node instanceof IndirectInstruction {
|
||||
InitializeParameterInstruction init;
|
||||
|
||||
IndirectParameterNode() { this.getInstruction() = init }
|
||||
IndirectParameterNode() { IndirectInstruction.super.hasInstructionAndIndirectionIndex(init, _) }
|
||||
|
||||
int getArgumentIndex() { init.hasIndex(result) }
|
||||
|
||||
@@ -677,7 +682,12 @@ class IndirectParameterNode extends Node, IndirectInstruction {
|
||||
|
||||
override Declaration getEnclosingCallable() { result = this.getFunction() }
|
||||
|
||||
override Declaration getFunction() { result = this.getInstruction().getEnclosingFunction() }
|
||||
override Declaration getFunction() { result = init.getEnclosingFunction() }
|
||||
|
||||
/** Gets the underlying operand and the underlying indirection index. */
|
||||
predicate hasInstructionAndIndirectionIndex(Instruction instr, int index) {
|
||||
IndirectInstruction.super.hasInstructionAndIndirectionIndex(instr, index)
|
||||
}
|
||||
|
||||
override Location getLocationImpl() { result = this.getParameter().getLocation() }
|
||||
|
||||
@@ -699,7 +709,8 @@ class IndirectReturnNode extends Node {
|
||||
IndirectReturnNode() {
|
||||
this instanceof FinalParameterNode
|
||||
or
|
||||
this.(IndirectOperand).getOperand() = any(ReturnValueInstruction ret).getReturnAddressOperand()
|
||||
this.(IndirectOperand)
|
||||
.hasOperandAndIndirectionIndex(any(ReturnValueInstruction ret).getReturnAddressOperand(), _)
|
||||
}
|
||||
|
||||
override Declaration getEnclosingCallable() { result = this.getFunction() }
|
||||
@@ -722,7 +733,7 @@ class IndirectReturnNode extends Node {
|
||||
int getIndirectionIndex() {
|
||||
result = this.(FinalParameterNode).getIndirectionIndex()
|
||||
or
|
||||
result = this.(IndirectOperand).getIndirectionIndex()
|
||||
this.(IndirectOperand).hasOperandAndIndirectionIndex(_, result)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1106,7 +1117,8 @@ predicate exprNodeShouldBeInstruction(Node node, Expr e) {
|
||||
/** Holds if `node` should be an `IndirectInstruction` that maps `node.asIndirectExpr()` to `e`. */
|
||||
predicate indirectExprNodeShouldBeIndirectInstruction(IndirectInstruction node, Expr e) {
|
||||
exists(Instruction instr |
|
||||
instr = node.getInstruction() and not indirectExprNodeShouldBeIndirectOperand(_, e)
|
||||
node.hasInstructionAndIndirectionIndex(instr, _) and
|
||||
not indirectExprNodeShouldBeIndirectOperand(_, e)
|
||||
|
|
||||
e = instr.(VariableAddressInstruction).getAst().(Expr).getFullyConverted()
|
||||
or
|
||||
@@ -1307,8 +1319,8 @@ pragma[noinline]
|
||||
private predicate indirectParameterNodeHasArgumentIndexAndIndex(
|
||||
IndirectParameterNode node, int argumentIndex, int indirectionIndex
|
||||
) {
|
||||
node.getArgumentIndex() = argumentIndex and
|
||||
node.getIndirectionIndex() = indirectionIndex
|
||||
node.hasInstructionAndIndirectionIndex(_, indirectionIndex) and
|
||||
node.getArgumentIndex() = argumentIndex
|
||||
}
|
||||
|
||||
/** A synthetic parameter to model the pointed-to object of a pointer parameter. */
|
||||
@@ -1479,18 +1491,14 @@ VariableNode variableNode(Variable v) {
|
||||
*/
|
||||
Node uninitializedNode(LocalVariable v) { none() }
|
||||
|
||||
pragma[noinline]
|
||||
predicate hasOperandAndIndex(IndirectOperand indirectOperand, Operand operand, int indirectionIndex) {
|
||||
indirectOperand.getOperand() = operand and
|
||||
indirectOperand.getIndirectionIndex() = indirectionIndex
|
||||
indirectOperand.hasOperandAndIndirectionIndex(operand, indirectionIndex)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
predicate hasInstructionAndIndex(
|
||||
IndirectInstruction indirectInstr, Instruction instr, int indirectionIndex
|
||||
) {
|
||||
indirectInstr.getInstruction() = instr and
|
||||
indirectInstr.getIndirectionIndex() = indirectionIndex
|
||||
indirectInstr.hasInstructionAndIndirectionIndex(instr, indirectionIndex)
|
||||
}
|
||||
|
||||
cached
|
||||
@@ -1656,8 +1664,7 @@ module ExprFlowCached {
|
||||
private predicate isIndirectBaseOfArrayAccess(IndirectOperand n, Expr e) {
|
||||
exists(LoadInstruction load, PointerArithmeticInstruction pai |
|
||||
pai = load.getSourceAddress() and
|
||||
pai.getLeftOperand() = n.getOperand() and
|
||||
n.getIndirectionIndex() = 1 and
|
||||
n.hasOperandAndIndirectionIndex(pai.getLeftOperand(), 1) and
|
||||
e = load.getConvertedResultExpression()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ class FieldFlowPropertyProvider extends IRPropertyProvider {
|
||||
override string getOperandProperty(Operand operand, string key) {
|
||||
exists(PostFieldUpdateNode pfun, Content content |
|
||||
key = "store " + content.toString() and
|
||||
operand = pfun.getPreUpdateNode().(IndirectOperand).getOperand() and
|
||||
pfun.getPreUpdateNode().(IndirectOperand).hasOperandAndIndirectionIndex(operand, _) and
|
||||
result =
|
||||
strictconcat(string element, Node node |
|
||||
storeStep(node, content, pfun) and
|
||||
@@ -25,7 +25,7 @@ class FieldFlowPropertyProvider extends IRPropertyProvider {
|
||||
or
|
||||
exists(Node node2, Content content |
|
||||
key = "read " + content.toString() and
|
||||
operand = node2.(IndirectOperand).getOperand() and
|
||||
node2.(IndirectOperand).hasOperandAndIndirectionIndex(operand, _) and
|
||||
result =
|
||||
strictconcat(string element, Node node1 |
|
||||
readStep(node1, content, node2) and
|
||||
|
||||
@@ -18,9 +18,12 @@ private string stars(int k) {
|
||||
}
|
||||
|
||||
string starsForNode(Node node) {
|
||||
result = stars(node.(IndirectInstruction).getIndirectionIndex())
|
||||
or
|
||||
result = stars(node.(IndirectOperand).getIndirectionIndex())
|
||||
exists(int indirectionIndex |
|
||||
node.(IndirectInstruction).hasInstructionAndIndirectionIndex(_, indirectionIndex) or
|
||||
node.(IndirectOperand).hasOperandAndIndirectionIndex(_, indirectionIndex)
|
||||
|
|
||||
result = stars(indirectionIndex)
|
||||
)
|
||||
or
|
||||
not node instanceof IndirectInstruction and
|
||||
not node instanceof IndirectOperand and
|
||||
|
||||
@@ -364,7 +364,25 @@ abstract private class OperandBasedUse extends UseImpl {
|
||||
OperandBasedUse() { any() }
|
||||
|
||||
final override predicate hasIndexInBlock(IRBlock block, int index) {
|
||||
operand.getUse() = block.getInstruction(index)
|
||||
// See the comment in `ssa0`'s `OperandBasedUse` for an explanation of this
|
||||
// predicate's implementation.
|
||||
exists(BaseSourceVariableInstruction base | base = this.getBase() |
|
||||
if base.getAst() = any(Cpp::PostfixCrementOperation c).getOperand()
|
||||
then
|
||||
exists(Operand op, int indirectionIndex, int indirection |
|
||||
indirectionIndex = this.getIndirectionIndex() and
|
||||
indirection = this.getIndirection() and
|
||||
op =
|
||||
min(Operand cand, int i |
|
||||
isUse(_, cand, base, indirection, indirectionIndex) and
|
||||
block.getInstruction(i) = cand.getUse()
|
||||
|
|
||||
cand order by i
|
||||
) and
|
||||
block.getInstruction(index) = op.getUse()
|
||||
)
|
||||
else operand.getUse() = block.getInstruction(index)
|
||||
)
|
||||
}
|
||||
|
||||
final Operand getOperand() { result = operand }
|
||||
|
||||
@@ -144,6 +144,20 @@ class AllocationInstruction extends CallInstruction {
|
||||
AllocationInstruction() { this.getStaticCallTarget() instanceof Cpp::AllocationFunction }
|
||||
}
|
||||
|
||||
private predicate isIndirectionType(Type t) { t instanceof Indirection }
|
||||
|
||||
private predicate hasUnspecifiedBaseType(Indirection t, Type base) {
|
||||
base = t.getBaseType().getUnspecifiedType()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `t2` is the same type as `t1`, but after stripping away `result` number
|
||||
* of indirections.
|
||||
* Furthermore, specifies in `t2` been deeply stripped and typedefs has been resolved.
|
||||
*/
|
||||
private int getNumberOfIndirectionsImpl(Type t1, Type t2) =
|
||||
shortestDistances(isIndirectionType/1, hasUnspecifiedBaseType/2)(t1, t2, result)
|
||||
|
||||
/**
|
||||
* An abstract class for handling indirections.
|
||||
*
|
||||
@@ -162,7 +176,10 @@ abstract class Indirection extends Type {
|
||||
* For example, the number of indirections of a variable `p` of type
|
||||
* `int**` is `3` (i.e., `p`, `*p` and `**p`).
|
||||
*/
|
||||
abstract int getNumberOfIndirections();
|
||||
final int getNumberOfIndirections() {
|
||||
result =
|
||||
getNumberOfIndirectionsImpl(this.getType(), any(Type end | not end instanceof Indirection))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `deref` is an instruction that behaves as a `LoadInstruction`
|
||||
@@ -200,19 +217,11 @@ private class PointerOrArrayOrReferenceTypeIndirection extends Indirection insta
|
||||
PointerOrArrayOrReferenceTypeIndirection() {
|
||||
baseType = PointerOrArrayOrReferenceType.super.getBaseType()
|
||||
}
|
||||
|
||||
override int getNumberOfIndirections() {
|
||||
result = 1 + countIndirections(this.getBaseType().getUnspecifiedType())
|
||||
}
|
||||
}
|
||||
|
||||
private class PointerWrapperTypeIndirection extends Indirection instanceof PointerWrapper {
|
||||
PointerWrapperTypeIndirection() { baseType = PointerWrapper.super.getBaseType() }
|
||||
|
||||
override int getNumberOfIndirections() {
|
||||
result = 1 + countIndirections(this.getBaseType().getUnspecifiedType())
|
||||
}
|
||||
|
||||
override predicate isAdditionalDereference(Instruction deref, Operand address) {
|
||||
exists(CallInstruction call |
|
||||
operandForFullyConvertedCall(getAUse(deref), call) and
|
||||
@@ -233,10 +242,6 @@ private module IteratorIndirections {
|
||||
baseType = super.getValueType()
|
||||
}
|
||||
|
||||
override int getNumberOfIndirections() {
|
||||
result = 1 + countIndirections(this.getBaseType().getUnspecifiedType())
|
||||
}
|
||||
|
||||
override predicate isAdditionalDereference(Instruction deref, Operand address) {
|
||||
exists(CallInstruction call |
|
||||
operandForFullyConvertedCall(getAUse(deref), call) and
|
||||
@@ -258,7 +263,7 @@ private module IteratorIndirections {
|
||||
// Taint through `operator+=` and `operator-=` on iterators.
|
||||
call.getStaticCallTarget() instanceof Iterator::IteratorAssignArithmeticOperator and
|
||||
node2.(IndirectArgumentOutNode).getPreUpdateNode() = node1 and
|
||||
node1.(IndirectOperand).getOperand() = call.getArgumentOperand(0) and
|
||||
node1.(IndirectOperand).hasOperandAndIndirectionIndex(call.getArgumentOperand(0), _) and
|
||||
node1.getType().getUnspecifiedType() = this
|
||||
)
|
||||
}
|
||||
@@ -791,7 +796,7 @@ private module Cached {
|
||||
address.getDef() = instr and
|
||||
isDereference(load, address) and
|
||||
isUseImpl(address, _, indirectionIndex - 1) and
|
||||
result = instr
|
||||
result = load
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -160,7 +160,7 @@ predicate modeledTaintStep(DataFlow::Node nodeIn, DataFlow::Node nodeOut) {
|
||||
FunctionInput modelIn, FunctionOutput modelOut
|
||||
|
|
||||
indirectArgument = callInput(call, modelIn) and
|
||||
indirectArgument.getAddressOperand() = nodeIn.asOperand() and
|
||||
indirectArgument.hasAddressOperandAndIndirectionIndex(nodeIn.asOperand(), _) and
|
||||
call.getStaticCallTarget() = func and
|
||||
(
|
||||
func.(DataFlowFunction).hasDataFlow(modelIn, modelOut)
|
||||
|
||||
@@ -122,7 +122,46 @@ abstract private class OperandBasedUse extends UseImpl {
|
||||
override string toString() { result = operand.toString() }
|
||||
|
||||
final override predicate hasIndexInBlock(IRBlock block, int index) {
|
||||
operand.getUse() = block.getInstruction(index)
|
||||
// Ideally, this would just be implemented as:
|
||||
// ```
|
||||
// operand.getUse() = block.getInstruction(index)
|
||||
// ```
|
||||
// but because the IR generated for a snippet such as
|
||||
// ```
|
||||
// int x = *p++;
|
||||
// ```
|
||||
// looks like
|
||||
// ```
|
||||
// r1(glval<int>) = VariableAddress[x] :
|
||||
// r2(glval<int *>) = VariableAddress[p] :
|
||||
// r3(int *) = Load[p] : &:r2, m1
|
||||
// r4(int) = Constant[1] :
|
||||
// r5(int *) = PointerAdd[4] : r3, r4
|
||||
// m3(int *) = Store[p] : &:r2, r5
|
||||
// r6(int *) = CopyValue : r3
|
||||
// r7(int) = Load[?] : &:r6, ~m2
|
||||
// m2(int) = Store[x] : &:r1, r7
|
||||
// ```
|
||||
// we need to ensure that the `r3` operand of the `CopyValue` instruction isn't seen as a fresh use
|
||||
// of `p` that happens after the increment. So if the base instruction of this use comes from a
|
||||
// post-fix crement operation we set the index of the SSA use that wraps the `r3` operand at the
|
||||
// `CopyValue` instruction to be the same index as the `r3` operand at the `PointerAdd` instruction.
|
||||
// This ensures that the SSA library doesn't create flow from the `PointerAdd` to `r6`.
|
||||
exists(BaseSourceVariableInstruction base | base = this.getBase() |
|
||||
if base.getAst() = any(Cpp::PostfixCrementOperation c).getOperand()
|
||||
then
|
||||
exists(Operand op |
|
||||
op =
|
||||
min(Operand cand, int i |
|
||||
isUse(_, cand, base, _, _) and
|
||||
block.getInstruction(i) = cand.getUse()
|
||||
|
|
||||
cand order by i
|
||||
) and
|
||||
block.getInstruction(index) = op.getUse()
|
||||
)
|
||||
else operand.getUse() = block.getInstruction(index)
|
||||
)
|
||||
}
|
||||
|
||||
final override Cpp::Location getLocation() { result = operand.getLocation() }
|
||||
|
||||
@@ -210,9 +210,6 @@ class Instruction extends Construction::TStageInstruction {
|
||||
*/
|
||||
final Language::AST getAst() { result = Construction::getInstructionAst(this) }
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated Language::AST getAST() { result = this.getAst() }
|
||||
|
||||
/**
|
||||
* Gets the location of the source code for this instruction.
|
||||
*/
|
||||
@@ -463,9 +460,6 @@ class VariableInstruction extends Instruction {
|
||||
* Gets the AST variable that this instruction's IR variable refers to, if one exists.
|
||||
*/
|
||||
final Language::Variable getAstVariable() { result = var.(IRUserVariable).getVariable() }
|
||||
|
||||
/** DEPRECATED: Alias for getAstVariable */
|
||||
deprecated Language::Variable getASTVariable() { result = this.getAstVariable() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -577,9 +577,6 @@ private Overlap getVariableMemoryLocationOverlap(
|
||||
*/
|
||||
predicate canReuseSsaForOldResult(Instruction instr) { OldSsa::canReuseSsaForMemoryResult(instr) }
|
||||
|
||||
/** DEPRECATED: Alias for canReuseSsaForOldResult */
|
||||
deprecated predicate canReuseSSAForOldResult = canReuseSsaForOldResult/1;
|
||||
|
||||
bindingset[result, b]
|
||||
private boolean unbindBool(boolean b) { result != b.booleanNot() }
|
||||
|
||||
|
||||
@@ -422,12 +422,6 @@ private module Cached {
|
||||
)
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for getInstructionAst */
|
||||
cached
|
||||
deprecated Language::AST getInstructionAST(Instruction instr) {
|
||||
result = getInstructionAst(instr)
|
||||
}
|
||||
|
||||
cached
|
||||
Language::LanguageType getInstructionResultType(Instruction instr) {
|
||||
result = instr.(RawIR::Instruction).getResultLanguageType()
|
||||
@@ -993,9 +987,6 @@ predicate canReuseSsaForMemoryResult(Instruction instruction) {
|
||||
// We don't support reusing SSA for any location that could create a `Chi` instruction.
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for canReuseSsaForMemoryResult */
|
||||
deprecated predicate canReuseSSAForMemoryResult = canReuseSsaForMemoryResult/1;
|
||||
|
||||
/**
|
||||
* Expose some of the internal predicates to PrintSSA.qll. We do this by publicly importing those modules in the
|
||||
* `DebugSsa` module, which is then imported by PrintSSA.
|
||||
@@ -1005,9 +996,6 @@ module DebugSsa {
|
||||
import DefUse
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for DebugSsa */
|
||||
deprecated module DebugSSA = DebugSsa;
|
||||
|
||||
import CachedForDebugging
|
||||
|
||||
cached
|
||||
|
||||
@@ -73,9 +73,6 @@ module UnaliasedSsaInstructions {
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for UnaliasedSsaInstructions */
|
||||
deprecated module UnaliasedSSAInstructions = UnaliasedSsaInstructions;
|
||||
|
||||
/**
|
||||
* Provides wrappers for the constructors of each branch of `TInstruction` that is used by the
|
||||
* aliased SSA stage.
|
||||
@@ -107,6 +104,3 @@ module AliasedSsaInstructions {
|
||||
result = TAliasedSsaUnreachedInstruction(irFunc)
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for AliasedSsaInstructions */
|
||||
deprecated module AliasedSSAInstructions = AliasedSsaInstructions;
|
||||
|
||||
@@ -74,20 +74,12 @@ private module Shared {
|
||||
|
||||
class TNonSsaMemoryOperand = Internal::TNonSsaMemoryOperand;
|
||||
|
||||
/** DEPRECATED: Alias for TNonSsaMemoryOperand */
|
||||
deprecated class TNonSSAMemoryOperand = TNonSsaMemoryOperand;
|
||||
|
||||
/**
|
||||
* Returns the non-Phi memory operand with the specified parameters.
|
||||
*/
|
||||
TNonSsaMemoryOperand nonSsaMemoryOperand(TRawInstruction useInstr, MemoryOperandTag tag) {
|
||||
result = Internal::TNonSsaMemoryOperand(useInstr, tag)
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for nonSsaMemoryOperand */
|
||||
deprecated TNonSSAMemoryOperand nonSSAMemoryOperand(TRawInstruction useInstr, MemoryOperandTag tag) {
|
||||
result = nonSsaMemoryOperand(useInstr, tag)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -167,9 +159,6 @@ module UnaliasedSsaOperands {
|
||||
TChiOperand chiOperand(Unaliased::Instruction useInstr, ChiOperandTag tag) { none() }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for UnaliasedSsaOperands */
|
||||
deprecated module UnaliasedSSAOperands = UnaliasedSsaOperands;
|
||||
|
||||
/**
|
||||
* Provides wrappers for the constructors of each branch of `TOperand` that is used by the
|
||||
* aliased SSA stage.
|
||||
@@ -217,6 +206,3 @@ module AliasedSsaOperands {
|
||||
result = Internal::TAliasedChiOperand(useInstr, tag)
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for AliasedSsaOperands */
|
||||
deprecated module AliasedSSAOperands = AliasedSsaOperands;
|
||||
|
||||
@@ -210,9 +210,6 @@ class Instruction extends Construction::TStageInstruction {
|
||||
*/
|
||||
final Language::AST getAst() { result = Construction::getInstructionAst(this) }
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated Language::AST getAST() { result = this.getAst() }
|
||||
|
||||
/**
|
||||
* Gets the location of the source code for this instruction.
|
||||
*/
|
||||
@@ -463,9 +460,6 @@ class VariableInstruction extends Instruction {
|
||||
* Gets the AST variable that this instruction's IR variable refers to, if one exists.
|
||||
*/
|
||||
final Language::Variable getAstVariable() { result = var.(IRUserVariable).getVariable() }
|
||||
|
||||
/** DEPRECATED: Alias for getAstVariable */
|
||||
deprecated Language::Variable getASTVariable() { result = this.getAstVariable() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -375,11 +375,6 @@ Locatable getInstructionAst(TStageInstruction instr) {
|
||||
)
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for getInstructionAst */
|
||||
deprecated Locatable getInstructionAST(TStageInstruction instr) {
|
||||
result = getInstructionAst(instr)
|
||||
}
|
||||
|
||||
CppType getInstructionResultType(TStageInstruction instr) {
|
||||
getInstructionTranslatedElement(instr).hasInstruction(_, getInstructionTag(instr), result)
|
||||
or
|
||||
|
||||
@@ -76,9 +76,6 @@ abstract class TranslatedExpr extends TranslatedElement {
|
||||
|
||||
final override Locatable getAst() { result = expr }
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated override Locatable getAST() { result = this.getAst() }
|
||||
|
||||
final override Declaration getFunction() { result = getEnclosingDeclaration(expr) }
|
||||
|
||||
/**
|
||||
|
||||
@@ -210,9 +210,6 @@ class Instruction extends Construction::TStageInstruction {
|
||||
*/
|
||||
final Language::AST getAst() { result = Construction::getInstructionAst(this) }
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated Language::AST getAST() { result = this.getAst() }
|
||||
|
||||
/**
|
||||
* Gets the location of the source code for this instruction.
|
||||
*/
|
||||
@@ -463,9 +460,6 @@ class VariableInstruction extends Instruction {
|
||||
* Gets the AST variable that this instruction's IR variable refers to, if one exists.
|
||||
*/
|
||||
final Language::Variable getAstVariable() { result = var.(IRUserVariable).getVariable() }
|
||||
|
||||
/** DEPRECATED: Alias for getAstVariable */
|
||||
deprecated Language::Variable getASTVariable() { result = this.getAstVariable() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -422,12 +422,6 @@ private module Cached {
|
||||
)
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for getInstructionAst */
|
||||
cached
|
||||
deprecated Language::AST getInstructionAST(Instruction instr) {
|
||||
result = getInstructionAst(instr)
|
||||
}
|
||||
|
||||
cached
|
||||
Language::LanguageType getInstructionResultType(Instruction instr) {
|
||||
result = instr.(RawIR::Instruction).getResultLanguageType()
|
||||
@@ -993,9 +987,6 @@ predicate canReuseSsaForMemoryResult(Instruction instruction) {
|
||||
// We don't support reusing SSA for any location that could create a `Chi` instruction.
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for canReuseSsaForMemoryResult */
|
||||
deprecated predicate canReuseSSAForMemoryResult = canReuseSsaForMemoryResult/1;
|
||||
|
||||
/**
|
||||
* Expose some of the internal predicates to PrintSSA.qll. We do this by publicly importing those modules in the
|
||||
* `DebugSsa` module, which is then imported by PrintSSA.
|
||||
@@ -1005,9 +996,6 @@ module DebugSsa {
|
||||
import DefUse
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for DebugSsa */
|
||||
deprecated module DebugSSA = DebugSsa;
|
||||
|
||||
import CachedForDebugging
|
||||
|
||||
cached
|
||||
|
||||
@@ -46,9 +46,6 @@ predicate canReuseSsaForVariable(IRAutomaticVariable var) {
|
||||
not allocationEscapes(var)
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for canReuseSsaForVariable */
|
||||
deprecated predicate canReuseSSAForVariable = canReuseSsaForVariable/1;
|
||||
|
||||
private newtype TMemoryLocation = MkMemoryLocation(Allocation var) { isVariableModeled(var) }
|
||||
|
||||
private MemoryLocation getMemoryLocation(Allocation var) { result.getAllocation() = var }
|
||||
@@ -80,9 +77,6 @@ class MemoryLocation extends TMemoryLocation {
|
||||
|
||||
predicate canReuseSsaForOldResult(Instruction instr) { none() }
|
||||
|
||||
/** DEPRECATED: Alias for canReuseSsaForOldResult */
|
||||
deprecated predicate canReuseSSAForOldResult = canReuseSsaForOldResult/1;
|
||||
|
||||
/**
|
||||
* Represents a set of `MemoryLocation`s that cannot overlap with
|
||||
* `MemoryLocation`s outside of the set. The `VirtualVariable` will be
|
||||
|
||||
@@ -108,7 +108,7 @@ class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction, Sid
|
||||
// these may do only a partial copy of the input buffer to the output
|
||||
// buffer
|
||||
exists(this.getParamSize()) and
|
||||
input.isParameter(this.getParamSrc()) and
|
||||
input.isParameterDeref(this.getParamSrc()) and
|
||||
(
|
||||
output.isParameterDeref(this.getParamDest()) or
|
||||
output.isReturnValueDeref()
|
||||
|
||||
@@ -40,9 +40,6 @@ library class RangeSsa extends SsaHelper {
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for RangeSsa */
|
||||
deprecated class RangeSSA = RangeSsa;
|
||||
|
||||
private predicate guard_defn(VariableAccess v, Expr guard, BasicBlock b, boolean branch) {
|
||||
guardCondition(guard, v, branch) and
|
||||
guardSuccessor(guard, branch, b)
|
||||
|
||||
@@ -1,3 +1,13 @@
|
||||
## 0.6.3
|
||||
|
||||
### New Queries
|
||||
|
||||
* Added a new query, `cpp/overrun-write`, to detect buffer overflows in C-style functions that manipulate buffers.
|
||||
|
||||
## 0.6.2
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
## 0.6.1
|
||||
|
||||
### New Queries
|
||||
|
||||
@@ -16,9 +16,6 @@ class UntrustedExternalApiDataNode extends ExternalApiDataNode {
|
||||
DataFlow::Node getAnUntrustedSource() { UntrustedDataToExternalApiFlow::flow(result, this) }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for UntrustedExternalApiDataNode */
|
||||
deprecated class UntrustedExternalAPIDataNode = UntrustedExternalApiDataNode;
|
||||
|
||||
/** An external API which is used with untrusted data. */
|
||||
private newtype TExternalApi =
|
||||
/** An untrusted API method `m` where untrusted data is passed at `index`. */
|
||||
@@ -51,6 +48,3 @@ class ExternalApiUsedWithUntrustedData extends TExternalApi {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for ExternalApiUsedWithUntrustedData */
|
||||
deprecated class ExternalAPIUsedWithUntrustedData = ExternalApiUsedWithUntrustedData;
|
||||
|
||||
@@ -41,9 +41,6 @@ class ExternalApiDataNode extends DataFlow::Node {
|
||||
string getFunctionDescription() { result = this.getExternalFunction().toString() }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for ExternalApiDataNode */
|
||||
deprecated class ExternalAPIDataNode = ExternalApiDataNode;
|
||||
|
||||
/** A configuration for tracking flow from `RemoteFlowSource`s to `ExternalApiDataNode`s. */
|
||||
deprecated class UntrustedDataToExternalApiConfig extends TaintTracking::Configuration {
|
||||
UntrustedDataToExternalApiConfig() { this = "UntrustedDataToExternalAPIConfig" }
|
||||
@@ -58,9 +55,6 @@ deprecated class UntrustedDataToExternalApiConfig extends TaintTracking::Configu
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof ExternalApiDataNode }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for UntrustedDataToExternalApiConfig */
|
||||
deprecated class UntrustedDataToExternalAPIConfig = UntrustedDataToExternalApiConfig;
|
||||
|
||||
/** A configuration for tracking flow from `RemoteFlowSource`s to `ExternalApiDataNode`s. */
|
||||
private module UntrustedDataToExternalApiConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
|
||||
@@ -10,9 +10,6 @@ private import semmle.code.cpp.models.interfaces.SideEffect
|
||||
*/
|
||||
abstract class SafeExternalApiFunction extends Function { }
|
||||
|
||||
/** DEPRECATED: Alias for SafeExternalApiFunction */
|
||||
deprecated class SafeExternalAPIFunction = SafeExternalApiFunction;
|
||||
|
||||
/** The default set of "safe" external APIs. */
|
||||
private class DefaultSafeExternalApiFunction extends SafeExternalApiFunction {
|
||||
DefaultSafeExternalApiFunction() {
|
||||
|
||||
@@ -16,9 +16,6 @@ class UntrustedExternalApiDataNode extends ExternalApiDataNode {
|
||||
DataFlow::Node getAnUntrustedSource() { UntrustedDataToExternalApiFlow::flow(result, this) }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for UntrustedExternalApiDataNode */
|
||||
deprecated class UntrustedExternalAPIDataNode = UntrustedExternalApiDataNode;
|
||||
|
||||
/** An external API which is used with untrusted data. */
|
||||
private newtype TExternalApi =
|
||||
/** An untrusted API method `m` where untrusted data is passed at `index`. */
|
||||
@@ -51,6 +48,3 @@ class ExternalApiUsedWithUntrustedData extends TExternalApi {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for ExternalApiUsedWithUntrustedData */
|
||||
deprecated class ExternalAPIUsedWithUntrustedData = ExternalApiUsedWithUntrustedData;
|
||||
|
||||
@@ -41,9 +41,6 @@ class ExternalApiDataNode extends DataFlow::Node {
|
||||
string getFunctionDescription() { result = this.getExternalFunction().toString() }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for ExternalApiDataNode */
|
||||
deprecated class ExternalAPIDataNode = ExternalApiDataNode;
|
||||
|
||||
/** A configuration for tracking flow from `RemoteFlowSource`s to `ExternalApiDataNode`s. */
|
||||
deprecated class UntrustedDataToExternalApiConfig extends TaintTracking::Configuration {
|
||||
UntrustedDataToExternalApiConfig() { this = "UntrustedDataToExternalAPIConfigIR" }
|
||||
@@ -53,9 +50,6 @@ deprecated class UntrustedDataToExternalApiConfig extends TaintTracking::Configu
|
||||
override predicate isSink(DataFlow::Node sink) { sink instanceof ExternalApiDataNode }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for UntrustedDataToExternalApiConfig */
|
||||
deprecated class UntrustedDataToExternalAPIConfig = UntrustedDataToExternalApiConfig;
|
||||
|
||||
/** A configuration for tracking flow from `RemoteFlowSource`s to `ExternalApiDataNode`s. */
|
||||
private module UntrustedDataToExternalApiConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
|
||||
|
||||
@@ -10,9 +10,6 @@ private import semmle.code.cpp.models.interfaces.SideEffect
|
||||
*/
|
||||
abstract class SafeExternalApiFunction extends Function { }
|
||||
|
||||
/** DEPRECATED: Alias for SafeExternalApiFunction */
|
||||
deprecated class SafeExternalAPIFunction = SafeExternalApiFunction;
|
||||
|
||||
/** The default set of "safe" external APIs. */
|
||||
private class DefaultSafeExternalApiFunction extends SafeExternalApiFunction {
|
||||
DefaultSafeExternalApiFunction() {
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
* @kind path-problem
|
||||
* @problem.severity error
|
||||
* @security-severity 9.3
|
||||
* @precision medium
|
||||
* @precision low
|
||||
* @id cpp/overrun-write
|
||||
* @tags reliability
|
||||
* security
|
||||
|
||||
3
cpp/ql/src/change-notes/released/0.6.2.md
Normal file
3
cpp/ql/src/change-notes/released/0.6.2.md
Normal file
@@ -0,0 +1,3 @@
|
||||
## 0.6.2
|
||||
|
||||
No user-facing changes.
|
||||
@@ -1,4 +1,5 @@
|
||||
---
|
||||
category: newQuery
|
||||
---
|
||||
## 0.6.3
|
||||
|
||||
### New Queries
|
||||
|
||||
* Added a new query, `cpp/overrun-write`, to detect buffer overflows in C-style functions that manipulate buffers.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.6.1
|
||||
lastReleaseVersion: 0.6.3
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
|
||||
<overview>
|
||||
<p>
|
||||
Detects <code>if (a+b>c) a=c-b</code>, which incorrectly implements
|
||||
<code>a = min(a,c-b)</code> if <code>a+b</code> overflows.
|
||||
</p>
|
||||
<p>
|
||||
Also detects variants such as <code>if (b+a>c) a=c-b</code> (swapped
|
||||
terms in addition), <code>if (a+b>c) { a=c-b }</code> (assignment
|
||||
inside block), <code>c<a+b</code> (swapped operands), and
|
||||
<code>>=</code>, <code><</code>, <code><=</code> instead of
|
||||
<code>></code> (all operators).
|
||||
</p>
|
||||
<p>
|
||||
This integer overflow is the root cause of the buffer overflow in
|
||||
the SHA-3 reference implementation (CVE-2022-37454).
|
||||
</p>
|
||||
</overview>
|
||||
<recommendation>
|
||||
<p>
|
||||
Replace by <code>if (a>c-b) a=c-b</code>. This avoids the overflow
|
||||
and makes it easy to see that <code>a = min(a,c-b)</code>.
|
||||
</p>
|
||||
</recommendation>
|
||||
<references>
|
||||
<li>CVE-2022-37454: <a href="https://nvd.nist.gov/vuln/detail/CVE-2022-37454">The Keccak XKCP SHA-3 reference implementation before fdc6fef has an integer overflow and resultant buffer overflow that allows attackers to execute arbitrary code or eliminate expected cryptographic properties. This occurs in the sponge function interface.</a></li>
|
||||
<li>GitHub Advisory Database: <a href="https://github.com/advisories/GHSA-6w4m-2xhg-2658">CVE-2022-37454: Buffer overflow in sponge queue functions</a></li>
|
||||
</references>
|
||||
</qhelp>
|
||||
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* @name Integer addition may overflow inside if statement
|
||||
* @description Writing 'if (a+b>c) a=c-b' incorrectly implements
|
||||
* 'a = min(a,c-b)' if 'a+b' overflows. This integer
|
||||
* overflow is the root cause of the buffer overflow
|
||||
* in the SHA-3 reference implementation (CVE-2022-37454).
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @id cpp/if-statement-addition-overflow
|
||||
* @tags: experimental
|
||||
* correctness
|
||||
* security
|
||||
* external/cwe/cwe-190
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
|
||||
import semmle.code.cpp.valuenumbering.HashCons
|
||||
import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
|
||||
import semmle.code.cpp.controlflow.Guards
|
||||
|
||||
from
|
||||
GuardCondition guard, Expr expr, ExprStmt exprstmt, BasicBlock block, AssignExpr assignexpr,
|
||||
AddExpr addexpr, SubExpr subexpr
|
||||
where
|
||||
(guard.ensuresLt(expr, addexpr, 0, block, _) or guard.ensuresLt(addexpr, expr, 0, block, _)) and
|
||||
addexpr.getUnspecifiedType() instanceof IntegralType and
|
||||
exprMightOverflowPositively(addexpr) and
|
||||
block.getANode() = exprstmt and
|
||||
exprstmt.getExpr() = assignexpr and
|
||||
assignexpr.getRValue() = subexpr and
|
||||
(
|
||||
hashCons(addexpr.getLeftOperand()) = hashCons(assignexpr.getLValue()) and
|
||||
globalValueNumber(addexpr.getRightOperand()) = globalValueNumber(subexpr.getRightOperand())
|
||||
or
|
||||
hashCons(addexpr.getRightOperand()) = hashCons(assignexpr.getLValue()) and
|
||||
globalValueNumber(addexpr.getLeftOperand()) = globalValueNumber(subexpr.getRightOperand())
|
||||
) and
|
||||
globalValueNumber(expr) = globalValueNumber(subexpr.getLeftOperand())
|
||||
select guard,
|
||||
"\"if (a+b>c) a=c-b\" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as \"if (a>c-b) a=c-b\" which avoids the overflow.",
|
||||
addexpr, "addition"
|
||||
@@ -78,11 +78,17 @@ predicate isInvalidPointerDerefSink2(DataFlow::Node sink, Instruction i, string
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate arrayTypeHasSizes(ArrayType arr, int baseTypeSize, int arraySize) {
|
||||
arr.getBaseType().getSize() = baseTypeSize and
|
||||
arr.getArraySize() = arraySize
|
||||
}
|
||||
|
||||
predicate pointerArithOverflow0(
|
||||
PointerArithmeticInstruction pai, Variable v, int size, int bound, int delta
|
||||
) {
|
||||
pai.getElementSize() = v.getUnspecifiedType().(ArrayType).getBaseType().getSize() and
|
||||
v.getUnspecifiedType().(ArrayType).getArraySize() = size and
|
||||
not v.getNamespace() instanceof StdNamespace and
|
||||
arrayTypeHasSizes(v.getUnspecifiedType(), pai.getElementSize(), size) and
|
||||
semBounded(getSemanticExpr(pai.getRight()), any(SemZeroBound b), bound, true, _) and
|
||||
delta = bound - size and
|
||||
delta >= 0 and
|
||||
@@ -162,7 +168,7 @@ from
|
||||
Variable v, ArrayAddressToDerefFlow::PathNode source, PointerArithmeticInstruction pai,
|
||||
ArrayAddressToDerefFlow::PathNode sink, Instruction deref, string operation, int delta
|
||||
where
|
||||
ArrayAddressToDerefFlow::flowPath(source, sink) and
|
||||
ArrayAddressToDerefFlow::flowPath(source, sink) and
|
||||
isInvalidPointerDerefSink2(sink.getNode(), deref, operation) and
|
||||
source.getState() = ArrayAddressToDerefConfig::TArray(v) and
|
||||
sink.getState() = ArrayAddressToDerefConfig::TOverflowArithmetic(pai) and
|
||||
|
||||
@@ -81,8 +81,8 @@ predicate hasSize(HeuristicAllocationExpr alloc, DataFlow::Node n, int state) {
|
||||
* ```
|
||||
*
|
||||
* We do this by splitting the task up into two configurations:
|
||||
* 1. `AllocToInvalidPointerConf` find flow from `malloc(size)` to `begin + size`, and
|
||||
* 2. `InvalidPointerToDerefConf` finds flow from `begin + size` to an `end` (on line 3).
|
||||
* 1. `AllocToInvalidPointerConfig` find flow from `malloc(size)` to `begin + size`, and
|
||||
* 2. `InvalidPointerToDerefConfig` finds flow from `begin + size` to an `end` (on line 3).
|
||||
*
|
||||
* Finally, the range-analysis library will find a load from (or store to) an address that
|
||||
* is non-strictly upper-bounded by `end` (which in this case is `*p`).
|
||||
@@ -180,14 +180,33 @@ predicate isSinkImpl(
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a sink for `InvalidPointerToDerefConf` and `i` is a `StoreInstruction` that
|
||||
* 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) {
|
||||
exists(AddressOperand addr, int delta |
|
||||
bounded1(addr.getDef(), sink.asInstruction(), delta) and
|
||||
predicate isInvalidPointerDerefSink(DataFlow::Node sink, Instruction i, string operation, int delta) {
|
||||
exists(AddressOperand addr, Instruction s |
|
||||
s = sink.asInstruction() and
|
||||
bounded1(addr.getDef(), s, delta) and
|
||||
delta >= 0 and
|
||||
i.getAnOperand() = addr
|
||||
|
|
||||
@@ -201,13 +220,13 @@ predicate isInvalidPointerDerefSink(DataFlow::Node sink, Instruction i, string o
|
||||
|
||||
/**
|
||||
* A configuration to track flow from a pointer-arithmetic operation found
|
||||
* by `AllocToInvalidPointerConf` to a dereference of the pointer.
|
||||
* by `AllocToInvalidPointerConfig` to a dereference of the pointer.
|
||||
*/
|
||||
module InvalidPointerToDerefConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { invalidPointerToDerefSource(_, source, _) }
|
||||
|
||||
pragma[inline]
|
||||
predicate isSink(DataFlow::Node sink) { isInvalidPointerDerefSink(sink, _, _) }
|
||||
predicate isSink(DataFlow::Node sink) { isInvalidPointerDerefSink(sink, _, _, _) }
|
||||
|
||||
predicate isBarrier(DataFlow::Node node) {
|
||||
node = any(DataFlow::SsaPhiNode phi | not phi.isPhiRead()).getAnInput(true)
|
||||
@@ -237,17 +256,18 @@ predicate invalidPointerToDerefSource(
|
||||
}
|
||||
|
||||
newtype TMergedPathNode =
|
||||
// The path nodes computed by the first projection of `AllocToInvalidPointerConf`
|
||||
// The path nodes computed by the first projection of `AllocToInvalidPointerConfig`
|
||||
TPathNode1(AllocToInvalidPointerFlow::PathNode1 p) or
|
||||
// The path nodes computed by `InvalidPointerToDerefConf`
|
||||
// The path nodes computed by `InvalidPointerToDerefConfig`
|
||||
TPathNode3(InvalidPointerToDerefFlow::PathNode p) or
|
||||
// The read/write that uses the invalid pointer identified by `InvalidPointerToDerefConf`.
|
||||
// This one is needed because the sink identified by `InvalidPointerToDerefConf` is the
|
||||
// The read/write that uses the invalid pointer identified by `InvalidPointerToDerefConfig`.
|
||||
// This one is needed because the sink identified by `InvalidPointerToDerefConfig` is the
|
||||
// pointer, but we want to raise an alert at the dereference.
|
||||
TPathNodeSink(Instruction i) {
|
||||
exists(DataFlow::Node n |
|
||||
InvalidPointerToDerefFlow::flowTo(n) and
|
||||
isInvalidPointerDerefSink(n, i, _)
|
||||
isInvalidPointerDerefSink(n, i, _, _) and
|
||||
i = getASuccessor(n.asInstruction())
|
||||
)
|
||||
}
|
||||
|
||||
@@ -321,7 +341,15 @@ query predicate edges(MergedPathNode node1, MergedPathNode node2) {
|
||||
or
|
||||
node1.asPathNode3().getASuccessor() = node2.asPathNode3()
|
||||
or
|
||||
joinOn2(node1.asPathNode3(), node2.asSinkNode(), _)
|
||||
joinOn2(node1.asPathNode3(), node2.asSinkNode(), _, _)
|
||||
}
|
||||
|
||||
query predicate nodes(MergedPathNode n, string key, string val) {
|
||||
AllocToInvalidPointerFlow::PathGraph1::nodes(n.asPathNode1(), key, val)
|
||||
or
|
||||
InvalidPointerToDerefFlow::PathGraph::nodes(n.asPathNode3(), key, val)
|
||||
or
|
||||
key = "semmle.label" and val = n.asSinkNode().toString()
|
||||
}
|
||||
|
||||
query predicate subpaths(
|
||||
@@ -335,8 +363,8 @@ query predicate subpaths(
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `p1` is a sink of `AllocToInvalidPointerConf` and `p2` is a source
|
||||
* of `InvalidPointerToDerefConf`, and they are connected through `pai`.
|
||||
* Holds if `p1` is a sink of `AllocToInvalidPointerConfig` and `p2` is a source
|
||||
* of `InvalidPointerToDerefConfig`, and they are connected through `pai`.
|
||||
*/
|
||||
predicate joinOn1(
|
||||
PointerArithmeticInstruction pai, AllocToInvalidPointerFlow::PathNode1 p1,
|
||||
@@ -347,34 +375,38 @@ predicate joinOn1(
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `p1` is a sink of `InvalidPointerToDerefConf` and `i` is the instruction
|
||||
* Holds if `p1` is a sink of `InvalidPointerToDerefConfig` and `i` is the instruction
|
||||
* that dereferences `p1`. The string `operation` describes whether the `i` is
|
||||
* a `StoreInstruction` or `LoadInstruction`.
|
||||
*/
|
||||
pragma[inline]
|
||||
predicate joinOn2(InvalidPointerToDerefFlow::PathNode p1, Instruction i, string operation) {
|
||||
isInvalidPointerDerefSink(p1.getNode(), i, operation)
|
||||
predicate joinOn2(InvalidPointerToDerefFlow::PathNode p1, Instruction i, string operation, int delta) {
|
||||
isInvalidPointerDerefSink(p1.getNode(), i, operation, delta)
|
||||
}
|
||||
|
||||
predicate hasFlowPath(
|
||||
MergedPathNode source1, MergedPathNode sink, InvalidPointerToDerefFlow::PathNode source3,
|
||||
PointerArithmeticInstruction pai, string operation
|
||||
PointerArithmeticInstruction pai, string operation, int delta
|
||||
) {
|
||||
exists(InvalidPointerToDerefFlow::PathNode sink3, AllocToInvalidPointerFlow::PathNode1 sink1 |
|
||||
AllocToInvalidPointerFlow::flowPath(source1.asPathNode1(), _, sink1, _) and
|
||||
joinOn1(pai, sink1, source3) and
|
||||
InvalidPointerToDerefFlow::flowPath(source3, sink3) and
|
||||
joinOn2(sink3, sink.asSinkNode(), operation)
|
||||
joinOn2(sink3, sink.asSinkNode(), operation, delta)
|
||||
)
|
||||
}
|
||||
|
||||
from
|
||||
MergedPathNode source, MergedPathNode sink, int k, string kstr,
|
||||
InvalidPointerToDerefFlow::PathNode source3, PointerArithmeticInstruction pai, string operation,
|
||||
Expr offset, DataFlow::Node n
|
||||
MergedPathNode source, MergedPathNode sink, int k, string kstr, PointerArithmeticInstruction pai,
|
||||
string operation, Expr offset, DataFlow::Node n
|
||||
where
|
||||
hasFlowPath(source, sink, source3, pai, operation) and
|
||||
invalidPointerToDerefSource(pai, source3.getNode(), k) and
|
||||
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
|
||||
offset = pai.getRight().getUnconvertedResultExpression() and
|
||||
n = source.asPathNode1().getNode() and
|
||||
if k = 0 then kstr = "" else kstr = " + " + k
|
||||
|
||||
373
cpp/ql/src/external/CodeDuplication.qll
vendored
373
cpp/ql/src/external/CodeDuplication.qll
vendored
@@ -1,373 +0,0 @@
|
||||
/** Provides classes for detecting duplicate or similar code. */
|
||||
|
||||
import cpp
|
||||
|
||||
deprecated private newtype TDuplicationOrSimilarity = MKDuplicationOrSimilarity()
|
||||
|
||||
/**
|
||||
* DEPRECATED: This class is no longer used.
|
||||
*
|
||||
* A token block used for detection of duplicate and similar code.
|
||||
*/
|
||||
deprecated class Copy extends TDuplicationOrSimilarity {
|
||||
/** Gets the index of the token in this block starting at the location `loc`, if any. */
|
||||
int tokenStartingAt(Location loc) { none() }
|
||||
|
||||
/** Gets the index of the token in this block ending at the location `loc`, if any. */
|
||||
int tokenEndingAt(Location loc) { none() }
|
||||
|
||||
/** Gets the line on which the first token in this block starts. */
|
||||
int sourceStartLine() { none() }
|
||||
|
||||
/** Gets the column on which the first token in this block starts. */
|
||||
int sourceStartColumn() { none() }
|
||||
|
||||
/** Gets the line on which the last token in this block ends. */
|
||||
int sourceEndLine() { none() }
|
||||
|
||||
/** Gets the column on which the last token in this block ends. */
|
||||
int sourceEndColumn() { none() }
|
||||
|
||||
/** Gets the number of lines containing at least (part of) one token in this block. */
|
||||
int sourceLines() { result = this.sourceEndLine() + 1 - this.sourceStartLine() }
|
||||
|
||||
/** Gets an opaque identifier for the equivalence class of this block. */
|
||||
int getEquivalenceClass() { none() }
|
||||
|
||||
/** Gets the source file in which this block appears. */
|
||||
File sourceFile() { none() }
|
||||
|
||||
/**
|
||||
* Holds if this element is at the specified location.
|
||||
* The location spans column `startcolumn` of line `startline` to
|
||||
* column `endcolumn` of line `endline` in file `filepath`.
|
||||
* For more information, see
|
||||
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries/).
|
||||
*/
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
this.sourceFile().getAbsolutePath() = filepath and
|
||||
startline = this.sourceStartLine() and
|
||||
startcolumn = this.sourceStartColumn() and
|
||||
endline = this.sourceEndLine() and
|
||||
endcolumn = this.sourceEndColumn()
|
||||
}
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: This class is no longer used.
|
||||
*
|
||||
* A block of duplicated code.
|
||||
*/
|
||||
deprecated class DuplicateBlock extends Copy {
|
||||
override string toString() {
|
||||
result = "Duplicate code: " + this.sourceLines() + " duplicated lines."
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: This class is no longer used.
|
||||
*
|
||||
* A block of similar code.
|
||||
*/
|
||||
deprecated class SimilarBlock extends Copy {
|
||||
override string toString() {
|
||||
result = "Similar code: " + this.sourceLines() + " almost duplicated lines."
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: The `CodeDuplication` library will be removed in a future release.
|
||||
*
|
||||
* Gets a function with a body and a location.
|
||||
*/
|
||||
deprecated FunctionDeclarationEntry sourceMethod() {
|
||||
result.isDefinition() and
|
||||
exists(result.getLocation()) and
|
||||
numlines(unresolveElement(result.getFunction()), _, _, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: The `CodeDuplication` library will be removed in a future release.
|
||||
*
|
||||
* Gets the number of member functions in `c` with a body and a location.
|
||||
*/
|
||||
deprecated int numberOfSourceMethods(Class c) {
|
||||
result =
|
||||
count(FunctionDeclarationEntry m |
|
||||
m = sourceMethod() and
|
||||
m.getFunction().getDeclaringType() = c
|
||||
)
|
||||
}
|
||||
|
||||
deprecated private predicate blockCoversStatement(int equivClass, int first, int last, Stmt stmt) {
|
||||
exists(DuplicateBlock b, Location loc |
|
||||
stmt.getLocation() = loc and
|
||||
first = b.tokenStartingAt(loc) and
|
||||
last = b.tokenEndingAt(loc) and
|
||||
b.getEquivalenceClass() = equivClass
|
||||
)
|
||||
}
|
||||
|
||||
deprecated private Stmt statementInMethod(FunctionDeclarationEntry m) {
|
||||
result.getParent+() = m.getBlock() and
|
||||
not result.getLocation() instanceof UnknownStmtLocation and
|
||||
not result instanceof BlockStmt
|
||||
}
|
||||
|
||||
deprecated private predicate duplicateStatement(
|
||||
FunctionDeclarationEntry m1, FunctionDeclarationEntry m2, Stmt s1, Stmt s2
|
||||
) {
|
||||
exists(int equivClass, int first, int last |
|
||||
s1 = statementInMethod(m1) and
|
||||
s2 = statementInMethod(m2) and
|
||||
blockCoversStatement(equivClass, first, last, s1) and
|
||||
blockCoversStatement(equivClass, first, last, s2) and
|
||||
s1 != s2 and
|
||||
m1 != m2
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Information on duplicated statements is no longer available.
|
||||
*
|
||||
* Holds if `m1` is a function with `total` lines, and `m2` is a function
|
||||
* that has `duplicate` lines in common with `m1`.
|
||||
*/
|
||||
deprecated predicate duplicateStatements(
|
||||
FunctionDeclarationEntry m1, FunctionDeclarationEntry m2, int duplicate, int total
|
||||
) {
|
||||
duplicate = strictcount(Stmt s | duplicateStatement(m1, m2, s, _)) and
|
||||
total = strictcount(statementInMethod(m1))
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Information on duplicated methods is no longer available.
|
||||
*
|
||||
* Holds if `m` and other are identical functions.
|
||||
*/
|
||||
deprecated predicate duplicateMethod(FunctionDeclarationEntry m, FunctionDeclarationEntry other) {
|
||||
exists(int total | duplicateStatements(m, other, total, total))
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Information on similar lines is no longer available.
|
||||
*
|
||||
* INTERNAL: do not use.
|
||||
*
|
||||
* Holds if `line` in `f` is similar to a line somewhere else.
|
||||
*/
|
||||
deprecated predicate similarLines(File f, int line) {
|
||||
exists(SimilarBlock b | b.sourceFile() = f and line in [b.sourceStartLine() .. b.sourceEndLine()])
|
||||
}
|
||||
|
||||
deprecated private predicate similarLinesPerEquivalenceClass(int equivClass, int lines, File f) {
|
||||
lines =
|
||||
strictsum(SimilarBlock b, int toSum |
|
||||
(b.sourceFile() = f and b.getEquivalenceClass() = equivClass) and
|
||||
toSum = b.sourceLines()
|
||||
|
|
||||
toSum
|
||||
)
|
||||
}
|
||||
|
||||
deprecated private predicate similarLinesCoveredFiles(File f, File otherFile) {
|
||||
exists(int numLines | numLines = f.getMetrics().getNumberOfLines() |
|
||||
exists(int coveredApprox |
|
||||
coveredApprox =
|
||||
strictsum(int num |
|
||||
exists(int equivClass |
|
||||
similarLinesPerEquivalenceClass(equivClass, num, f) and
|
||||
similarLinesPerEquivalenceClass(equivClass, num, otherFile) and
|
||||
f != otherFile
|
||||
)
|
||||
) and
|
||||
(coveredApprox * 100) / numLines > 75
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Information on similar lines is no longer available.
|
||||
*
|
||||
* Holds if `coveredLines` lines of `f` are similar to lines in `otherFile`.
|
||||
*/
|
||||
deprecated predicate similarLinesCovered(File f, int coveredLines, File otherFile) {
|
||||
exists(int numLines | numLines = f.getMetrics().getNumberOfLines() |
|
||||
similarLinesCoveredFiles(f, otherFile) and
|
||||
exists(int notCovered |
|
||||
notCovered =
|
||||
count(int j |
|
||||
j in [1 .. numLines] and
|
||||
not similarLines(f, j)
|
||||
) and
|
||||
coveredLines = numLines - notCovered
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Information on duplicate lines is no longer available.
|
||||
*
|
||||
* INTERNAL: do not use.
|
||||
*
|
||||
* Holds if `line` in `f` is duplicated by a line somewhere else.
|
||||
*/
|
||||
deprecated predicate duplicateLines(File f, int line) {
|
||||
exists(DuplicateBlock b |
|
||||
b.sourceFile() = f and line in [b.sourceStartLine() .. b.sourceEndLine()]
|
||||
)
|
||||
}
|
||||
|
||||
deprecated private predicate duplicateLinesPerEquivalenceClass(int equivClass, int lines, File f) {
|
||||
lines =
|
||||
strictsum(DuplicateBlock b, int toSum |
|
||||
(b.sourceFile() = f and b.getEquivalenceClass() = equivClass) and
|
||||
toSum = b.sourceLines()
|
||||
|
|
||||
toSum
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Information on duplicate lines is no longer available.
|
||||
*
|
||||
* Holds if `coveredLines` lines of `f` are duplicates of lines in `otherFile`.
|
||||
*/
|
||||
deprecated predicate duplicateLinesCovered(File f, int coveredLines, File otherFile) {
|
||||
exists(int numLines | numLines = f.getMetrics().getNumberOfLines() |
|
||||
exists(int coveredApprox |
|
||||
coveredApprox =
|
||||
strictsum(int num |
|
||||
exists(int equivClass |
|
||||
duplicateLinesPerEquivalenceClass(equivClass, num, f) and
|
||||
duplicateLinesPerEquivalenceClass(equivClass, num, otherFile) and
|
||||
f != otherFile
|
||||
)
|
||||
) and
|
||||
(coveredApprox * 100) / numLines > 75
|
||||
) and
|
||||
exists(int notCovered |
|
||||
notCovered =
|
||||
count(int j |
|
||||
j in [1 .. numLines] and
|
||||
not duplicateLines(f, j)
|
||||
) and
|
||||
coveredLines = numLines - notCovered
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Information on similar files is no longer available.
|
||||
*
|
||||
* Holds if most of `f` (`percent`%) is similar to `other`.
|
||||
*/
|
||||
deprecated predicate similarFiles(File f, File other, int percent) {
|
||||
exists(int covered, int total |
|
||||
similarLinesCovered(f, covered, other) and
|
||||
total = f.getMetrics().getNumberOfLines() and
|
||||
covered * 100 / total = percent and
|
||||
percent > 80
|
||||
) and
|
||||
not duplicateFiles(f, other, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Information on duplicate files is no longer available.
|
||||
*
|
||||
* Holds if most of `f` (`percent`%) is duplicated by `other`.
|
||||
*/
|
||||
deprecated predicate duplicateFiles(File f, File other, int percent) {
|
||||
exists(int covered, int total |
|
||||
duplicateLinesCovered(f, covered, other) and
|
||||
total = f.getMetrics().getNumberOfLines() and
|
||||
covered * 100 / total = percent and
|
||||
percent > 70
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Information on duplicate classes is no longer available.
|
||||
*
|
||||
* Holds if most member functions of `c` (`numDup` out of `total`) are
|
||||
* duplicates of member functions in `other`.
|
||||
*/
|
||||
deprecated predicate mostlyDuplicateClassBase(Class c, Class other, int numDup, int total) {
|
||||
numDup =
|
||||
strictcount(FunctionDeclarationEntry m1 |
|
||||
exists(FunctionDeclarationEntry m2 |
|
||||
duplicateMethod(m1, m2) and
|
||||
m1 = sourceMethod() and
|
||||
exists(Function f | f = m1.getFunction() and f.getDeclaringType() = c) and
|
||||
exists(Function f | f = m2.getFunction() and f.getDeclaringType() = other) and
|
||||
c != other
|
||||
)
|
||||
) and
|
||||
total = numberOfSourceMethods(c) and
|
||||
(numDup * 100) / total > 80
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Information on duplicate classes is no longer available.
|
||||
*
|
||||
* Holds if most member functions of `c` are duplicates of member functions in
|
||||
* `other`. Provides the human-readable `message` to describe the amount of
|
||||
* duplication.
|
||||
*/
|
||||
deprecated predicate mostlyDuplicateClass(Class c, Class other, string message) {
|
||||
exists(int numDup, int total |
|
||||
mostlyDuplicateClassBase(c, other, numDup, total) and
|
||||
(
|
||||
total != numDup and
|
||||
exists(string s1, string s2, string s3, string name |
|
||||
s1 = " out of " and
|
||||
s2 = " methods in " and
|
||||
s3 = " are duplicated in $@." and
|
||||
name = c.getName()
|
||||
|
|
||||
message = numDup + s1 + total + s2 + name + s3
|
||||
)
|
||||
or
|
||||
total = numDup and
|
||||
exists(string s1, string s2, string name |
|
||||
s1 = "All methods in " and s2 = " are identical in $@." and name = c.getName()
|
||||
|
|
||||
message = s1 + name + s2
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Information on file duplication is no longer available.
|
||||
*
|
||||
* Holds if `f` and `other` are similar or duplicates.
|
||||
*/
|
||||
deprecated predicate fileLevelDuplication(File f, File other) {
|
||||
similarFiles(f, other, _) or duplicateFiles(f, other, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Information on class duplication is no longer available.
|
||||
*
|
||||
* Holds if most member functions of `c` are duplicates of member functions in
|
||||
* `other`.
|
||||
*/
|
||||
deprecated predicate classLevelDuplication(Class c, Class other) {
|
||||
mostlyDuplicateClass(c, other, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: The CodeDuplication library will be removed in a future release.
|
||||
*
|
||||
* Holds if `line` in `f` should be allowed to be duplicated. This is the case
|
||||
* for `#include` directives.
|
||||
*/
|
||||
deprecated predicate whitelistedLineForDuplication(File f, int line) {
|
||||
exists(Include i | i.getFile() = f and i.getLocation().getStartLine() = line)
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-queries
|
||||
version: 0.6.2-dev
|
||||
version: 0.6.4-dev
|
||||
groups:
|
||||
- cpp
|
||||
- queries
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
| test.cpp:18:6:18:10 | ... > ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:18:6:18:8 | ... + ... | addition |
|
||||
| test.cpp:19:6:19:10 | ... > ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:19:6:19:8 | ... + ... | addition |
|
||||
| test.cpp:20:6:20:10 | ... > ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:20:6:20:8 | ... + ... | addition |
|
||||
| test.cpp:21:6:21:10 | ... > ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:21:6:21:8 | ... + ... | addition |
|
||||
| test.cpp:22:6:22:10 | ... > ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:22:8:22:10 | ... + ... | addition |
|
||||
| test.cpp:23:6:23:10 | ... > ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:23:8:23:10 | ... + ... | addition |
|
||||
| test.cpp:24:6:24:10 | ... > ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:24:8:24:10 | ... + ... | addition |
|
||||
| test.cpp:25:6:25:10 | ... > ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:25:8:25:10 | ... + ... | addition |
|
||||
| test.cpp:27:6:27:11 | ... >= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:27:6:27:8 | ... + ... | addition |
|
||||
| test.cpp:28:6:28:11 | ... >= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:28:6:28:8 | ... + ... | addition |
|
||||
| test.cpp:29:6:29:11 | ... >= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:29:6:29:8 | ... + ... | addition |
|
||||
| test.cpp:30:6:30:11 | ... >= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:30:6:30:8 | ... + ... | addition |
|
||||
| test.cpp:31:6:31:11 | ... >= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:31:9:31:11 | ... + ... | addition |
|
||||
| test.cpp:32:6:32:11 | ... >= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:32:9:32:11 | ... + ... | addition |
|
||||
| test.cpp:33:6:33:11 | ... >= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:33:9:33:11 | ... + ... | addition |
|
||||
| test.cpp:34:6:34:11 | ... >= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:34:9:34:11 | ... + ... | addition |
|
||||
| test.cpp:36:6:36:10 | ... < ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:36:6:36:8 | ... + ... | addition |
|
||||
| test.cpp:37:6:37:10 | ... < ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:37:6:37:8 | ... + ... | addition |
|
||||
| test.cpp:38:6:38:10 | ... < ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:38:6:38:8 | ... + ... | addition |
|
||||
| test.cpp:39:6:39:10 | ... < ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:39:6:39:8 | ... + ... | addition |
|
||||
| test.cpp:40:6:40:10 | ... < ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:40:8:40:10 | ... + ... | addition |
|
||||
| test.cpp:41:6:41:10 | ... < ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:41:8:41:10 | ... + ... | addition |
|
||||
| test.cpp:42:6:42:10 | ... < ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:42:8:42:10 | ... + ... | addition |
|
||||
| test.cpp:43:6:43:10 | ... < ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:43:8:43:10 | ... + ... | addition |
|
||||
| test.cpp:45:6:45:11 | ... <= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:45:6:45:8 | ... + ... | addition |
|
||||
| test.cpp:46:6:46:11 | ... <= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:46:6:46:8 | ... + ... | addition |
|
||||
| test.cpp:47:6:47:11 | ... <= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:47:6:47:8 | ... + ... | addition |
|
||||
| test.cpp:48:6:48:11 | ... <= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:48:6:48:8 | ... + ... | addition |
|
||||
| test.cpp:49:6:49:11 | ... <= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:49:9:49:11 | ... + ... | addition |
|
||||
| test.cpp:50:6:50:11 | ... <= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:50:9:50:11 | ... + ... | addition |
|
||||
| test.cpp:51:6:51:11 | ... <= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:51:9:51:11 | ... + ... | addition |
|
||||
| test.cpp:52:6:52:11 | ... <= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:52:9:52:11 | ... + ... | addition |
|
||||
| test.cpp:54:6:54:10 | ... > ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:54:6:54:8 | ... + ... | addition |
|
||||
| test.cpp:61:6:61:11 | ... <= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:61:6:61:8 | ... + ... | addition |
|
||||
| test.cpp:62:6:62:11 | ... <= ... | "if (a+b>c) a=c-b" was detected where the $@ may potentially overflow/wraparound. The code can be rewritten as "if (a>c-b) a=c-b" which avoids the overflow. | test.cpp:62:6:62:8 | ... + ... | addition |
|
||||
@@ -0,0 +1 @@
|
||||
experimental/Security/CWE/CWE-190/IfStatementAdditionOverflow.ql
|
||||
@@ -0,0 +1,63 @@
|
||||
|
||||
int getAnInt();
|
||||
double getADouble();
|
||||
unsigned short getAnUnsignedShort();
|
||||
|
||||
void test()
|
||||
{
|
||||
int a = getAnInt();
|
||||
int b = getAnInt();
|
||||
int c = getAnInt();
|
||||
int x = getAnInt();
|
||||
int y = getAnInt();
|
||||
double d = getADouble();
|
||||
unsigned short a1 = getAnUnsignedShort();
|
||||
unsigned short b1 = getAnUnsignedShort();
|
||||
unsigned short c1 = getAnUnsignedShort();
|
||||
|
||||
if (a+b>c) a = c-b; // BAD
|
||||
if (a+b>c) { a = c-b; } // BAD
|
||||
if (b+a>c) a = c-b; // BAD
|
||||
if (b+a>c) { a = c-b; } // BAD
|
||||
if (c>a+b) a = c-b; // BAD
|
||||
if (c>a+b) { a = c-b; } // BAD
|
||||
if (c>b+a) a = c-b; // BAD
|
||||
if (c>b+a) { a = c-b; } // BAD
|
||||
|
||||
if (a+b>=c) a = c-b; // BAD
|
||||
if (a+b>=c) { a = c-b; } // BAD
|
||||
if (b+a>=c) a = c-b; // BAD
|
||||
if (b+a>=c) { a = c-b; } // BAD
|
||||
if (c>=a+b) a = c-b; // BAD
|
||||
if (c>=a+b) { a = c-b; } // BAD
|
||||
if (c>=b+a) a = c-b; // BAD
|
||||
if (c>=b+a) { a = c-b; } // BAD
|
||||
|
||||
if (a+b<c) a = c-b; // BAD
|
||||
if (a+b<c) { a = c-b; } // BAD
|
||||
if (b+a<c) a = c-b; // BAD
|
||||
if (b+a<c) { a = c-b; } // BAD
|
||||
if (c<a+b) a = c-b; // BAD
|
||||
if (c<a+b) { a = c-b; } // BAD
|
||||
if (c<b+a) a = c-b; // BAD
|
||||
if (c<b+a) { a = c-b; } // BAD
|
||||
|
||||
if (a+b<=c) a = c-b; // BAD
|
||||
if (a+b<=c) { a = c-b; } // BAD
|
||||
if (b+a<=c) a = c-b; // BAD
|
||||
if (b+a<=c) { a = c-b; } // BAD
|
||||
if (c<=a+b) a = c-b; // BAD
|
||||
if (c<=a+b) { a = c-b; } // BAD
|
||||
if (c<=b+a) a = c-b; // BAD
|
||||
if (c<=b+a) { a = c-b; } // BAD
|
||||
|
||||
if (a+b>d) a = d-b; // BAD
|
||||
if (a+(double)b>c) a = c-b; // GOOD
|
||||
if (a+(-x)>c) a = c-(-y); // GOOD
|
||||
if (a+b>c) { b++; a = c-b; } // GOOD
|
||||
if (a+d>c) a = c-d; // GOOD
|
||||
if (a1+b1>c1) a1 = c1-b1; // GOOD
|
||||
|
||||
if (a+b<=c) { /* ... */ } else { a = c-b; } // BAD
|
||||
if (a+b<=c) { return; } a = c-b; // BAD
|
||||
}
|
||||
@@ -663,26 +663,509 @@ edges
|
||||
| test.cpp:326:15:326:23 | ... + ... | test.cpp:342:8:342:17 | * ... |
|
||||
| test.cpp:338:8:338:15 | * ... | test.cpp:342:8:342:17 | * ... |
|
||||
| test.cpp:341:8:341:17 | * ... | test.cpp:342:8:342:17 | * ... |
|
||||
| test.cpp:342:8:342:17 | * ... | test.cpp:333:5:333:21 | Store: ... = ... |
|
||||
| test.cpp:342:8:342:17 | * ... | test.cpp:341:5:341:21 | Store: ... = ... |
|
||||
| test.cpp:347:14:347:27 | new[] | test.cpp:348:15:348:16 | xs |
|
||||
| test.cpp:348:15:348:16 | xs | test.cpp:350:16:350:19 | ... ++ |
|
||||
| test.cpp:348:15:348:16 | xs | test.cpp:350:16:350:19 | ... ++ |
|
||||
| test.cpp:350:16:350:19 | ... ++ | test.cpp:350:15:350:19 | Load: * ... |
|
||||
| test.cpp:350:16:350:19 | ... ++ | test.cpp:350:16:350:19 | ... ++ |
|
||||
| test.cpp:350:16:350:19 | ... ++ | test.cpp:350:16:350:19 | ... ++ |
|
||||
| test.cpp:355:14:355:27 | new[] | test.cpp:356:15:356:16 | xs |
|
||||
| test.cpp:356:15:356:16 | xs | test.cpp:356:15:356:23 | ... + ... |
|
||||
| test.cpp:356:15:356:16 | xs | test.cpp:356:15:356:23 | ... + ... |
|
||||
| test.cpp:356:15:356:16 | xs | test.cpp:356:15:356:23 | ... + ... |
|
||||
| test.cpp:356:15:356:16 | xs | test.cpp:356:15:356:23 | ... + ... |
|
||||
| test.cpp:356:15:356:16 | xs | test.cpp:357:24:357:26 | end |
|
||||
| test.cpp:356:15:356:16 | xs | test.cpp:357:24:357:30 | ... + ... |
|
||||
| test.cpp:356:15:356:16 | xs | test.cpp:357:24:357:30 | ... + ... |
|
||||
| test.cpp:356:15:356:16 | xs | test.cpp:357:24:357:30 | ... + ... |
|
||||
| test.cpp:356:15:356:16 | xs | test.cpp:357:24:357:30 | ... + ... |
|
||||
| test.cpp:356:15:356:16 | xs | test.cpp:358:15:358:26 | end_plus_one |
|
||||
| test.cpp:356:15:356:16 | xs | test.cpp:358:15:358:26 | end_plus_one |
|
||||
| test.cpp:356:15:356:16 | xs | test.cpp:359:16:359:27 | end_plus_one |
|
||||
| test.cpp:356:15:356:16 | xs | test.cpp:359:16:359:31 | ... + ... |
|
||||
| test.cpp:356:15:356:23 | ... + ... | test.cpp:356:15:356:23 | ... + ... |
|
||||
| test.cpp:356:15:356:23 | ... + ... | test.cpp:356:15:356:23 | ... + ... |
|
||||
| test.cpp:356:15:356:23 | ... + ... | test.cpp:357:24:357:26 | end |
|
||||
| test.cpp:356:15:356:23 | ... + ... | test.cpp:357:24:357:26 | end |
|
||||
| test.cpp:356:15:356:23 | ... + ... | test.cpp:358:14:358:26 | Load: * ... |
|
||||
| test.cpp:356:15:356:23 | ... + ... | test.cpp:358:14:358:26 | Load: * ... |
|
||||
| test.cpp:356:15:356:23 | ... + ... | test.cpp:358:14:358:26 | Load: * ... |
|
||||
| test.cpp:356:15:356:23 | ... + ... | test.cpp:358:14:358:26 | Load: * ... |
|
||||
| test.cpp:356:15:356:23 | ... + ... | test.cpp:359:14:359:32 | Load: * ... |
|
||||
| test.cpp:356:15:356:23 | ... + ... | test.cpp:359:14:359:32 | Load: * ... |
|
||||
| test.cpp:356:15:356:23 | ... + ... | test.cpp:359:14:359:32 | Load: * ... |
|
||||
| test.cpp:356:15:356:23 | ... + ... | test.cpp:359:14:359:32 | Load: * ... |
|
||||
| test.cpp:357:24:357:26 | end | test.cpp:358:14:358:26 | Load: * ... |
|
||||
| test.cpp:357:24:357:26 | end | test.cpp:359:14:359:32 | Load: * ... |
|
||||
| test.cpp:357:24:357:30 | ... + ... | test.cpp:357:24:357:30 | ... + ... |
|
||||
| test.cpp:357:24:357:30 | ... + ... | test.cpp:357:24:357:30 | ... + ... |
|
||||
| test.cpp:357:24:357:30 | ... + ... | test.cpp:358:14:358:26 | Load: * ... |
|
||||
| test.cpp:357:24:357:30 | ... + ... | test.cpp:358:14:358:26 | Load: * ... |
|
||||
| test.cpp:357:24:357:30 | ... + ... | test.cpp:358:14:358:26 | Load: * ... |
|
||||
| test.cpp:357:24:357:30 | ... + ... | test.cpp:358:14:358:26 | Load: * ... |
|
||||
| test.cpp:357:24:357:30 | ... + ... | test.cpp:358:15:358:26 | end_plus_one |
|
||||
| test.cpp:357:24:357:30 | ... + ... | test.cpp:358:15:358:26 | end_plus_one |
|
||||
| test.cpp:357:24:357:30 | ... + ... | test.cpp:358:15:358:26 | end_plus_one |
|
||||
| test.cpp:357:24:357:30 | ... + ... | test.cpp:358:15:358:26 | end_plus_one |
|
||||
| test.cpp:357:24:357:30 | ... + ... | test.cpp:359:14:359:32 | Load: * ... |
|
||||
| test.cpp:357:24:357:30 | ... + ... | test.cpp:359:14:359:32 | Load: * ... |
|
||||
| test.cpp:357:24:357:30 | ... + ... | test.cpp:359:14:359:32 | Load: * ... |
|
||||
| test.cpp:357:24:357:30 | ... + ... | test.cpp:359:14:359:32 | Load: * ... |
|
||||
| test.cpp:357:24:357:30 | ... + ... | test.cpp:359:16:359:27 | end_plus_one |
|
||||
| test.cpp:357:24:357:30 | ... + ... | test.cpp:359:16:359:27 | end_plus_one |
|
||||
| test.cpp:358:15:358:26 | end_plus_one | test.cpp:358:14:358:26 | Load: * ... |
|
||||
| test.cpp:358:15:358:26 | end_plus_one | test.cpp:358:14:358:26 | Load: * ... |
|
||||
| test.cpp:358:15:358:26 | end_plus_one | test.cpp:359:14:359:32 | Load: * ... |
|
||||
| test.cpp:358:15:358:26 | end_plus_one | test.cpp:359:14:359:32 | Load: * ... |
|
||||
| test.cpp:358:15:358:26 | end_plus_one | test.cpp:359:16:359:27 | end_plus_one |
|
||||
| test.cpp:359:16:359:27 | end_plus_one | test.cpp:358:14:358:26 | Load: * ... |
|
||||
| test.cpp:359:16:359:27 | end_plus_one | test.cpp:359:14:359:32 | Load: * ... |
|
||||
| test.cpp:359:16:359:31 | ... + ... | test.cpp:359:14:359:32 | Load: * ... |
|
||||
| test.cpp:363:14:363:27 | new[] | test.cpp:365:15:365:15 | p |
|
||||
| test.cpp:365:15:365:15 | p | test.cpp:368:5:368:10 | ... += ... |
|
||||
| test.cpp:365:15:365:15 | p | test.cpp:368:5:368:10 | ... += ... |
|
||||
| test.cpp:368:5:368:10 | ... += ... | test.cpp:371:7:371:7 | p |
|
||||
| test.cpp:368:5:368:10 | ... += ... | test.cpp:371:7:371:7 | p |
|
||||
| test.cpp:368:5:368:10 | ... += ... | test.cpp:372:16:372:16 | p |
|
||||
| test.cpp:368:5:368:10 | ... += ... | test.cpp:372:16:372:16 | p |
|
||||
| test.cpp:371:7:371:7 | p | test.cpp:372:15:372:16 | Load: * ... |
|
||||
| test.cpp:372:16:372:16 | p | test.cpp:372:15:372:16 | Load: * ... |
|
||||
| test.cpp:377:14:377:27 | new[] | test.cpp:378:15:378:16 | xs |
|
||||
| test.cpp:378:15:378:16 | xs | test.cpp:378:15:378:23 | ... + ... |
|
||||
| test.cpp:378:15:378:16 | xs | test.cpp:378:15:378:23 | ... + ... |
|
||||
| test.cpp:378:15:378:16 | xs | test.cpp:378:15:378:23 | ... + ... |
|
||||
| test.cpp:378:15:378:16 | xs | test.cpp:378:15:378:23 | ... + ... |
|
||||
| test.cpp:378:15:378:16 | xs | test.cpp:381:5:381:7 | end |
|
||||
| test.cpp:378:15:378:16 | xs | test.cpp:381:5:381:9 | ... ++ |
|
||||
| test.cpp:378:15:378:16 | xs | test.cpp:381:5:381:9 | ... ++ |
|
||||
| test.cpp:378:15:378:16 | xs | test.cpp:384:14:384:16 | end |
|
||||
| test.cpp:378:15:378:23 | ... + ... | test.cpp:378:15:378:23 | ... + ... |
|
||||
| test.cpp:378:15:378:23 | ... + ... | test.cpp:378:15:378:23 | ... + ... |
|
||||
| test.cpp:378:15:378:23 | ... + ... | test.cpp:381:5:381:7 | end |
|
||||
| test.cpp:378:15:378:23 | ... + ... | test.cpp:381:5:381:7 | end |
|
||||
| test.cpp:378:15:378:23 | ... + ... | test.cpp:384:13:384:16 | Load: * ... |
|
||||
| test.cpp:378:15:378:23 | ... + ... | test.cpp:384:13:384:16 | Load: * ... |
|
||||
| test.cpp:378:15:378:23 | ... + ... | test.cpp:384:13:384:16 | Load: * ... |
|
||||
| test.cpp:378:15:378:23 | ... + ... | test.cpp:384:13:384:16 | Load: * ... |
|
||||
| test.cpp:378:15:378:23 | ... + ... | test.cpp:384:14:384:16 | end |
|
||||
| test.cpp:378:15:378:23 | ... + ... | test.cpp:384:14:384:16 | end |
|
||||
| test.cpp:381:5:381:7 | end | test.cpp:384:13:384:16 | Load: * ... |
|
||||
| test.cpp:381:5:381:9 | ... ++ | test.cpp:384:14:384:16 | end |
|
||||
| test.cpp:381:5:381:9 | ... ++ | test.cpp:384:14:384:16 | end |
|
||||
| test.cpp:384:14:384:16 | end | test.cpp:384:13:384:16 | Load: * ... |
|
||||
| test.cpp:388:14:388:27 | new[] | test.cpp:389:16:389:17 | xs |
|
||||
| test.cpp:388:14:388:27 | new[] | test.cpp:392:5:392:6 | xs |
|
||||
| test.cpp:389:16:389:17 | xs | test.cpp:392:5:392:8 | ... ++ |
|
||||
| test.cpp:389:16:389:17 | xs | test.cpp:392:5:392:8 | ... ++ |
|
||||
| test.cpp:389:16:389:17 | xs | test.cpp:392:5:392:8 | ... ++ |
|
||||
| test.cpp:389:16:389:17 | xs | test.cpp:392:5:392:8 | ... ++ |
|
||||
| test.cpp:389:16:389:17 | xs | test.cpp:393:9:393:10 | xs |
|
||||
| test.cpp:389:16:389:17 | xs | test.cpp:393:9:393:10 | xs |
|
||||
| test.cpp:392:5:392:8 | ... ++ | test.cpp:392:5:392:8 | ... ++ |
|
||||
| test.cpp:392:5:392:8 | ... ++ | test.cpp:392:5:392:8 | ... ++ |
|
||||
| test.cpp:392:5:392:8 | ... ++ | test.cpp:393:9:393:10 | xs |
|
||||
| test.cpp:392:5:392:8 | ... ++ | test.cpp:393:9:393:10 | xs |
|
||||
| test.cpp:392:5:392:8 | ... ++ | test.cpp:393:9:393:10 | xs |
|
||||
| test.cpp:392:5:392:8 | ... ++ | test.cpp:393:9:393:10 | xs |
|
||||
| test.cpp:392:5:392:8 | ... ++ | test.cpp:395:5:395:6 | xs |
|
||||
| test.cpp:392:5:392:8 | ... ++ | test.cpp:395:5:395:6 | xs |
|
||||
| test.cpp:392:5:392:8 | ... ++ | test.cpp:395:5:395:13 | Store: ... = ... |
|
||||
| test.cpp:392:5:392:8 | ... ++ | test.cpp:395:5:395:13 | Store: ... = ... |
|
||||
| test.cpp:392:5:392:8 | ... ++ | test.cpp:395:5:395:13 | Store: ... = ... |
|
||||
| test.cpp:392:5:392:8 | ... ++ | test.cpp:395:5:395:13 | Store: ... = ... |
|
||||
| test.cpp:393:9:393:10 | xs | test.cpp:395:5:395:6 | xs |
|
||||
| test.cpp:393:9:393:10 | xs | test.cpp:395:5:395:13 | Store: ... = ... |
|
||||
| test.cpp:393:9:393:10 | xs | test.cpp:395:5:395:13 | Store: ... = ... |
|
||||
| test.cpp:395:5:395:6 | xs | test.cpp:395:5:395:13 | Store: ... = ... |
|
||||
| test.cpp:404:3:404:25 | ... = ... | test.cpp:404:7:404:8 | val indirection [post update] [xs] |
|
||||
| test.cpp:404:7:404:8 | val indirection [post update] [xs] | test.cpp:407:3:407:5 | val indirection [xs] |
|
||||
| test.cpp:404:12:404:25 | new[] | test.cpp:404:3:404:25 | ... = ... |
|
||||
| test.cpp:406:3:406:25 | ... = ... | test.cpp:406:7:406:8 | val indirection [post update] [xs] |
|
||||
| test.cpp:406:7:406:8 | val indirection [post update] [xs] | test.cpp:407:3:407:5 | val indirection [xs] |
|
||||
| test.cpp:406:12:406:25 | new[] | test.cpp:406:3:406:25 | ... = ... |
|
||||
| test.cpp:407:3:407:5 | val indirection [xs] | test.cpp:407:7:407:8 | xs indirection |
|
||||
| test.cpp:407:3:407:18 | access to array | test.cpp:407:3:407:22 | Store: ... = ... |
|
||||
| test.cpp:407:7:407:8 | xs | test.cpp:407:3:407:18 | access to array |
|
||||
| test.cpp:407:7:407:8 | xs indirection | test.cpp:407:7:407:8 | xs |
|
||||
| test.cpp:417:16:417:33 | new[] | test.cpp:419:7:419:8 | xs |
|
||||
| test.cpp:419:7:419:8 | xs | test.cpp:419:7:419:11 | access to array |
|
||||
| test.cpp:419:7:419:11 | access to array | test.cpp:419:7:419:15 | Store: ... = ... |
|
||||
| test.cpp:427:14:427:27 | new[] | test.cpp:433:5:433:6 | xs |
|
||||
| test.cpp:433:5:433:6 | xs | test.cpp:433:5:433:17 | access to array |
|
||||
| test.cpp:433:5:433:17 | access to array | test.cpp:433:5:433:21 | Store: ... = ... |
|
||||
nodes
|
||||
| test.cpp:4:15:4:20 | call to malloc | semmle.label | call to malloc |
|
||||
| test.cpp:5:15:5:15 | p | semmle.label | p |
|
||||
| test.cpp:5:15:5:22 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:5:15:5:22 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:5:15:5:22 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:5:15:5:22 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:6:14:6:15 | Load: * ... | semmle.label | Load: * ... |
|
||||
| test.cpp:6:15:6:15 | q | semmle.label | q |
|
||||
| test.cpp:6:15:6:15 | q | semmle.label | q |
|
||||
| test.cpp:7:16:7:16 | q | semmle.label | q |
|
||||
| test.cpp:7:16:7:16 | q | semmle.label | q |
|
||||
| test.cpp:8:14:8:21 | Load: * ... | semmle.label | Load: * ... |
|
||||
| test.cpp:8:16:8:16 | q | semmle.label | q |
|
||||
| test.cpp:8:16:8:16 | q | semmle.label | q |
|
||||
| test.cpp:8:16:8:20 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:9:16:9:16 | q | semmle.label | q |
|
||||
| test.cpp:9:16:9:16 | q | semmle.label | q |
|
||||
| test.cpp:10:16:10:16 | q | semmle.label | q |
|
||||
| test.cpp:10:16:10:16 | q | semmle.label | q |
|
||||
| test.cpp:11:16:11:16 | q | semmle.label | q |
|
||||
| test.cpp:11:16:11:16 | q | semmle.label | q |
|
||||
| test.cpp:12:16:12:16 | q | semmle.label | q |
|
||||
| test.cpp:16:15:16:20 | call to malloc | semmle.label | call to malloc |
|
||||
| test.cpp:17:15:17:15 | p | semmle.label | p |
|
||||
| test.cpp:17:15:17:22 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:20:14:20:21 | Load: * ... | semmle.label | Load: * ... |
|
||||
| test.cpp:20:16:20:20 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:28:15:28:20 | call to malloc | semmle.label | call to malloc |
|
||||
| test.cpp:29:15:29:15 | p | semmle.label | p |
|
||||
| test.cpp:29:15:29:28 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:29:15:29:28 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:29:15:29:28 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:29:15:29:28 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:30:14:30:15 | Load: * ... | semmle.label | Load: * ... |
|
||||
| test.cpp:30:15:30:15 | q | semmle.label | q |
|
||||
| test.cpp:30:15:30:15 | q | semmle.label | q |
|
||||
| test.cpp:31:16:31:16 | q | semmle.label | q |
|
||||
| test.cpp:31:16:31:16 | q | semmle.label | q |
|
||||
| test.cpp:32:14:32:21 | Load: * ... | semmle.label | Load: * ... |
|
||||
| test.cpp:32:16:32:16 | q | semmle.label | q |
|
||||
| test.cpp:32:16:32:16 | q | semmle.label | q |
|
||||
| test.cpp:32:16:32:20 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:33:16:33:16 | q | semmle.label | q |
|
||||
| test.cpp:33:16:33:16 | q | semmle.label | q |
|
||||
| test.cpp:34:16:34:16 | q | semmle.label | q |
|
||||
| test.cpp:34:16:34:16 | q | semmle.label | q |
|
||||
| test.cpp:35:16:35:16 | q | semmle.label | q |
|
||||
| test.cpp:35:16:35:16 | q | semmle.label | q |
|
||||
| test.cpp:36:16:36:16 | q | semmle.label | q |
|
||||
| test.cpp:40:15:40:20 | call to malloc | semmle.label | call to malloc |
|
||||
| test.cpp:41:15:41:15 | p | semmle.label | p |
|
||||
| test.cpp:41:15:41:28 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:41:15:41:28 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:41:15:41:28 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:41:15:41:28 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:42:14:42:15 | Load: * ... | semmle.label | Load: * ... |
|
||||
| test.cpp:42:15:42:15 | q | semmle.label | q |
|
||||
| test.cpp:42:15:42:15 | q | semmle.label | q |
|
||||
| test.cpp:43:16:43:16 | q | semmle.label | q |
|
||||
| test.cpp:43:16:43:16 | q | semmle.label | q |
|
||||
| test.cpp:44:14:44:21 | Load: * ... | semmle.label | Load: * ... |
|
||||
| test.cpp:44:16:44:16 | q | semmle.label | q |
|
||||
| test.cpp:44:16:44:16 | q | semmle.label | q |
|
||||
| test.cpp:44:16:44:20 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:45:16:45:16 | q | semmle.label | q |
|
||||
| test.cpp:45:16:45:16 | q | semmle.label | q |
|
||||
| test.cpp:46:16:46:16 | q | semmle.label | q |
|
||||
| test.cpp:46:16:46:16 | q | semmle.label | q |
|
||||
| test.cpp:47:16:47:16 | q | semmle.label | q |
|
||||
| test.cpp:47:16:47:16 | q | semmle.label | q |
|
||||
| test.cpp:48:16:48:16 | q | semmle.label | q |
|
||||
| test.cpp:51:7:51:14 | mk_array indirection | semmle.label | mk_array indirection |
|
||||
| test.cpp:51:33:51:35 | end | semmle.label | end |
|
||||
| test.cpp:52:19:52:24 | call to malloc | semmle.label | call to malloc |
|
||||
| test.cpp:53:5:53:23 | ... = ... | semmle.label | ... = ... |
|
||||
| test.cpp:53:12:53:16 | begin | semmle.label | begin |
|
||||
| test.cpp:53:12:53:23 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:60:19:60:26 | call to mk_array | semmle.label | call to mk_array |
|
||||
| test.cpp:60:34:60:37 | mk_array output argument | semmle.label | mk_array output argument |
|
||||
| test.cpp:62:32:62:34 | end | semmle.label | end |
|
||||
| test.cpp:62:39:62:39 | p | semmle.label | p |
|
||||
| test.cpp:66:32:66:34 | end | semmle.label | end |
|
||||
| test.cpp:66:39:66:39 | p | semmle.label | p |
|
||||
| test.cpp:67:9:67:14 | Store: ... = ... | semmle.label | Store: ... = ... |
|
||||
| test.cpp:70:31:70:33 | end | semmle.label | end |
|
||||
| test.cpp:70:38:70:38 | p | semmle.label | p |
|
||||
| test.cpp:80:9:80:16 | mk_array indirection [begin] | semmle.label | mk_array indirection [begin] |
|
||||
| test.cpp:80:9:80:16 | mk_array indirection [end] | semmle.label | mk_array indirection [end] |
|
||||
| test.cpp:82:5:82:28 | ... = ... | semmle.label | ... = ... |
|
||||
| test.cpp:82:9:82:13 | arr indirection [post update] [begin] | semmle.label | arr indirection [post update] [begin] |
|
||||
| test.cpp:82:17:82:22 | call to malloc | semmle.label | call to malloc |
|
||||
| test.cpp:83:5:83:30 | ... = ... | semmle.label | ... = ... |
|
||||
| test.cpp:83:9:83:11 | arr indirection [post update] [end] | semmle.label | arr indirection [post update] [end] |
|
||||
| test.cpp:83:15:83:17 | arr indirection [begin] | semmle.label | arr indirection [begin] |
|
||||
| test.cpp:83:15:83:30 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:83:19:83:23 | begin | semmle.label | begin |
|
||||
| test.cpp:83:19:83:23 | begin indirection | semmle.label | begin indirection |
|
||||
| test.cpp:89:19:89:26 | call to mk_array [begin] | semmle.label | call to mk_array [begin] |
|
||||
| test.cpp:89:19:89:26 | call to mk_array [end] | semmle.label | call to mk_array [end] |
|
||||
| test.cpp:91:20:91:22 | arr indirection [begin] | semmle.label | arr indirection [begin] |
|
||||
| test.cpp:91:24:91:28 | begin | semmle.label | begin |
|
||||
| test.cpp:91:24:91:28 | begin indirection | semmle.label | begin indirection |
|
||||
| test.cpp:91:36:91:38 | arr indirection [end] | semmle.label | arr indirection [end] |
|
||||
| test.cpp:91:40:91:42 | end | semmle.label | end |
|
||||
| test.cpp:91:40:91:42 | end indirection | semmle.label | end indirection |
|
||||
| test.cpp:91:47:91:47 | p | semmle.label | p |
|
||||
| test.cpp:95:20:95:22 | arr indirection [begin] | semmle.label | arr indirection [begin] |
|
||||
| test.cpp:95:24:95:28 | begin | semmle.label | begin |
|
||||
| test.cpp:95:24:95:28 | begin indirection | semmle.label | begin indirection |
|
||||
| test.cpp:95:36:95:38 | arr indirection [end] | semmle.label | arr indirection [end] |
|
||||
| test.cpp:95:40:95:42 | end | semmle.label | end |
|
||||
| test.cpp:95:40:95:42 | end indirection | semmle.label | end indirection |
|
||||
| test.cpp:95:47:95:47 | p | semmle.label | p |
|
||||
| test.cpp:96:9:96:14 | Store: ... = ... | semmle.label | Store: ... = ... |
|
||||
| test.cpp:99:20:99:22 | arr indirection [begin] | semmle.label | arr indirection [begin] |
|
||||
| test.cpp:99:24:99:28 | begin | semmle.label | begin |
|
||||
| test.cpp:99:24:99:28 | begin indirection | semmle.label | begin indirection |
|
||||
| test.cpp:99:35:99:37 | arr indirection [end] | semmle.label | arr indirection [end] |
|
||||
| test.cpp:99:39:99:41 | end | semmle.label | end |
|
||||
| test.cpp:99:39:99:41 | end indirection | semmle.label | end indirection |
|
||||
| test.cpp:99:46:99:46 | p | semmle.label | p |
|
||||
| test.cpp:104:27:104:29 | arr [begin] | semmle.label | arr [begin] |
|
||||
| test.cpp:104:27:104:29 | arr [end] | semmle.label | arr [end] |
|
||||
| test.cpp:105:20:105:22 | arr indirection [begin] | semmle.label | arr indirection [begin] |
|
||||
| test.cpp:105:24:105:28 | begin | semmle.label | begin |
|
||||
| test.cpp:105:24:105:28 | begin indirection | semmle.label | begin indirection |
|
||||
| test.cpp:105:36:105:38 | arr indirection [end] | semmle.label | arr indirection [end] |
|
||||
| test.cpp:105:40:105:42 | end | semmle.label | end |
|
||||
| test.cpp:105:40:105:42 | end indirection | semmle.label | end indirection |
|
||||
| test.cpp:105:47:105:47 | p | semmle.label | p |
|
||||
| test.cpp:109:20:109:22 | arr indirection [begin] | semmle.label | arr indirection [begin] |
|
||||
| test.cpp:109:24:109:28 | begin | semmle.label | begin |
|
||||
| test.cpp:109:24:109:28 | begin indirection | semmle.label | begin indirection |
|
||||
| test.cpp:109:36:109:38 | arr indirection [end] | semmle.label | arr indirection [end] |
|
||||
| test.cpp:109:40:109:42 | end | semmle.label | end |
|
||||
| test.cpp:109:40:109:42 | end indirection | semmle.label | end indirection |
|
||||
| test.cpp:109:47:109:47 | p | semmle.label | p |
|
||||
| test.cpp:110:9:110:14 | Store: ... = ... | semmle.label | Store: ... = ... |
|
||||
| test.cpp:113:20:113:22 | arr indirection [begin] | semmle.label | arr indirection [begin] |
|
||||
| test.cpp:113:24:113:28 | begin | semmle.label | begin |
|
||||
| test.cpp:113:24:113:28 | begin indirection | semmle.label | begin indirection |
|
||||
| test.cpp:113:35:113:37 | arr indirection [end] | semmle.label | arr indirection [end] |
|
||||
| test.cpp:113:39:113:41 | end | semmle.label | end |
|
||||
| test.cpp:113:39:113:41 | end indirection | semmle.label | end indirection |
|
||||
| test.cpp:113:46:113:46 | p | semmle.label | p |
|
||||
| test.cpp:119:18:119:25 | call to mk_array [begin] | semmle.label | call to mk_array [begin] |
|
||||
| test.cpp:119:18:119:25 | call to mk_array [end] | semmle.label | call to mk_array [end] |
|
||||
| test.cpp:124:15:124:20 | call to malloc | semmle.label | call to malloc |
|
||||
| test.cpp:125:5:125:17 | ... = ... | semmle.label | ... = ... |
|
||||
| test.cpp:125:9:125:13 | arr indirection [post update] [begin] | semmle.label | arr indirection [post update] [begin] |
|
||||
| test.cpp:126:15:126:15 | p | semmle.label | p |
|
||||
| test.cpp:129:11:129:13 | arr indirection [begin] | semmle.label | arr indirection [begin] |
|
||||
| test.cpp:129:15:129:19 | begin | semmle.label | begin |
|
||||
| test.cpp:129:15:129:19 | begin indirection | semmle.label | begin indirection |
|
||||
| test.cpp:133:11:133:13 | arr indirection [begin] | semmle.label | arr indirection [begin] |
|
||||
| test.cpp:133:15:133:19 | begin | semmle.label | begin |
|
||||
| test.cpp:133:15:133:19 | begin indirection | semmle.label | begin indirection |
|
||||
| test.cpp:137:11:137:13 | arr indirection [begin] | semmle.label | arr indirection [begin] |
|
||||
| test.cpp:137:15:137:19 | begin | semmle.label | begin |
|
||||
| test.cpp:137:15:137:19 | begin indirection | semmle.label | begin indirection |
|
||||
| test.cpp:141:10:141:19 | mk_array_p indirection [begin] | semmle.label | mk_array_p indirection [begin] |
|
||||
| test.cpp:141:10:141:19 | mk_array_p indirection [end] | semmle.label | mk_array_p indirection [end] |
|
||||
| test.cpp:143:5:143:29 | ... = ... | semmle.label | ... = ... |
|
||||
| test.cpp:143:10:143:14 | arr indirection [post update] [begin] | semmle.label | arr indirection [post update] [begin] |
|
||||
| test.cpp:143:18:143:23 | call to malloc | semmle.label | call to malloc |
|
||||
| test.cpp:144:5:144:32 | ... = ... | semmle.label | ... = ... |
|
||||
| test.cpp:144:10:144:12 | arr indirection [post update] [end] | semmle.label | arr indirection [post update] [end] |
|
||||
| test.cpp:144:16:144:18 | arr indirection [begin] | semmle.label | arr indirection [begin] |
|
||||
| test.cpp:144:16:144:32 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:144:21:144:25 | begin | semmle.label | begin |
|
||||
| test.cpp:144:21:144:25 | begin indirection | semmle.label | begin indirection |
|
||||
| test.cpp:150:20:150:29 | call to mk_array_p indirection [begin] | semmle.label | call to mk_array_p indirection [begin] |
|
||||
| test.cpp:150:20:150:29 | call to mk_array_p indirection [end] | semmle.label | call to mk_array_p indirection [end] |
|
||||
| test.cpp:152:20:152:22 | arr indirection [begin] | semmle.label | arr indirection [begin] |
|
||||
| test.cpp:152:25:152:29 | begin | semmle.label | begin |
|
||||
| test.cpp:152:25:152:29 | begin indirection | semmle.label | begin indirection |
|
||||
| test.cpp:152:49:152:49 | p | semmle.label | p |
|
||||
| test.cpp:156:20:156:22 | arr indirection [begin] | semmle.label | arr indirection [begin] |
|
||||
| test.cpp:156:25:156:29 | begin | semmle.label | begin |
|
||||
| test.cpp:156:25:156:29 | begin indirection | semmle.label | begin indirection |
|
||||
| test.cpp:156:37:156:39 | arr indirection [end] | semmle.label | arr indirection [end] |
|
||||
| test.cpp:156:42:156:44 | end | semmle.label | end |
|
||||
| test.cpp:156:42:156:44 | end indirection | semmle.label | end indirection |
|
||||
| test.cpp:156:49:156:49 | p | semmle.label | p |
|
||||
| test.cpp:157:9:157:14 | Store: ... = ... | semmle.label | Store: ... = ... |
|
||||
| test.cpp:160:20:160:22 | arr indirection [begin] | semmle.label | arr indirection [begin] |
|
||||
| test.cpp:160:25:160:29 | begin | semmle.label | begin |
|
||||
| test.cpp:160:25:160:29 | begin indirection | semmle.label | begin indirection |
|
||||
| test.cpp:160:48:160:48 | p | semmle.label | p |
|
||||
| test.cpp:165:29:165:31 | arr indirection [begin] | semmle.label | arr indirection [begin] |
|
||||
| test.cpp:165:29:165:31 | arr indirection [end] | semmle.label | arr indirection [end] |
|
||||
| test.cpp:166:20:166:22 | arr indirection [begin] | semmle.label | arr indirection [begin] |
|
||||
| test.cpp:166:25:166:29 | begin | semmle.label | begin |
|
||||
| test.cpp:166:25:166:29 | begin indirection | semmle.label | begin indirection |
|
||||
| test.cpp:166:37:166:39 | arr indirection [end] | semmle.label | arr indirection [end] |
|
||||
| test.cpp:166:42:166:44 | end | semmle.label | end |
|
||||
| test.cpp:166:42:166:44 | end indirection | semmle.label | end indirection |
|
||||
| test.cpp:166:49:166:49 | p | semmle.label | p |
|
||||
| test.cpp:170:20:170:22 | arr indirection [begin] | semmle.label | arr indirection [begin] |
|
||||
| test.cpp:170:25:170:29 | begin | semmle.label | begin |
|
||||
| test.cpp:170:25:170:29 | begin indirection | semmle.label | begin indirection |
|
||||
| test.cpp:170:37:170:39 | arr indirection [end] | semmle.label | arr indirection [end] |
|
||||
| test.cpp:170:42:170:44 | end | semmle.label | end |
|
||||
| test.cpp:170:42:170:44 | end indirection | semmle.label | end indirection |
|
||||
| test.cpp:170:49:170:49 | p | semmle.label | p |
|
||||
| test.cpp:171:9:171:14 | Store: ... = ... | semmle.label | Store: ... = ... |
|
||||
| test.cpp:174:20:174:22 | arr indirection [begin] | semmle.label | arr indirection [begin] |
|
||||
| test.cpp:174:25:174:29 | begin | semmle.label | begin |
|
||||
| test.cpp:174:25:174:29 | begin indirection | semmle.label | begin indirection |
|
||||
| test.cpp:174:36:174:38 | arr indirection [end] | semmle.label | arr indirection [end] |
|
||||
| test.cpp:174:41:174:43 | end | semmle.label | end |
|
||||
| test.cpp:174:41:174:43 | end indirection | semmle.label | end indirection |
|
||||
| test.cpp:174:48:174:48 | p | semmle.label | p |
|
||||
| test.cpp:180:19:180:28 | call to mk_array_p indirection [begin] | semmle.label | call to mk_array_p indirection [begin] |
|
||||
| test.cpp:180:19:180:28 | call to mk_array_p indirection [end] | semmle.label | call to mk_array_p indirection [end] |
|
||||
| test.cpp:188:15:188:20 | call to malloc | semmle.label | call to malloc |
|
||||
| test.cpp:189:15:189:15 | p | semmle.label | p |
|
||||
| test.cpp:194:23:194:28 | call to malloc | semmle.label | call to malloc |
|
||||
| test.cpp:195:17:195:17 | p | semmle.label | p |
|
||||
| test.cpp:195:17:195:23 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:195:17:195:23 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:195:17:195:23 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:195:17:195:23 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:197:8:197:8 | p | semmle.label | p |
|
||||
| test.cpp:197:20:197:22 | end | semmle.label | end |
|
||||
| test.cpp:201:5:201:5 | p | semmle.label | p |
|
||||
| test.cpp:201:5:201:12 | access to array | semmle.label | access to array |
|
||||
| test.cpp:201:5:201:19 | Store: ... = ... | semmle.label | Store: ... = ... |
|
||||
| test.cpp:205:23:205:28 | call to malloc | semmle.label | call to malloc |
|
||||
| test.cpp:206:17:206:17 | p | semmle.label | p |
|
||||
| test.cpp:206:17:206:23 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:206:17:206:23 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:206:17:206:23 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:206:17:206:23 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:208:15:208:15 | p | semmle.label | p |
|
||||
| test.cpp:209:12:209:14 | end | semmle.label | end |
|
||||
| test.cpp:213:5:213:6 | * ... | semmle.label | * ... |
|
||||
| test.cpp:213:5:213:13 | Store: ... = ... | semmle.label | Store: ... = ... |
|
||||
| test.cpp:213:6:213:6 | q | semmle.label | q |
|
||||
| test.cpp:213:6:213:6 | q | semmle.label | q |
|
||||
| test.cpp:221:17:221:22 | call to malloc | semmle.label | call to malloc |
|
||||
| test.cpp:222:5:222:5 | p | semmle.label | p |
|
||||
| test.cpp:231:18:231:30 | new[] | semmle.label | new[] |
|
||||
| test.cpp:232:3:232:9 | newname | semmle.label | newname |
|
||||
| test.cpp:232:3:232:16 | access to array | semmle.label | access to array |
|
||||
| test.cpp:232:3:232:20 | Store: ... = ... | semmle.label | Store: ... = ... |
|
||||
| test.cpp:238:20:238:32 | new[] | semmle.label | new[] |
|
||||
| test.cpp:239:5:239:11 | newname | semmle.label | newname |
|
||||
| test.cpp:239:5:239:18 | access to array | semmle.label | access to array |
|
||||
| test.cpp:239:5:239:22 | Store: ... = ... | semmle.label | Store: ... = ... |
|
||||
| test.cpp:248:24:248:30 | call to realloc | semmle.label | call to realloc |
|
||||
| test.cpp:249:9:249:9 | p | semmle.label | p |
|
||||
| test.cpp:250:22:250:22 | p | semmle.label | p |
|
||||
| test.cpp:254:9:254:9 | p | semmle.label | p |
|
||||
| test.cpp:254:9:254:12 | access to array | semmle.label | access to array |
|
||||
| test.cpp:254:9:254:16 | Store: ... = ... | semmle.label | Store: ... = ... |
|
||||
| test.cpp:260:13:260:24 | new[] | semmle.label | new[] |
|
||||
| test.cpp:261:14:261:15 | xs | semmle.label | xs |
|
||||
| test.cpp:261:14:261:21 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:261:14:261:21 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:261:14:261:21 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:261:14:261:21 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:262:26:262:28 | end | semmle.label | end |
|
||||
| test.cpp:262:26:262:28 | end | semmle.label | end |
|
||||
| test.cpp:262:31:262:31 | x | semmle.label | x |
|
||||
| test.cpp:264:13:264:14 | Load: * ... | semmle.label | Load: * ... |
|
||||
| test.cpp:264:14:264:14 | x | semmle.label | x |
|
||||
| test.cpp:264:14:264:14 | x | semmle.label | x |
|
||||
| test.cpp:270:13:270:24 | new[] | semmle.label | new[] |
|
||||
| test.cpp:271:14:271:15 | xs | semmle.label | xs |
|
||||
| test.cpp:271:14:271:21 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:271:14:271:21 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:271:14:271:21 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:271:14:271:21 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:272:26:272:28 | end | semmle.label | end |
|
||||
| test.cpp:272:26:272:28 | end | semmle.label | end |
|
||||
| test.cpp:272:31:272:31 | x | semmle.label | x |
|
||||
| test.cpp:272:31:272:31 | x | semmle.label | x |
|
||||
| test.cpp:274:5:274:6 | * ... | semmle.label | * ... |
|
||||
| test.cpp:274:5:274:10 | Store: ... = ... | semmle.label | Store: ... = ... |
|
||||
| test.cpp:274:6:274:6 | x | semmle.label | x |
|
||||
| test.cpp:274:6:274:6 | x | semmle.label | x |
|
||||
| test.cpp:280:13:280:24 | new[] | semmle.label | new[] |
|
||||
| test.cpp:281:14:281:15 | xs | semmle.label | xs |
|
||||
| test.cpp:290:13:290:24 | new[] | semmle.label | new[] |
|
||||
| test.cpp:291:14:291:15 | xs | semmle.label | xs |
|
||||
| test.cpp:292:30:292:30 | x | semmle.label | x |
|
||||
| test.cpp:304:15:304:26 | new[] | semmle.label | new[] |
|
||||
| test.cpp:307:5:307:6 | xs | semmle.label | xs |
|
||||
| test.cpp:308:5:308:6 | xs | semmle.label | xs |
|
||||
| test.cpp:308:5:308:11 | access to array | semmle.label | access to array |
|
||||
| test.cpp:308:5:308:29 | Store: ... = ... | semmle.label | Store: ... = ... |
|
||||
| test.cpp:313:14:313:27 | new[] | semmle.label | new[] |
|
||||
| test.cpp:314:15:314:16 | xs | semmle.label | xs |
|
||||
| test.cpp:325:14:325:27 | new[] | semmle.label | new[] |
|
||||
| test.cpp:326:15:326:16 | xs | semmle.label | xs |
|
||||
| test.cpp:326:15:326:23 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:326:15:326:23 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:338:8:338:15 | * ... | semmle.label | * ... |
|
||||
| test.cpp:341:8:341:17 | * ... | semmle.label | * ... |
|
||||
| test.cpp:342:8:342:17 | * ... | semmle.label | * ... |
|
||||
| test.cpp:347:14:347:27 | new[] | semmle.label | new[] |
|
||||
| test.cpp:348:15:348:16 | xs | semmle.label | xs |
|
||||
| test.cpp:355:14:355:27 | new[] | semmle.label | new[] |
|
||||
| test.cpp:356:15:356:16 | xs | semmle.label | xs |
|
||||
| test.cpp:356:15:356:23 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:356:15:356:23 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:356:15:356:23 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:356:15:356:23 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:357:24:357:26 | end | semmle.label | end |
|
||||
| test.cpp:357:24:357:30 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:357:24:357:30 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:357:24:357:30 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:357:24:357:30 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:358:14:358:26 | Load: * ... | semmle.label | Load: * ... |
|
||||
| test.cpp:358:15:358:26 | end_plus_one | semmle.label | end_plus_one |
|
||||
| test.cpp:358:15:358:26 | end_plus_one | semmle.label | end_plus_one |
|
||||
| test.cpp:359:14:359:32 | Load: * ... | semmle.label | Load: * ... |
|
||||
| test.cpp:359:16:359:27 | end_plus_one | semmle.label | end_plus_one |
|
||||
| test.cpp:359:16:359:31 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:363:14:363:27 | new[] | semmle.label | new[] |
|
||||
| test.cpp:365:15:365:15 | p | semmle.label | p |
|
||||
| test.cpp:368:5:368:10 | ... += ... | semmle.label | ... += ... |
|
||||
| test.cpp:368:5:368:10 | ... += ... | semmle.label | ... += ... |
|
||||
| test.cpp:371:7:371:7 | p | semmle.label | p |
|
||||
| test.cpp:372:15:372:16 | Load: * ... | semmle.label | Load: * ... |
|
||||
| test.cpp:372:16:372:16 | p | semmle.label | p |
|
||||
| test.cpp:377:14:377:27 | new[] | semmle.label | new[] |
|
||||
| test.cpp:378:15:378:16 | xs | semmle.label | xs |
|
||||
| test.cpp:378:15:378:23 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:378:15:378:23 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:378:15:378:23 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:378:15:378:23 | ... + ... | semmle.label | ... + ... |
|
||||
| test.cpp:381:5:381:7 | end | semmle.label | end |
|
||||
| test.cpp:381:5:381:9 | ... ++ | semmle.label | ... ++ |
|
||||
| test.cpp:381:5:381:9 | ... ++ | semmle.label | ... ++ |
|
||||
| test.cpp:384:13:384:16 | Load: * ... | semmle.label | Load: * ... |
|
||||
| test.cpp:384:14:384:16 | end | semmle.label | end |
|
||||
| test.cpp:388:14:388:27 | new[] | semmle.label | new[] |
|
||||
| test.cpp:389:16:389:17 | xs | semmle.label | xs |
|
||||
| test.cpp:392:5:392:6 | xs | semmle.label | xs |
|
||||
| test.cpp:392:5:392:8 | ... ++ | semmle.label | ... ++ |
|
||||
| test.cpp:392:5:392:8 | ... ++ | semmle.label | ... ++ |
|
||||
| test.cpp:392:5:392:8 | ... ++ | semmle.label | ... ++ |
|
||||
| test.cpp:392:5:392:8 | ... ++ | semmle.label | ... ++ |
|
||||
| test.cpp:393:9:393:10 | xs | semmle.label | xs |
|
||||
| test.cpp:393:9:393:10 | xs | semmle.label | xs |
|
||||
| test.cpp:395:5:395:6 | xs | semmle.label | xs |
|
||||
| test.cpp:395:5:395:13 | Store: ... = ... | semmle.label | Store: ... = ... |
|
||||
| test.cpp:404:3:404:25 | ... = ... | semmle.label | ... = ... |
|
||||
| test.cpp:404:7:404:8 | val indirection [post update] [xs] | semmle.label | val indirection [post update] [xs] |
|
||||
| test.cpp:404:12:404:25 | new[] | semmle.label | new[] |
|
||||
| test.cpp:406:3:406:25 | ... = ... | semmle.label | ... = ... |
|
||||
| test.cpp:406:7:406:8 | val indirection [post update] [xs] | semmle.label | val indirection [post update] [xs] |
|
||||
| test.cpp:406:12:406:25 | new[] | semmle.label | new[] |
|
||||
| test.cpp:407:3:407:5 | val indirection [xs] | semmle.label | val indirection [xs] |
|
||||
| test.cpp:407:3:407:18 | access to array | semmle.label | access to array |
|
||||
| test.cpp:407:3:407:22 | Store: ... = ... | semmle.label | Store: ... = ... |
|
||||
| test.cpp:407:7:407:8 | xs | semmle.label | xs |
|
||||
| test.cpp:407:7:407:8 | xs indirection | semmle.label | xs indirection |
|
||||
| test.cpp:417:16:417:33 | new[] | semmle.label | new[] |
|
||||
| test.cpp:419:7:419:8 | xs | semmle.label | xs |
|
||||
| test.cpp:419:7:419:11 | access to array | semmle.label | access to array |
|
||||
| test.cpp:419:7:419:15 | Store: ... = ... | semmle.label | Store: ... = ... |
|
||||
| test.cpp:427:14:427:27 | new[] | semmle.label | new[] |
|
||||
| test.cpp:433:5:433:6 | xs | semmle.label | xs |
|
||||
| test.cpp:433:5:433:17 | access to array | semmle.label | access to array |
|
||||
| test.cpp:433:5:433:21 | Store: ... = ... | semmle.label | Store: ... = ... |
|
||||
subpaths
|
||||
#select
|
||||
| test.cpp:6:14:6:15 | Load: * ... | test.cpp:4:15:4:20 | call to malloc | test.cpp:6:14:6:15 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:4:15:4:20 | call to malloc | call to malloc | test.cpp:5:19:5:22 | size | size |
|
||||
| test.cpp:8:14:8:21 | Load: * ... | test.cpp:4:15:4:20 | call to malloc | test.cpp:8:14:8:21 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@ + 1. | test.cpp:4:15:4:20 | call to malloc | call to malloc | test.cpp:5:19:5:22 | size | size |
|
||||
| test.cpp:8:14:8:21 | Load: * ... | test.cpp:4:15:4:20 | call to malloc | test.cpp:8:14:8:21 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:4:15:4:20 | call to malloc | call to malloc | test.cpp:5:19:5:22 | size | size |
|
||||
| test.cpp:20:14:20:21 | Load: * ... | test.cpp:16:15:16:20 | call to malloc | test.cpp:20:14:20:21 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:16:15:16:20 | call to malloc | call to malloc | test.cpp:17:19:17:22 | size | size |
|
||||
| test.cpp:30:14:30:15 | Load: * ... | test.cpp:28:15:28:20 | call to malloc | test.cpp:30:14:30:15 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:28:15:28:20 | call to malloc | call to malloc | test.cpp:29:20:29:27 | ... + ... | ... + ... |
|
||||
| test.cpp:32:14:32:21 | Load: * ... | test.cpp:28:15:28:20 | call to malloc | test.cpp:32:14:32:21 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@ + 1. | test.cpp:28:15:28:20 | call to malloc | call to malloc | test.cpp:29:20:29:27 | ... + ... | ... + ... |
|
||||
| test.cpp:32:14:32:21 | Load: * ... | test.cpp:28:15:28:20 | call to malloc | test.cpp:32:14:32:21 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:28:15:28:20 | call to malloc | call to malloc | test.cpp:29:20:29:27 | ... + ... | ... + ... |
|
||||
| test.cpp:42:14:42:15 | Load: * ... | test.cpp:40:15:40:20 | call to malloc | test.cpp:42:14:42:15 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:40:15:40:20 | call to malloc | call to malloc | test.cpp:41:20:41:27 | ... - ... | ... - ... |
|
||||
| test.cpp:44:14:44:21 | Load: * ... | test.cpp:40:15:40:20 | call to malloc | test.cpp:44:14:44:21 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@ + 1. | test.cpp:40:15:40:20 | call to malloc | call to malloc | test.cpp:41:20:41:27 | ... - ... | ... - ... |
|
||||
| test.cpp:44:14:44:21 | Load: * ... | test.cpp:40:15:40:20 | call to malloc | test.cpp:44:14:44:21 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:40:15:40:20 | call to malloc | call to malloc | test.cpp:41:20:41:27 | ... - ... | ... - ... |
|
||||
| test.cpp:67:9:67:14 | Store: ... = ... | test.cpp:52:19:52:24 | call to malloc | test.cpp:67:9:67:14 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:52:19:52:24 | call to malloc | call to malloc | test.cpp:53:20:53:23 | size | size |
|
||||
| test.cpp:96:9:96:14 | Store: ... = ... | test.cpp:82:17:82:22 | call to malloc | test.cpp:96:9:96:14 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:82:17:82:22 | call to malloc | call to malloc | test.cpp:83:27:83:30 | size | size |
|
||||
| test.cpp:110:9:110:14 | Store: ... = ... | test.cpp:82:17:82:22 | call to malloc | test.cpp:110:9:110:14 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:82:17:82:22 | call to malloc | call to malloc | test.cpp:83:27:83:30 | size | size |
|
||||
@@ -696,6 +1179,11 @@ subpaths
|
||||
| test.cpp:264:13:264:14 | Load: * ... | test.cpp:260:13:260:24 | new[] | test.cpp:264:13:264:14 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:260:13:260:24 | new[] | new[] | test.cpp:261:19:261:21 | len | len |
|
||||
| test.cpp:274:5:274:10 | Store: ... = ... | test.cpp:270:13:270:24 | new[] | test.cpp:274:5:274:10 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:270:13:270:24 | new[] | new[] | test.cpp:271:19:271:21 | len | len |
|
||||
| test.cpp:308:5:308:29 | Store: ... = ... | test.cpp:304:15:304:26 | new[] | test.cpp:308:5:308:29 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:304:15:304:26 | new[] | new[] | test.cpp:308:8:308:10 | ... + ... | ... + ... |
|
||||
| test.cpp:333:5:333:21 | Store: ... = ... | test.cpp:325:14:325:27 | new[] | test.cpp:333:5:333:21 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:325:14:325:27 | new[] | new[] | test.cpp:326:20:326:23 | size | size |
|
||||
| test.cpp:341:5:341:21 | Store: ... = ... | test.cpp:325:14:325:27 | new[] | test.cpp:341:5:341:21 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:325:14:325:27 | new[] | new[] | test.cpp:326:20:326:23 | size | size |
|
||||
| test.cpp:350:15:350:19 | Load: * ... | test.cpp:347:14:347:27 | new[] | test.cpp:350:15:350:19 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:347:14:347:27 | new[] | new[] | test.cpp:348:20:348:23 | size | size |
|
||||
| test.cpp:358:14:358:26 | Load: * ... | test.cpp:355:14:355:27 | new[] | test.cpp:358:14:358:26 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@ + 1. | test.cpp:355:14:355:27 | new[] | new[] | test.cpp:356:20:356:23 | size | size |
|
||||
| test.cpp:359:14:359:32 | Load: * ... | test.cpp:355:14:355:27 | new[] | test.cpp:359:14:359:32 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@ + 2. | test.cpp:355:14:355:27 | new[] | new[] | test.cpp:356:20:356:23 | size | size |
|
||||
| test.cpp:372:15:372:16 | Load: * ... | test.cpp:363:14:363:27 | new[] | test.cpp:372:15:372:16 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:363:14:363:27 | new[] | new[] | test.cpp:365:19:365:22 | size | size |
|
||||
| test.cpp:384:13:384:16 | Load: * ... | test.cpp:377:14:377:27 | new[] | test.cpp:384:13:384:16 | Load: * ... | This read might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:377:14:377:27 | new[] | new[] | test.cpp:378:20:378:23 | size | size |
|
||||
| test.cpp:395:5:395:13 | Store: ... = ... | test.cpp:388:14:388:27 | new[] | test.cpp:395:5:395:13 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:388:14:388:27 | new[] | new[] | test.cpp:389:19:389:22 | size | size |
|
||||
| test.cpp:407:3:407:22 | Store: ... = ... | test.cpp:404:12:404:25 | new[] | test.cpp:407:3:407:22 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:404:12:404:25 | new[] | new[] | test.cpp:407:10:407:17 | ... - ... | ... - ... |
|
||||
| test.cpp:419:7:419:15 | Store: ... = ... | test.cpp:417:16:417:33 | new[] | test.cpp:419:7:419:15 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:417:16:417:33 | new[] | new[] | test.cpp:419:10:419:10 | i | i |
|
||||
| test.cpp:433:5:433:21 | Store: ... = ... | test.cpp:427:14:427:27 | new[] | test.cpp:433:5:433:21 | Store: ... = ... | This write might be out of bounds, as the pointer might be equal to $@ + $@. | test.cpp:427:14:427:27 | new[] | new[] | test.cpp:433:8:433:16 | ... ++ | ... ++ |
|
||||
|
||||
@@ -330,7 +330,7 @@ void test23(unsigned size, int val) {
|
||||
if(*current - xs < 1)
|
||||
return;
|
||||
|
||||
*--(*current) = 0; // GOOD [FALSE POSITIVE]
|
||||
*--(*current) = 0; // GOOD
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -338,7 +338,7 @@ void test23(unsigned size, int val) {
|
||||
if(*current - xs < 2)
|
||||
return;
|
||||
|
||||
*--(*current) = 0; // GOOD [FALSE POSITIVE]
|
||||
*--(*current) = 0; // GOOD
|
||||
*--(*current) = 0; // GOOD
|
||||
}
|
||||
}
|
||||
@@ -347,6 +347,89 @@ void test24(unsigned size) {
|
||||
char *xs = new char[size];
|
||||
char *end = xs + size;
|
||||
if (xs < end) {
|
||||
int val = *xs++; // GOOD [FALSE POSITIVE]
|
||||
int val = *xs++; // GOOD
|
||||
}
|
||||
}
|
||||
|
||||
void test25(unsigned size) {
|
||||
char *xs = new char[size];
|
||||
char *end = xs + size;
|
||||
char *end_plus_one = end + 1;
|
||||
int val1 = *end_plus_one; // BAD
|
||||
int val2 = *(end_plus_one + 1); // BAD
|
||||
}
|
||||
|
||||
void test26(unsigned size) {
|
||||
char *xs = new char[size];
|
||||
char *p = xs;
|
||||
char *end = p + size;
|
||||
|
||||
if (p + 4 <= end) {
|
||||
p += 4;
|
||||
}
|
||||
|
||||
if (p < end) {
|
||||
int val = *p; // GOOD [FALSE POSITIVE]
|
||||
}
|
||||
}
|
||||
|
||||
void test27(unsigned size, bool b) {
|
||||
char *xs = new char[size];
|
||||
char *end = xs + size;
|
||||
|
||||
if (b) {
|
||||
end++;
|
||||
}
|
||||
|
||||
int val = *end; // BAD
|
||||
}
|
||||
|
||||
void test28(unsigned size) {
|
||||
char *xs = new char[size];
|
||||
char *end = &xs[size];
|
||||
if (xs >= end)
|
||||
return;
|
||||
xs++;
|
||||
if (xs >= end)
|
||||
return;
|
||||
xs[0] = 0; // GOOD [FALSE POSITIVE]
|
||||
}
|
||||
|
||||
struct test29_struct {
|
||||
char* xs;
|
||||
};
|
||||
|
||||
void test29(unsigned size) {
|
||||
test29_struct val;
|
||||
val.xs = new char[size];
|
||||
size++;
|
||||
val.xs = new char[size];
|
||||
val.xs[size - 1] = 0; // GOOD [FALSE POSITIVE]
|
||||
}
|
||||
|
||||
void test30(int *size)
|
||||
{
|
||||
int new_size = 0, tmp_size = 0;
|
||||
|
||||
test30(&tmp_size);
|
||||
if (tmp_size + 1 > new_size) {
|
||||
new_size = tmp_size + 1;
|
||||
char *xs = new char[new_size];
|
||||
for (int i = 0; i < new_size; i++) {
|
||||
xs[i] = 0; // GOOD [FALSE POSITIVE]
|
||||
}
|
||||
}
|
||||
*size = new_size;
|
||||
}
|
||||
|
||||
void test31(unsigned size, unsigned src_pos)
|
||||
{
|
||||
char *xs = new char[size];
|
||||
if (src_pos > size) {
|
||||
src_pos = size;
|
||||
}
|
||||
unsigned dst_pos = src_pos;
|
||||
if(dst_pos < size - 3) {
|
||||
xs[dst_pos++] = 0; // GOOD [FALSE POSITIVE]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -67,6 +67,8 @@ postWithInFlow
|
||||
| ref.cpp:109:9:109:11 | val [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| ref.cpp:113:11:113:13 | val [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| ref.cpp:115:11:115:13 | val [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| self_parameter_flow.cpp:3:4:3:5 | ps [inner post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| self_parameter_flow.cpp:8:9:8:9 | s [inner post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| test.cpp:91:3:91:9 | source1 [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| test.cpp:115:3:115:6 | * ... [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| test.cpp:115:4:115:6 | out [inner post update] | PostUpdateNode should not be the target of local flow. |
|
||||
@@ -128,6 +130,10 @@ postWithInFlow
|
||||
| test.cpp:690:3:690:3 | s [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| test.cpp:694:4:694:6 | buf [inner post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| test.cpp:704:23:704:25 | buf [inner post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| test.cpp:715:25:715:25 | c [inner post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| test.cpp:728:3:728:4 | * ... [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| test.cpp:728:4:728:4 | p [inner post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| test.cpp:734:41:734:41 | x [inner post update] | PostUpdateNode should not be the target of local flow. |
|
||||
viableImplInCallContextTooLarge
|
||||
uniqueParameterNodeAtPosition
|
||||
uniqueParameterNodePosition
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
void incr(unsigned char **ps) // $ ast-def=ps ir-def=*ps ir-def=**ps
|
||||
{
|
||||
*ps += 1;
|
||||
}
|
||||
|
||||
void callincr(unsigned char *s) // $ ast-def=s
|
||||
{
|
||||
incr(&s);
|
||||
}
|
||||
|
||||
void test(unsigned char *s) // $ ast-def=s
|
||||
{
|
||||
callincr(s); // $ flow
|
||||
}
|
||||
@@ -702,4 +702,35 @@ void call_increment_buf(int** buf) { // $ ast-def=buf
|
||||
void test_conflation_regression(int* source) { // $ ast-def=source
|
||||
int* buf = source;
|
||||
call_increment_buf(&buf);
|
||||
}
|
||||
}
|
||||
|
||||
void write_to_star_star_p(unsigned char **p) // $ ast-def=p ir-def=**p ir-def=*p
|
||||
{
|
||||
**p = 0;
|
||||
}
|
||||
|
||||
void write_to_star_buf(unsigned char *buf) // $ ast-def=buf
|
||||
{
|
||||
unsigned char *c = buf;
|
||||
write_to_star_star_p(&c);
|
||||
}
|
||||
|
||||
void test_write_to_star_buf(unsigned char *source) // $ ast-def=source
|
||||
{
|
||||
write_to_star_buf(source);
|
||||
sink(*source); // clean
|
||||
}
|
||||
|
||||
void does_not_write_source_to_dereference(int *p) // $ ast-def=p ir-def=*p
|
||||
{
|
||||
int x = source();
|
||||
p = &x;
|
||||
*p = 42;
|
||||
}
|
||||
|
||||
void test_does_not_write_source_to_dereference()
|
||||
{
|
||||
int x;
|
||||
does_not_write_source_to_dereference(&x);
|
||||
sink(x); // $ ast,ir=733:7 SPURIOUS: ast,ir=726:11
|
||||
}
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
failures
|
||||
testFailures
|
||||
@@ -0,0 +1,34 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.dataflow.new.DataFlow
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
|
||||
module TestConfig implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) {
|
||||
source.getLocation().getFile().getBaseName() = "self_parameter_flow.cpp" and
|
||||
source.asIndirectArgument() =
|
||||
any(Call call | call.getTarget().hasName("callincr")).getAnArgument()
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink) {
|
||||
sink.asDefiningArgument() =
|
||||
any(Call call | call.getTarget().hasName("callincr")).getAnArgument()
|
||||
}
|
||||
}
|
||||
|
||||
import DataFlow::Global<TestConfig>
|
||||
|
||||
module TestSelfParameterFlow implements TestSig {
|
||||
string getARelevantTag() { result = "flow" }
|
||||
|
||||
predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(DataFlow::Node sink |
|
||||
flowTo(sink) and
|
||||
location = sink.getLocation() and
|
||||
element = sink.toString() and
|
||||
tag = "flow" and
|
||||
value = ""
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
import MakeTest<TestSelfParameterFlow>
|
||||
@@ -42,3 +42,5 @@
|
||||
| test.cpp:551:9:551:9 | y | test.cpp:552:28:552:28 | y |
|
||||
| test.cpp:595:8:595:9 | xs | test.cpp:596:3:596:4 | xs |
|
||||
| test.cpp:595:8:595:9 | xs | test.cpp:597:9:597:10 | xs |
|
||||
| test.cpp:733:7:733:7 | x | test.cpp:734:41:734:41 | x |
|
||||
| test.cpp:733:7:733:7 | x | test.cpp:735:8:735:8 | x |
|
||||
|
||||
@@ -34,9 +34,6 @@ class AstNode extends Node, TAstNode {
|
||||
override Location getLocation() { result = n.getLocation() }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for AstNode */
|
||||
deprecated class ASTNode = AstNode;
|
||||
|
||||
class IRNode extends Node, TIRNode {
|
||||
IR::DataFlow::Node n;
|
||||
|
||||
|
||||
@@ -6584,6 +6584,27 @@
|
||||
| taint.cpp:691:18:691:18 | s [post update] | taint.cpp:695:7:695:7 | s | |
|
||||
| taint.cpp:691:20:691:20 | ref arg x | taint.cpp:694:9:694:9 | x | |
|
||||
| taint.cpp:694:7:694:7 | s [post update] | taint.cpp:695:7:695:7 | s | |
|
||||
| taint.cpp:700:13:700:18 | call to source | taint.cpp:702:11:702:11 | s | |
|
||||
| taint.cpp:701:9:701:9 | p | taint.cpp:702:4:702:4 | p | |
|
||||
| taint.cpp:702:4:702:4 | p | taint.cpp:702:4:702:6 | ... ++ | |
|
||||
| taint.cpp:702:4:702:6 | ... ++ | taint.cpp:702:3:702:6 | * ... | TAINT |
|
||||
| taint.cpp:702:4:702:6 | ... ++ | taint.cpp:703:8:703:8 | p | TAINT |
|
||||
| taint.cpp:702:10:702:11 | * ... | taint.cpp:702:3:702:11 | ... = ... | |
|
||||
| taint.cpp:702:11:702:11 | s | taint.cpp:702:10:702:11 | * ... | TAINT |
|
||||
| taint.cpp:709:25:709:25 | d | taint.cpp:709:25:709:25 | d | |
|
||||
| taint.cpp:709:25:709:25 | d | taint.cpp:711:10:711:10 | d | |
|
||||
| taint.cpp:709:25:709:25 | d | taint.cpp:712:7:712:7 | d | |
|
||||
| taint.cpp:709:34:709:34 | s | taint.cpp:709:34:709:34 | s | |
|
||||
| taint.cpp:709:34:709:34 | s | taint.cpp:710:18:710:18 | s | |
|
||||
| taint.cpp:709:34:709:34 | s | taint.cpp:711:13:711:13 | s | |
|
||||
| taint.cpp:710:18:710:18 | ref arg s | taint.cpp:709:34:709:34 | s | |
|
||||
| taint.cpp:710:18:710:18 | ref arg s | taint.cpp:711:13:711:13 | s | |
|
||||
| taint.cpp:711:10:711:10 | d | taint.cpp:711:2:711:8 | call to strncpy | |
|
||||
| taint.cpp:711:10:711:10 | ref arg d | taint.cpp:709:25:709:25 | d | |
|
||||
| taint.cpp:711:10:711:10 | ref arg d | taint.cpp:712:7:712:7 | d | |
|
||||
| taint.cpp:711:13:711:13 | s | taint.cpp:711:2:711:8 | call to strncpy | TAINT |
|
||||
| taint.cpp:711:13:711:13 | s | taint.cpp:711:10:711:10 | ref arg d | TAINT |
|
||||
| taint.cpp:712:7:712:7 | ref arg d | taint.cpp:709:25:709:25 | d | |
|
||||
| vector.cpp:16:43:16:49 | source1 | vector.cpp:17:26:17:32 | source1 | |
|
||||
| vector.cpp:16:43:16:49 | source1 | vector.cpp:31:38:31:44 | source1 | |
|
||||
| vector.cpp:17:21:17:33 | call to vector | vector.cpp:19:14:19:14 | v | |
|
||||
|
||||
@@ -693,4 +693,21 @@ void test_argument_source_field_to_obj() {
|
||||
sink(s); // $ SPURIOUS: ast,ir
|
||||
sink(s.x); // $ ast,ir
|
||||
sink(s.y); // clean
|
||||
}
|
||||
|
||||
namespace strings {
|
||||
void test_write_to_read_then_incr_then_deref() {
|
||||
char* s = source();
|
||||
char* p;
|
||||
*p++ = *s;
|
||||
sink(p); // $ ast ir
|
||||
}
|
||||
}
|
||||
|
||||
char * strncpy (char *, const char *, unsigned long);
|
||||
|
||||
void test_strncpy(char* d, char* s) {
|
||||
argument_source(s);
|
||||
strncpy(d, s, 16);
|
||||
sink(d); // $ ast ir
|
||||
}
|
||||
@@ -40,14 +40,7 @@ bindingset[delta]
|
||||
private string getBoundString(SemBound b, float delta) {
|
||||
b instanceof SemZeroBound and result = delta.toString()
|
||||
or
|
||||
result =
|
||||
strictconcat(b.(SemSsaBound)
|
||||
.getAVariable()
|
||||
.(SemanticExprConfig::SsaVariable)
|
||||
.asInstruction()
|
||||
.getAst()
|
||||
.toString(), ":"
|
||||
) + getOffsetString(delta)
|
||||
result = strictconcat(b.(SemSsaBound).getAVariable().toString(), " | ") + getOffsetString(delta)
|
||||
}
|
||||
|
||||
private string getARangeString(SemExpr e) {
|
||||
|
||||
@@ -8,7 +8,7 @@ int test1(struct List* p) {
|
||||
int count = 0;
|
||||
for (; p; p = p->next) {
|
||||
count = count+1;
|
||||
range(count); // $ range===count:p+1
|
||||
range(count); // $ range="==Phi: p | Store: count+1"
|
||||
}
|
||||
range(count);
|
||||
return count;
|
||||
@@ -18,7 +18,7 @@ int test2(struct List* p) {
|
||||
int count = 0;
|
||||
for (; p; p = p->next) {
|
||||
count = (count+1) % 10;
|
||||
range(count); // $ range=<=9 range=>=-9 range=<=count:p+1
|
||||
range(count); // $ range=<=9 range=>=-9 range="<=Phi: p | Store: count+1"
|
||||
}
|
||||
range(count); // $ range=>=-9 range=<=9
|
||||
return count;
|
||||
@@ -29,7 +29,7 @@ int test3(struct List* p) {
|
||||
for (; p; p = p->next) {
|
||||
range(count++); // $ range=>=-9 range=<=9
|
||||
count = count % 10;
|
||||
range(count); // $ range=<=9 range=>=-9 range="<=... +++0" range=<=count:p+1
|
||||
range(count); // $ range=<=9 range=>=-9 range="<=Store: ... +++0" range="<=Phi: p | Store: count+1"
|
||||
}
|
||||
range(count); // $ range=>=-9 range=<=9
|
||||
return count;
|
||||
@@ -42,11 +42,11 @@ int test4() {
|
||||
range(i); // $ range=<=1 range=>=0
|
||||
range(total);
|
||||
total += i;
|
||||
range(total); // $ range=<=i+1 range=<=i+1 MISSING: range=>=0 range=>=i+0
|
||||
range(total); // $ range="<=Phi: i+1" MISSING: range=>=0 range=>=i+0
|
||||
}
|
||||
range(total); // $ MISSING: range=>=0
|
||||
range(i); // $ range===2
|
||||
range(total + i); // $ range=<=i+2 MISSING: range===i+2 range=>=2 range=>=i+0
|
||||
range(total + i); // $ range="<=Phi: i+2" MISSING: range===i+2 range=>=2 range=>=i+0
|
||||
return total + i;
|
||||
}
|
||||
|
||||
@@ -57,11 +57,11 @@ int test5() {
|
||||
range(i); // $ range=<=1 range=>=0
|
||||
range(total); // $ MISSING: range=>=0
|
||||
total += i;
|
||||
range(total); // $ range=<=i+1 MISSING: range=>=0 range=>=i+0
|
||||
range(total); // $ range="<=Phi: i+1" MISSING: range=>=0 range=>=i+0
|
||||
}
|
||||
range(total); // $ MISSING: range=>=0
|
||||
range(i); // $ range===2
|
||||
range(total + i); // $ range=<=i+2 MISSING: range===i+2 range=>=2 range=>=i+0
|
||||
range(total + i); // $ range="<=Phi: i+2" MISSING: range===i+2 range=>=2 range=>=i+0
|
||||
return total + i;
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ int test6() {
|
||||
range(i); // $ range=<=1 range=>=0
|
||||
range(total); // $ MISSING: range=>=0
|
||||
total += i;
|
||||
range(total); // $ range=<=i+1 MISSING: range=>=0 range=>=i+0
|
||||
range(total); // $ range="<=Phi: i+1" MISSING: range=>=0 range=>=i+0
|
||||
}
|
||||
return total + i;
|
||||
}
|
||||
@@ -93,12 +93,12 @@ int test8(int x, int y) {
|
||||
if (-1000 < y && y < 10) {
|
||||
range(y); // $ range=<=9 range=>=-999
|
||||
if (x < y-2) {
|
||||
range(x); // $ range=<=6 range=<=y-3
|
||||
range(y); // $ range=<=9 range=>=-999 range=>=x+3
|
||||
range(x); // $ range=<=6 range="<=InitializeParameter: y | Store: y-3"
|
||||
range(y); // $ range=<=9 range=>=-999 range=">=InitializeParameter: x | Store: x+3"
|
||||
return x;
|
||||
}
|
||||
range(x); // $ range=>=-1001 range=>=y-2
|
||||
range(y); // $ range=<=9 range=<=x+2 range=>=-999
|
||||
range(x); // $ range=>=-1001 range=">=InitializeParameter: y | Store: y-2"
|
||||
range(y); // $ range=<=9 range="<=InitializeParameter: x | Store: x+2" range=>=-999
|
||||
}
|
||||
range(x);
|
||||
range(y);
|
||||
@@ -127,12 +127,12 @@ int test10(int x, int y) {
|
||||
if (y > 7) {
|
||||
range(y); // $ range=>=8
|
||||
if (x < y) {
|
||||
range(x); // $ range=<=y-1
|
||||
range(y); // $ range=>=8 range=>=x+1
|
||||
range(x); // $ range="<=InitializeParameter: y-1"
|
||||
range(y); // $ range=>=8 range=">=InitializeParameter: x | Store: x+1"
|
||||
return 0;
|
||||
}
|
||||
range(x); // $ range=>=8 range=>=y+0
|
||||
range(y); // $ range=<=x+0 range=>=8
|
||||
range(x); // $ range=>=8 range=">=InitializeParameter: y+0"
|
||||
range(y); // $ range="<=InitializeParameter: x | Store: x+0" range=>=8
|
||||
return x;
|
||||
}
|
||||
range(y); // $ range=<=7
|
||||
@@ -145,7 +145,7 @@ int test11(char *p) {
|
||||
range(*p);
|
||||
if (c != '\0') {
|
||||
*p++ = '\0';
|
||||
range(p); // $ range===p+1
|
||||
range(p); // $ range="==InitializeParameter: p+1"
|
||||
range(*p);
|
||||
}
|
||||
if (c == ':') {
|
||||
@@ -155,7 +155,7 @@ int test11(char *p) {
|
||||
if (c != '\0') {
|
||||
range(c);
|
||||
*p++ = '\0';
|
||||
range(p); // $ range=<=p+2 range===c+1 range=>=p+1
|
||||
range(p); // $ range="<=InitializeParameter: p+2" range="==Phi: c+1" range=">=InitializeParameter: p+1"
|
||||
}
|
||||
if (c != ',') {
|
||||
return 1;
|
||||
@@ -193,7 +193,7 @@ int test13(char c, int i) {
|
||||
unsigned int y = x-1; // $ overflow=-
|
||||
range(y); // $ range===-1 overflow=-
|
||||
int z = i+1; // $ overflow=+
|
||||
range(z); // $ range===i+1
|
||||
range(z); // $ range="==InitializeParameter: i+1"
|
||||
range(c + i + uc + x + y + z); // $ overflow=+- overflow=+ overflow=- MISSING: range=>=1
|
||||
range((double)(c + i + uc + x + y + z)); // $ overflow=+ overflow=+- overflow=- MISSING: range=>=1
|
||||
return (double)(c + i + uc + x + y + z); // $ overflow=+- overflow=+ overflow=-
|
||||
@@ -245,7 +245,7 @@ int test_unary(int a) {
|
||||
range(c); // $ range=<=0 range=>=-11
|
||||
range(b+c); // $ range=<=11 range=>=-11 MISSING:range=">=- ...+0"
|
||||
total += b+c;
|
||||
range(total); // $ range=<=0+11 range=<=19 range=>=0-11 range=>=-19
|
||||
range(total); // $ range="<=Phi: 0+11" range=<=19 range=">=Phi: 0-11" range=>=-19
|
||||
}
|
||||
if (-7 <= a && a <= 11) {
|
||||
range(a); // $ range=<=11 range=>=-7
|
||||
@@ -255,7 +255,7 @@ int test_unary(int a) {
|
||||
range(c); // $ range=<=7 range=>=-11
|
||||
range(b+c); // $ range=<=18 range=>=-18
|
||||
total += b+c;
|
||||
range(total); // $ range="<=- ...+18" range=">=- ...-18" range=<=0+29 range=<=37 range=>=0-29 range=>=-37
|
||||
range(total); // $ range="<=Phi: - ...+18" range=">=Phi: - ...-18" range="<=Phi: 0+29" range=<=37 range=">=Phi: 0-29" range=>=-37
|
||||
}
|
||||
if (-7 <= a && a <= 1) {
|
||||
range(a); // $ range=<=1 range=>=-7
|
||||
@@ -265,7 +265,7 @@ int test_unary(int a) {
|
||||
range(c); // $ range=<=7 range=>=-1
|
||||
range(b+c); // $ range=<=8 range=>=-8
|
||||
total += b+c;
|
||||
range(total); // $ range="<=- ...+8" range="<=- ...+26" range=">=- ...-8" range=">=- ...-26" range=<=0+37 range=<=45 range=>=0-37 range=>=-45
|
||||
range(total); // $ range="<=Phi: - ...+8" range="<=Phi: - ...+26" range=">=Phi: - ...-8" range=">=Phi: - ...-26" range="<=Phi: 0+37" range=<=45 range=">=Phi: 0-37" range=>=-45
|
||||
}
|
||||
if (-7 <= a && a <= 0) {
|
||||
range(a); // $ range=<=0 range=>=-7
|
||||
@@ -275,7 +275,7 @@ int test_unary(int a) {
|
||||
range(c); // $ range=<=7 range=>=0
|
||||
range(b+c); // $ range=>=-7 range=<=7 MISSING:range="<=- ...+0"
|
||||
total += b+c;
|
||||
range(total); // $ range="<=- ...+7" range="<=- ...+15" range="<=- ...+33" range=">=- ...-7" range=">=- ...-15" range=">=- ...-33" range=<=0+44 range=<=52 range=>=0-44 range=>=-52
|
||||
range(total); // $ range="<=Phi: - ...+7" range="<=Phi: - ...+15" range="<=Phi: - ...+33" range=">=Phi: - ...-7" range=">=Phi: - ...-15" range=">=Phi: - ...-33" range="<=Phi: 0+44" range=<=52 Unexpected result: range=">=Phi: 0-44" range=>=-52
|
||||
}
|
||||
if (-7 <= a && a <= -2) {
|
||||
range(a); // $ range=<=-2 range=>=-7
|
||||
@@ -285,9 +285,9 @@ int test_unary(int a) {
|
||||
range(c); // $ range=<=7 range=>=2
|
||||
range(b+c); // $ range=<=5 range=>=-5
|
||||
total += b+c;
|
||||
range(total); // $ range="<=- ...+5" range="<=- ...+12" range="<=- ...+20" range="<=- ...+38" range=">=- ...-5" range=">=- ...-12" range=">=- ...-20" range=">=- ...-38" range=<=0+49 range=<=57 range=>=0-49 range=>=-57
|
||||
range(total); // $ range="<=Phi: - ...+5" range="<=Phi: - ...+12" range="<=Phi: - ...+20" range="<=Phi: - ...+38" range=">=Phi: - ...-5" range=">=Phi: - ...-12" range=">=Phi: - ...-20" range=">=Phi: - ...-38" range="<=Phi: 0+49" range=<=57 range=">=Phi: 0-49" range=>=-57
|
||||
}
|
||||
range(total); // $ range="<=- ...+5" range="<=- ...+12" range="<=- ...+20" range="<=- ...+38" range=">=- ...-5" range=">=- ...-12" range=">=- ...-20" range=">=- ...-38" range=<=0+49 range=<=57 range=>=0-49 range=>=-57
|
||||
range(total); // $ range="<=Phi: - ...+5" range="<=Phi: - ...+12" range="<=Phi: - ...+20" range="<=Phi: - ...+38" range=">=Phi: - ...-5" range=">=Phi: - ...-12" range=">=Phi: - ...-20" range=">=Phi: - ...-38" range="<=Phi: 0+49" range=<=57 range=">=Phi: 0-49" range=>=-57
|
||||
return total;
|
||||
}
|
||||
|
||||
@@ -310,7 +310,7 @@ int test_mult01(int a, int b) {
|
||||
int r = a*b; // 0 .. 253
|
||||
range(r); // $ range=<=253 range=>=0
|
||||
total += r;
|
||||
range(total); // $ range=<=3+253 range=<=506 range=>=0 range=>=3+0
|
||||
range(total); // $ range="<=Phi: 3+253" range=<=506 range=>=0 range=">=Phi: 3+0"
|
||||
}
|
||||
if (3 <= a && a <= 11 && -13 <= b && b <= 23) {
|
||||
range(a); // $ range=<=11 range=>=3
|
||||
@@ -326,7 +326,7 @@ int test_mult01(int a, int b) {
|
||||
int r = a*b; // -143 .. 0
|
||||
range(r); // $ range=<=0 range=>=-143
|
||||
total += r;
|
||||
range(total); // $ range=>=3-143
|
||||
range(total); // $ range=">=Phi: 3-143"
|
||||
}
|
||||
if (3 <= a && a <= 11 && -13 <= b && b <= -7) {
|
||||
range(a); // $ range=<=11 range=>=3
|
||||
@@ -334,9 +334,9 @@ int test_mult01(int a, int b) {
|
||||
int r = a*b; // -143 .. -21
|
||||
range(r); // $ range=<=-21 range=>=-143
|
||||
total += r;
|
||||
range(total); // $ range=>=3-143 range=>=3-286
|
||||
range(total); // $ range=">=Phi: 3-143" range=">=Phi: 3-286"
|
||||
}
|
||||
range(total); // $ range=>=3-143 range=>=3-286
|
||||
range(total); // $ range=">=Phi: 3-143" range=">=Phi: 3-286"
|
||||
return total;
|
||||
}
|
||||
|
||||
@@ -358,7 +358,7 @@ int test_mult02(int a, int b) {
|
||||
int r = a*b; // 0 .. 253
|
||||
range(r); // $ range=<=253 range=>=0
|
||||
total += r;
|
||||
range(total); // $ range=>=0 range=>=0+0 range=<=0+253 range=<=506
|
||||
range(total); // $ range=>=0 range=">=Phi: 0+0" range="<=Phi: 0+253" range=<=506
|
||||
}
|
||||
if (0 <= a && a <= 11 && -13 <= b && b <= 23) {
|
||||
range(a); // $ range=<=11 range=>=0
|
||||
@@ -374,7 +374,7 @@ int test_mult02(int a, int b) {
|
||||
int r = a*b; // -143 .. 0
|
||||
range(r); // $ range=<=0 range=>=-143
|
||||
total += r;
|
||||
range(total); // $ range=>=0-143
|
||||
range(total); // $ range=">=Phi: 0-143"
|
||||
}
|
||||
if (0 <= a && a <= 11 && -13 <= b && b <= -7) {
|
||||
range(a); // $ range=<=11 range=>=0
|
||||
@@ -382,9 +382,9 @@ int test_mult02(int a, int b) {
|
||||
int r = a*b; // -143 .. 0
|
||||
range(r); // $ range=<=0 range=>=-143
|
||||
total += r;
|
||||
range(total); // $ range=>=0-143 range=>=0-286
|
||||
range(total); // $ range=">=Phi: 0-143" range=">=Phi: 0-286"
|
||||
}
|
||||
range(total); // $range=>=0-143 range=>=0-286
|
||||
range(total); // $range=">=Phi: 0-143" range=">=Phi: 0-286"
|
||||
return total;
|
||||
}
|
||||
|
||||
@@ -453,7 +453,7 @@ int test_mult04(int a, int b) {
|
||||
int r = a*b; // -391 .. 0
|
||||
range(r); // $ range=<=0 range=>=-391
|
||||
total += r;
|
||||
range(total); // $ range="<=- ...+0" range=<=0 range=">=- ...-391" range=>=-782
|
||||
range(total); // $ range="<=Phi: - ...+0" range=<=0 range=">=Phi: - ...-391" range=>=-782
|
||||
}
|
||||
if (-17 <= a && a <= 0 && -13 <= b && b <= 23) {
|
||||
range(a); // $ range=<=0 range=>=-17
|
||||
@@ -469,7 +469,7 @@ int test_mult04(int a, int b) {
|
||||
int r = a*b; // 0 .. 221
|
||||
range(r); // $ range=<=221 range=>=0
|
||||
total += r;
|
||||
range(total); // $ range="<=- ...+221"
|
||||
range(total); // $ range="<=Phi: - ...+221"
|
||||
}
|
||||
if (-17 <= a && a <= 0 && -13 <= b && b <= -7) {
|
||||
range(a); // $ range=<=0 range=>=-17
|
||||
@@ -477,9 +477,9 @@ int test_mult04(int a, int b) {
|
||||
int r = a*b; // 0 .. 221
|
||||
range(r); // $ range=<=221 range=>=0
|
||||
total += r;
|
||||
range(total); // $ range="<=- ...+221" range="<=- ...+442"
|
||||
range(total); // $ range="<=Phi: - ...+221" range="<=Phi: - ...+442"
|
||||
}
|
||||
range(total); // $ range="<=- ...+221" range="<=- ...+442"
|
||||
range(total); // $ range="<=Phi: - ...+221" range="<=Phi: - ...+442"
|
||||
return total;
|
||||
}
|
||||
|
||||
@@ -501,7 +501,7 @@ int test_mult05(int a, int b) {
|
||||
int r = a*b; // -391 .. 0
|
||||
range(r); // $ range=<=0 range=>=-391
|
||||
total += r;
|
||||
range(total); // $ range="<=- ...+0" range=<=0 range=">=- ...-391" range=>=-782
|
||||
range(total); // $ range="<=Phi: - ...+0" range=<=0 range=">=Phi: - ...-391" range=>=-782
|
||||
}
|
||||
if (-17 <= a && a <= -2 && -13 <= b && b <= 23) {
|
||||
range(a); // $ range=<=-2 range=>=-17
|
||||
@@ -517,7 +517,7 @@ int test_mult05(int a, int b) {
|
||||
int r = a*b; // 0 .. 221
|
||||
range(r); // $ range=<=221 range=>=0
|
||||
total += r;
|
||||
range(total); // $ range="<=- ...+221"
|
||||
range(total); // $ range="<=Phi: - ...+221"
|
||||
}
|
||||
if (-17 <= a && a <= -2 && -13 <= b && b <= -7) {
|
||||
range(a); // $ range=<=-2 range=>=-17
|
||||
@@ -525,9 +525,9 @@ int test_mult05(int a, int b) {
|
||||
int r = a*b; // 14 .. 221
|
||||
range(r); // $ range=<=221 range=>=14
|
||||
total += r;
|
||||
range(total); // $ range="<=- ...+221" range="<=- ...+442"
|
||||
range(total); // $ range="<=Phi: - ...+221" range="<=Phi: - ...+442"
|
||||
}
|
||||
range(total); // $ range="<=- ...+221" range="<=- ...+442"
|
||||
range(total); // $ range="<=Phi: - ...+221" range="<=Phi: - ...+442"
|
||||
return total;
|
||||
}
|
||||
|
||||
@@ -541,7 +541,7 @@ int test16(int x) {
|
||||
while (i < 3) {
|
||||
range(i); // $ range=<=2 range=>=0
|
||||
i++;
|
||||
range(i); // $ range=<=3 range=>=1 range="==... = ...:i+1" SPURIOUS:range="==... = ...:i+1"
|
||||
range(i); // $ range=<=3 range=>=1 range="==Phi: i | Store: ... = ...+1"
|
||||
}
|
||||
range(d);
|
||||
d = i;
|
||||
@@ -640,14 +640,14 @@ unsigned int test_comma01(unsigned int x) {
|
||||
unsigned int y1;
|
||||
unsigned int y2;
|
||||
y1 = (++y, y);
|
||||
range(y1); // $ range=<=101 range="==... ? ... : ...+1"
|
||||
range(y1); // $ range=<=101 range="==Phi: ... ? ... : ... | Store: ... ? ... : ...+1"
|
||||
y2 = (y++,
|
||||
range(y), // $ range=<=102 range="==++ ...:... = ...+1" range="==... ? ... : ...+2"
|
||||
range(y), // $ range=<=102 range="==Store: ++ ... | Store: ... = ...+1" range="==Phi: ... ? ... : ... | Store: ... ? ... : ...+2"
|
||||
y += 3,
|
||||
range(y), // $ range=<=105 range="==++ ...:... = ...+4" range="==... +++3" range="==... ? ... : ...+5"
|
||||
range(y), // $ range=<=105 range="==Store: ++ ... | Store: ... = ...+4" range="==Store: ... +++3" range="==Phi: ... ? ... : ... | Store: ... ? ... : ...+5"
|
||||
y);
|
||||
range(y2); // $ range=<=105 range="==++ ...:... = ...+4" range="==... +++3" range="==... ? ... : ...+5"
|
||||
range(y1 + y2); // $ range=<=206 range="<=... ? ... : ...+106" MISSING: range=">=++ ...:... = ...+5" range=">=... +++4" range=">=... += ...:... = ...+1" range=">=... ? ... : ...+6"
|
||||
range(y2); // $ range=<=105 range="==Store: ++ ... | Store: ... = ...+4" range="==Store: ... +++3" Unexpected result: range="==Phi: ... ? ... : ... | Store: ... ? ... : ...+5"
|
||||
range(y1 + y2); // $ range=<=206 range="<=Phi: ... ? ... : ... | Store: ... ? ... : ...+106" MISSING: range=">=++ ...:... = ...+5" range=">=... +++4" range=">=... += ...:... = ...+1" range=">=... ? ... : ...+6"
|
||||
return y1 + y2;
|
||||
}
|
||||
|
||||
@@ -672,7 +672,7 @@ void test17() {
|
||||
range(i); // $ range===50
|
||||
|
||||
i = 20 + (j -= 10);
|
||||
range(i); // $ range="==... += ...:... = ...+10" range===60
|
||||
range(i); // $ range="==Store: ... += ... | Store: ... = ...+10" range===60
|
||||
}
|
||||
|
||||
// Tests for unsigned multiplication.
|
||||
@@ -693,7 +693,7 @@ int test_unsigned_mult01(unsigned int a, unsigned b) {
|
||||
int r = a*b; // 0 .. 253
|
||||
range(r);// $ range=>=0 range=<=253
|
||||
total += r;
|
||||
range(total); // $ range=">=(unsigned int)...+0" range=>=0 range=<=506 range="<=(unsigned int)...+253"
|
||||
range(total); // $ range=">=Phi: (unsigned int)...+0" range=>=0 range=<=506 range="<=Phi: (unsigned int)...+253"
|
||||
}
|
||||
if (3 <= a && a <= 11 && 13 <= b && b <= 23) {
|
||||
range(a); // $ range=<=11 range=>=3
|
||||
@@ -701,9 +701,9 @@ int test_unsigned_mult01(unsigned int a, unsigned b) {
|
||||
int r = a*b; // 39 .. 253
|
||||
range(r); // $ range=>=39 range=<=253
|
||||
total += r;
|
||||
range(total); // $ range=>=39 range=<=759 range="<=(unsigned int)...+253" range="<=(unsigned int)...+506" range=">=(unsigned int)...+39"
|
||||
range(total); // $ range=>=39 range=<=759 range="<=Phi: (unsigned int)...+253" range="<=Phi: (unsigned int)...+506" range=">=Phi: (unsigned int)...+39"
|
||||
}
|
||||
range(total); // $ range=>=0 range=<=759 range=">=(unsigned int)...+0" range="<=(unsigned int)...+506" range="<=(unsigned int)...+253"
|
||||
range(total); // $ range=>=0 range=<=759 range=">=Phi: (unsigned int)...+0" range="<=Phi: (unsigned int)...+506" range="<=Phi: (unsigned int)...+253"
|
||||
return total;
|
||||
}
|
||||
|
||||
@@ -722,16 +722,16 @@ int test_unsigned_mult02(unsigned b) {
|
||||
int r = 11*b; // 0 .. 253
|
||||
range(r); // $ range=>=0 range=<=253
|
||||
total += r;
|
||||
range(total); // $ range=">=(unsigned int)...+0" range=>=0 range="<=(unsigned int)...+253" range=<=506
|
||||
range(total); // $ range=">=Phi: (unsigned int)...+0" range=>=0 range="<=Phi: (unsigned int)...+253" range=<=506
|
||||
}
|
||||
if (13 <= b && b <= 23) {
|
||||
range(b); // $ range=<=23 range=>=13
|
||||
int r = 11*b; // 143 .. 253
|
||||
range(r); // $ range=>=143 range=<=253
|
||||
total += r;
|
||||
range(total); // $ range="<=(unsigned int)...+253" range="<=(unsigned int)...+506" range=">=(unsigned int)...+143" range=>=143 range=<=759
|
||||
range(total); // $ range="<=Phi: (unsigned int)...+253" range="<=Phi: (unsigned int)...+506" range=">=Phi: (unsigned int)...+143" range=>=143 range=<=759
|
||||
}
|
||||
range(total); // $ range=>=0 range=<=759 range=">=(unsigned int)...+0" range="<=(unsigned int)...+506" range="<=(unsigned int)...+253"
|
||||
range(total); // $ range=>=0 range=<=759 range=">=Phi: (unsigned int)...+0" range="<=Phi: (unsigned int)...+506" range="<=Phi: (unsigned int)...+253"
|
||||
return total;
|
||||
}
|
||||
|
||||
@@ -851,7 +851,7 @@ int notequal_type_endpoint(unsigned n) {
|
||||
n--; // 1 ..
|
||||
}
|
||||
|
||||
range(n); // $ range=<=n+0 // 0 .. 0
|
||||
range(n); // $ range="<=InitializeParameter: n+0" // 0 .. 0
|
||||
}
|
||||
|
||||
void notequal_refinement(short n) {
|
||||
@@ -946,7 +946,7 @@ void widen_recursive_expr() {
|
||||
for (s = 0; s < 10; s++) {
|
||||
range(s); // $ range=<=9 range=>=0
|
||||
int result = s + s;
|
||||
range(result); // $ range=<=18 range=<=s+9 range=>=0 range=>=s+0
|
||||
range(result); // $ range=<=18 Unexpected result: range="<=Phi: s+9" range=>=0 Unexpected result: range=">=Phi: s+0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -974,7 +974,7 @@ void test_mod_neg(int s) {
|
||||
|
||||
void test_mod_ternary(int s, bool b) {
|
||||
int s2 = s % (b ? 5 : 500);
|
||||
range(s2); // $ range=>=-499 range=<=499 range="<=... ? ... : ...-1"
|
||||
range(s2); // $ range=>=-499 range=<=499 range="<=Phi: ... ? ... : ...-1"
|
||||
}
|
||||
|
||||
void test_mod_ternary2(int s, bool b1, bool b2) {
|
||||
|
||||
@@ -16,8 +16,8 @@
|
||||
int sum = x + y; // $ overflow=+-
|
||||
} else {
|
||||
if (y > 300) {
|
||||
range(x); // $ range=>=302 range=<=400 range=<=y+1 MISSING: range===y+1
|
||||
range(y); // $ range=>=301 range=<=399 range===x-1
|
||||
range(x); // $ range=>=302 range=<=400 range="<=InitializeParameter: y+1" MISSING: range===y+1
|
||||
range(y); // $ range=>=301 range=<=399 range="==InitializeParameter: x | Store: x-1"
|
||||
int sum = x + y;
|
||||
}
|
||||
}
|
||||
@@ -39,9 +39,9 @@
|
||||
}
|
||||
|
||||
if (y == x - 1 && y > 300 && y + 2 == z && z == 350) { // $ overflow=+ overflow=-
|
||||
range(x); // $ range===349 range===y+1 range===z-1
|
||||
range(y); // $ range===348 range=>=x-1 range===z-2 MISSING: range===x-1
|
||||
range(z); // $ range===350 range=<=y+2 MISSING: range===x+1 range===y+2
|
||||
range(x); // $ range===349 range="==InitializeParameter: y+1" range="==InitializeParameter: z-1"
|
||||
range(y); // $ range===348 range=">=InitializeParameter: x | Store: x-1" range="==InitializeParameter: z-2" MISSING: range===x-1
|
||||
range(z); // $ range===350 range="<=InitializeParameter: y+2" MISSING: range===x+1 range===y+2
|
||||
return x + y + z;
|
||||
}
|
||||
}
|
||||
@@ -56,7 +56,7 @@
|
||||
while (f3_get(n)) n+=2;
|
||||
|
||||
for (int i = 0; i < n; i += 2) {
|
||||
range(i); // $ range=>=0 SPURIOUS: range="<=call to f3_get-1" range="<=call to f3_get-2"
|
||||
range(i); // $ range=>=0 SPURIOUS: range="<=Phi: call to f3_get-1" range="<=Phi: call to f3_get-2"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,13 +8,19 @@ edges
|
||||
| overflowdestination.cpp:23:45:23:48 | argv indirection | overflowdestination.cpp:30:17:30:20 | arg1 indirection |
|
||||
| overflowdestination.cpp:23:45:23:48 | argv indirection | overflowdestination.cpp:30:17:30:20 | arg1 indirection |
|
||||
| overflowdestination.cpp:43:8:43:10 | fgets output argument | overflowdestination.cpp:46:15:46:17 | src indirection |
|
||||
| overflowdestination.cpp:50:52:50:54 | src indirection | overflowdestination.cpp:53:9:53:12 | memcpy output argument |
|
||||
| overflowdestination.cpp:50:52:50:54 | src indirection | overflowdestination.cpp:53:15:53:17 | src indirection |
|
||||
| overflowdestination.cpp:50:52:50:54 | src indirection | overflowdestination.cpp:53:15:53:17 | src indirection |
|
||||
| overflowdestination.cpp:50:52:50:54 | src indirection | overflowdestination.cpp:54:9:54:12 | memcpy output argument |
|
||||
| overflowdestination.cpp:53:9:53:12 | memcpy output argument | overflowdestination.cpp:54:9:54:12 | memcpy output argument |
|
||||
| overflowdestination.cpp:54:9:54:12 | memcpy output argument | overflowdestination.cpp:54:9:54:12 | memcpy output argument |
|
||||
| overflowdestination.cpp:57:52:57:54 | src indirection | overflowdestination.cpp:64:16:64:19 | src2 indirection |
|
||||
| overflowdestination.cpp:57:52:57:54 | src indirection | overflowdestination.cpp:64:16:64:19 | src2 indirection |
|
||||
| overflowdestination.cpp:73:8:73:10 | fgets output argument | overflowdestination.cpp:75:30:75:32 | src indirection |
|
||||
| overflowdestination.cpp:73:8:73:10 | fgets output argument | overflowdestination.cpp:76:30:76:32 | src indirection |
|
||||
| overflowdestination.cpp:75:30:75:32 | overflowdest_test2 output argument | overflowdestination.cpp:76:30:76:32 | src indirection |
|
||||
| overflowdestination.cpp:75:30:75:32 | src indirection | overflowdestination.cpp:50:52:50:54 | src indirection |
|
||||
| overflowdestination.cpp:75:30:75:32 | src indirection | overflowdestination.cpp:75:30:75:32 | overflowdest_test2 output argument |
|
||||
| overflowdestination.cpp:76:30:76:32 | src indirection | overflowdestination.cpp:57:52:57:54 | src indirection |
|
||||
nodes
|
||||
| main.cpp:6:27:6:30 | argv indirection | semmle.label | argv indirection |
|
||||
@@ -28,15 +34,20 @@ nodes
|
||||
| overflowdestination.cpp:43:8:43:10 | fgets output argument | semmle.label | fgets output argument |
|
||||
| overflowdestination.cpp:46:15:46:17 | src indirection | semmle.label | src indirection |
|
||||
| overflowdestination.cpp:50:52:50:54 | src indirection | semmle.label | src indirection |
|
||||
| overflowdestination.cpp:53:9:53:12 | memcpy output argument | semmle.label | memcpy output argument |
|
||||
| overflowdestination.cpp:53:15:53:17 | src indirection | semmle.label | src indirection |
|
||||
| overflowdestination.cpp:53:15:53:17 | src indirection | semmle.label | src indirection |
|
||||
| overflowdestination.cpp:54:9:54:12 | memcpy output argument | semmle.label | memcpy output argument |
|
||||
| overflowdestination.cpp:57:52:57:54 | src indirection | semmle.label | src indirection |
|
||||
| overflowdestination.cpp:64:16:64:19 | src2 indirection | semmle.label | src2 indirection |
|
||||
| overflowdestination.cpp:64:16:64:19 | src2 indirection | semmle.label | src2 indirection |
|
||||
| overflowdestination.cpp:73:8:73:10 | fgets output argument | semmle.label | fgets output argument |
|
||||
| overflowdestination.cpp:75:30:75:32 | overflowdest_test2 output argument | semmle.label | overflowdest_test2 output argument |
|
||||
| overflowdestination.cpp:75:30:75:32 | src indirection | semmle.label | src indirection |
|
||||
| overflowdestination.cpp:76:30:76:32 | src indirection | semmle.label | src indirection |
|
||||
subpaths
|
||||
| overflowdestination.cpp:75:30:75:32 | src indirection | overflowdestination.cpp:50:52:50:54 | src indirection | overflowdestination.cpp:53:9:53:12 | memcpy output argument | overflowdestination.cpp:75:30:75:32 | overflowdest_test2 output argument |
|
||||
| overflowdestination.cpp:75:30:75:32 | src indirection | overflowdestination.cpp:50:52:50:54 | src indirection | overflowdestination.cpp:54:9:54:12 | memcpy output argument | overflowdestination.cpp:75:30:75:32 | overflowdest_test2 output argument |
|
||||
#select
|
||||
| overflowdestination.cpp:30:2:30:8 | call to strncpy | main.cpp:6:27:6:30 | argv indirection | overflowdestination.cpp:30:17:30:20 | arg1 indirection | To avoid overflow, this operation should be bounded by destination-buffer size, not source-buffer size. |
|
||||
| overflowdestination.cpp:30:2:30:8 | call to strncpy | main.cpp:6:27:6:30 | argv indirection | overflowdestination.cpp:30:17:30:20 | arg1 indirection | To avoid overflow, this operation should be bounded by destination-buffer size, not source-buffer size. |
|
||||
|
||||
Reference in New Issue
Block a user