Merge remote-tracking branch 'upstream/master' into ir-copy-unloaded-result

Fixed conflicts by accepting new qltest output.

Conflicts:
      cpp/ql/test/library-tests/ir/ir/raw_ir.expected
      cpp/ql/test/library-tests/ir/ssa/aliased_ssa_ir.expected
      cpp/ql/test/library-tests/ir/ssa/unaliased_ssa_ir.expected
      cpp/ql/test/library-tests/syntax-zoo/aliased_ssa_sanity.expected
      cpp/ql/test/library-tests/syntax-zoo/unaliased_ssa_sanity.expected
This commit is contained in:
Jonas Jensen
2019-10-23 08:46:39 +02:00
764 changed files with 47816 additions and 11145 deletions

View File

@@ -14,9 +14,16 @@ import cpp
from RelationalOperation e, BinaryBitwiseOperation lhs
where
lhs = e.getGreaterOperand() and
lhs.getActualType().(IntegralType).isSigned() and
forall(int op | op = lhs.(BitwiseAndExpr).getAnOperand().getValue().toInt() | op < 0) and
// `lhs > 0` (or `0 < lhs`)
// (note that `lhs < 0`, `lhs >= 0` or `lhs <= 0` all imply that the signedness of
// `lhs` is understood, so should not be flagged).
(e instanceof GTExpr or e instanceof LTExpr) and
e.getGreaterOperand() = lhs and
e.getLesserOperand().getValue() = "0" and
// lhs is signed
lhs.getActualType().(IntegralType).isSigned() and
// if `lhs` has the form `x & c`, with constant `c`, `c` is negative
forall(int op | op = lhs.(BitwiseAndExpr).getAnOperand().getValue().toInt() | op < 0) and
// exception for cases involving macros
not e.isAffectedByMacro()
select e, "Potential unsafe sign check of a bitwise operation."

View File

@@ -14,5 +14,8 @@
import cpp
from ComparisonOperation co, ComparisonOperation chco
where co.getAChild() = chco and not chco.isParenthesised()
where
co.getAChild() = chco and
not chco.isParenthesised() and
not co.isFromUninstantiatedTemplate(_)
select co, "Check the comparison operator precedence."

View File

@@ -30,7 +30,7 @@ private predicate additionalLogicalCheck(Expr e, string operation, int valueToCh
/**
* An `Operation` that seems to be checking for leap year.
*/
class CheckForLeapYearOperation extends Operation {
class CheckForLeapYearOperation extends Expr {
CheckForLeapYearOperation() {
exists(BinaryArithmeticOperation bo | bo = this |
bo.getAnOperand().getValue().toInt() = 4 and
@@ -39,8 +39,6 @@ class CheckForLeapYearOperation extends Operation {
additionalLogicalCheck(this.getEnclosingElement(), "%", 400)
)
}
override string getOperator() { result = "LeapYearCheck" }
}
/**

View File

@@ -0,0 +1,15 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>Using TLS or SSLv23 protool from the boost::asio library, but not disabling deprecated protocols or disabling minimum-recommended protocols.</p>
</overview>
<references>
<li>
<a href="https://www.boost.org/doc/libs/1_71_0/doc/html/boost_asio.html">Boost.Asio documentation</a>.
</li>
</references>
</qhelp>

View File

@@ -0,0 +1,119 @@
/**
* @name Boost_asio TLS Settings Misconfiguration
* @description Using TLS or SSLv23 protool from the boost::asio library, but not disabling deprecated protocols or disabling minimum-recommended protocols
* @kind problem
* @problem.severity error
* @id cpp/boost/tls_settings_misconfiguration
* @tags security
*/
import cpp
import semmle.code.cpp.security.boostorg.asio.protocols
class ExistsAnyFlowConfig extends DataFlow::Configuration {
ExistsAnyFlowConfig() { this = "ExistsAnyFlowConfig" }
override predicate isSource(DataFlow::Node source) { any() }
override predicate isSink(DataFlow::Node sink) { any() }
}
bindingset[flag]
predicate isOptionSet(ConstructorCall cc, int flag, FunctionCall fcSetOptions) {
exists(
BoostorgAsio::SslContextFlowsToSetOptionConfig config, ExistsAnyFlowConfig testConfig,
Expr optionsSink
|
config.hasFlow(DataFlow::exprNode(cc), DataFlow::exprNode(optionsSink)) and
exists(VariableAccess contextSetOptions |
testConfig.hasFlow(DataFlow::exprNode(cc), DataFlow::exprNode(contextSetOptions)) and
exists(BoostorgAsio::SslSetOptionsFunction f | f.getACallToThisFunction() = fcSetOptions |
contextSetOptions = fcSetOptions.getQualifier() and
forall(
Expr optionArgument, BoostorgAsio::SslOptionConfig optionArgConfig,
Expr optionArgumentSource
|
optionArgument = fcSetOptions.getArgument(0) and
optionArgConfig
.hasFlow(DataFlow::exprNode(optionArgumentSource), DataFlow::exprNode(optionArgument))
|
optionArgument.getValue().toInt().bitShiftRight(16).bitAnd(flag) = flag
)
)
)
)
}
bindingset[flag]
predicate isOptionNotSet(ConstructorCall cc, int flag) {
not exists(
BoostorgAsio::SslContextFlowsToSetOptionConfig config, ExistsAnyFlowConfig testConfig,
Expr optionsSink
|
config.hasFlow(DataFlow::exprNode(cc), DataFlow::exprNode(optionsSink)) and
exists(VariableAccess contextSetOptions |
testConfig.hasFlow(DataFlow::exprNode(cc), DataFlow::exprNode(contextSetOptions)) and
exists(FunctionCall fcSetOptions, BoostorgAsio::SslSetOptionsFunction f |
f.getACallToThisFunction() = fcSetOptions
|
contextSetOptions = fcSetOptions.getQualifier() and
forall(
Expr optionArgument, BoostorgAsio::SslOptionConfig optionArgConfig,
Expr optionArgumentSource
|
optionArgument = fcSetOptions.getArgument(0) and
optionArgConfig
.hasFlow(DataFlow::exprNode(optionArgumentSource), DataFlow::exprNode(optionArgument))
|
optionArgument.getValue().toInt().bitShiftRight(16).bitAnd(flag) = flag
)
)
)
)
}
from
BoostorgAsio::SslContextCallTlsProtocolConfig configConstructor,
BoostorgAsio::SslContextFlowsToSetOptionConfig config, Expr protocolSource, Expr protocolSink,
ConstructorCall cc, Expr e, string msg
where
configConstructor.hasFlow(DataFlow::exprNode(protocolSource), DataFlow::exprNode(protocolSink)) and
cc.getArgument(0) = protocolSink and
(
BoostorgAsio::isExprSslV23BoostProtocol(protocolSource) and
not exists(Expr optionsSink |
config.hasFlow(DataFlow::exprNode(cc), DataFlow::exprNode(optionsSink)) and
isOptionSet(cc, BoostorgAsio::getShiftedSslOptionsNoSsl3(), _) and
isOptionSet(cc, BoostorgAsio::getShiftedSslOptionsNoTls1(), _) and
isOptionSet(cc, BoostorgAsio::getShiftedSslOptionsNoTls1_1(), _) and
isOptionNotSet(cc, BoostorgAsio::getShiftedSslOptionsNoTls1_2())
)
or
BoostorgAsio::isExprTlsBoostProtocol(protocolSource) and
not BoostorgAsio::isExprSslV23BoostProtocol(protocolSource) and
not exists(Expr optionsSink |
config.hasFlow(DataFlow::exprNode(cc), DataFlow::exprNode(optionsSink)) and
isOptionSet(cc, BoostorgAsio::getShiftedSslOptionsNoTls1(), _) and
isOptionSet(cc, BoostorgAsio::getShiftedSslOptionsNoTls1_1(), _) and
isOptionNotSet(cc, BoostorgAsio::getShiftedSslOptionsNoTls1_2())
)
) and
(
BoostorgAsio::isExprSslV23BoostProtocol(protocolSource) and
isOptionNotSet(cc, BoostorgAsio::getShiftedSslOptionsNoSsl3()) and
e = cc and
msg = "no_sslv3 has not been set"
or
isOptionNotSet(cc, BoostorgAsio::getShiftedSslOptionsNoTls1()) and
e = cc and
msg = "no_tlsv1 has not been set"
or
isOptionNotSet(cc, BoostorgAsio::getShiftedSslOptionsNoTls1_1()) and
e = cc and
msg = "no_tlsv1_1 has not been set"
or
isOptionSet(cc, BoostorgAsio::getShiftedSslOptionsNoTls1_2(), e) and
msg = "no_tlsv1_2 was set"
)
select cc, "Usage of $@ with protocol $@ is not configured correctly: The option $@.", cc,
"boost::asio::ssl::context::context", protocolSource, protocolSource.toString(), e, msg

View File

@@ -0,0 +1,16 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>Using boost::asio library but specifying a deprecated hardcoded protocol.</p>
<p>Using a deprecated hardcoded protocol instead of negotiting would lock your application to a protocol that has known vulnerabilities or weaknesses.</p>
</overview>
<references>
<li>
<a href="https://www.boost.org/doc/libs/1_71_0/doc/html/boost_asio.html">Boost.Asio documentation</a>.
</li>
</references>
</qhelp>

View File

@@ -0,0 +1,27 @@
/**
* @name boost::asio Use of deprecated hardcoded Protocol
* @description Using a deprecated hard-coded protocol using the boost::asio library.
* @kind problem
* @problem.severity error
* @id cpp/boost/use-of-deprecated-hardcoded-security-protocol
* @tags security
*/
import cpp
import semmle.code.cpp.security.boostorg.asio.protocols
from
BoostorgAsio::SslContextCallConfig config, Expr protocolSource, Expr protocolSink,
ConstructorCall cc
where
config.hasFlow(DataFlow::exprNode(protocolSource), DataFlow::exprNode(protocolSink)) and
not exists(BoostorgAsio::SslContextCallTlsProtocolConfig tlsConfig |
tlsConfig.hasFlow(DataFlow::exprNode(protocolSource), DataFlow::exprNode(protocolSink))
) and
cc.getArgument(0) = protocolSink and
exists(BoostorgAsio::SslContextCallBannedProtocolConfig bannedConfig |
bannedConfig.hasFlow(DataFlow::exprNode(protocolSource), DataFlow::exprNode(protocolSink))
)
select protocolSink, "Usage of $@ specifying a deprecated hardcoded protocol $@ in function $@.",
cc, "boost::asio::ssl::context::context", protocolSource, protocolSource.toString(),
cc.getEnclosingFunction(), cc.getEnclosingFunction().toString()

View File

@@ -0,0 +1,14 @@
- description: Standard LGTM queries for C/C++, including ones not displayed by default
- qlpack: codeql-cpp
- apply: lgtm-selectors.yml
from: codeql-suite-helpers
# These queries are infeasible to compute on large projects:
- exclude:
query path:
- Security/CWE/CWE-497/ExposedSystemData.ql
- Critical/DescriptorMayNotBeClosed.ql
- Critical/DescriptorNeverClosed.ql
- Critical/FileMayNotBeClosed.ql
- Critical/FileNeverClosed.ql
- Critical/MemoryMayNotBeFreed.ql
- Critical/MemoryNeverFreed.ql

View File

@@ -0,0 +1,4 @@
- description: Standard LGTM queries for C/C++
- apply: codeql-suites/cpp-lgtm-full.qls
- apply: lgtm-displayed-only.yml
from: codeql-suite-helpers

View File

@@ -51,7 +51,7 @@ class ReferenceCopyAssignmentOperator extends MemberFunction {
/**
* A call to a function called swap. Note: could be a member,
* std::swap or a function overloading std::swap (not in std::)
* `std::swap` or a function overloading `std::swap` (not in `std::`)
* so keep it simple
*/
FunctionCall getASwapCall() {

View File

@@ -10,7 +10,7 @@
/*
* See More Effective C++ item 7.
* Note: Meyers allows unary & to be overloaded but not comma
* Note: Meyers allows unary `&` to be overloaded but not comma.
*/
import cpp

View File

@@ -15,11 +15,11 @@ import cpp
/*
* Interpretation and deviations:
* - if the higher operator has precedence > arithmetic then it is fine
* RATIONALE: exprs like f(), *x, &x are easily understood to bind tightly
* RATIONALE: exprs like `f()`, `*x`, `&x` are easily understood to bind tightly
* - if the higher operator is the RHS of an assign then it is fine
* RATIONALE: cf. MISRA, too many cases excluded otherwise
* - comparison operators can be mixed with arithmetic
* RATIONALE: x==y+z is common and unambiguous
* RATIONALE: `x==y+z` is common and unambiguous
*/
predicate arithmeticPrecedence(int p) { p = 12 or p = 13 }

4
cpp/ql/src/qlpack.yml Normal file
View File

@@ -0,0 +1,4 @@
name: codeql-cpp
version: 0.0.0
dbscheme: semmlecode.cpp.dbscheme
suites: codeql-suites

View File

@@ -14,8 +14,12 @@ private import semmle.code.cpp.internal.QualifiedName as Q
* ```
* extern int myglobal;
* ```
* Each of these declarations is given its own distinct `DeclarationEntry`,
* but they all share the same `Declaration`.
* and defined in one:
* ```
* int myglobal;
* ```
* Each of these declarations (including the definition) is given its own
* distinct `DeclarationEntry`, but they all share the same `Declaration`.
*
* Some derived class of `Declaration` do not have a corresponding
* `DeclarationEntry`, because they always have a unique source location.
@@ -206,9 +210,19 @@ abstract class Declaration extends Locatable, @declaration {
}
/**
* A C/C++ declaration entry. See the comment above `Declaration` for an
* explanation of the relationship between `Declaration` and
* `DeclarationEntry`.
* A C/C++ declaration entry. For example the following code contains five
* declaration entries:
* ```
* extern int myGlobal;
* int myVariable;
* typedef char MyChar;
* void myFunction();
* void myFunction() {
* // ...
* }
* ```
* See the comment above `Declaration` for an explanation of the relationship
* between `Declaration` and `DeclarationEntry`.
*/
abstract class DeclarationEntry extends Locatable {
/** Gets a specifier associated with this declaration entry. */
@@ -281,8 +295,19 @@ abstract class DeclarationEntry extends Locatable {
* A declaration that can potentially have more C++ access rights than its
* enclosing element. This comprises `Class` (they have access to their own
* private members) along with other `UserType`s and `Function` (they can be
* the target of `friend` declarations).
* the target of `friend` declarations). For example `MyClass` and
* `myFunction` in the following code:
* ```
* class MyClass
* {
* public:
* ...
* };
*
* void myFunction() {
* // ...
* }
* ```
* In the C++ standard (N4140 11.2), rules for access control revolve around
* the informal phrase "_R_ occurs in a member or friend of class C", where
* `AccessHolder` corresponds to this _R_.
@@ -416,8 +441,19 @@ abstract class AccessHolder extends Declaration {
/**
* A declaration that very likely has more C++ access rights than its
* enclosing element. This comprises `Class` (they have access to their own
* private members) along with any target of a `friend` declaration.
* private members) along with any target of a `friend` declaration. For
* example `MyClass` and `friendFunction` in the following code:
* ```
* class MyClass
* {
* public:
* friend void friendFunction();
* };
*
* void friendFunction() {
* // ...
* }
* ```
* Most access rights are computed for `DirectAccessHolder` instead of
* `AccessHolder` -- that's more efficient because there are fewer
* `DirectAccessHolder`s. If a `DirectAccessHolder` contains an `AccessHolder`,

View File

@@ -158,3 +158,10 @@ class Parameter extends LocalScopeVariable, @parameter {
)
}
}
/**
* An `int` that is a parameter index for some function. This is needed for binding in certain cases.
*/
class ParameterIndex extends int {
ParameterIndex() { exists(Parameter p | this = p.getIndex()) }
}

View File

@@ -3,11 +3,17 @@ private import semmle.code.cpp.internal.ResolveClass
/**
* A C/C++ typedef type. See 4.9.1.
*
* Represents either of the following typedef styles:
*
* * CTypedefType: typedef <type> <name>;
* * UsingAliasTypedefType: using <name> = <type>;
*/
class TypedefType extends UserType {
TypedefType() { usertypes(underlyingElement(this), _, 5) }
override string getCanonicalQLClass() { result = "TypedefType" }
TypedefType() {
usertypes(underlyingElement(this), _, 5) or
usertypes(underlyingElement(this), _, 14)
}
/**
* Gets the base type of this typedef type.
@@ -26,10 +32,6 @@ class TypedefType extends UserType {
result = this.getBaseType().getPointerIndirectionLevel()
}
override string explain() {
result = "typedef {" + this.getBaseType().explain() + "} as \"" + this.getName() + "\""
}
override predicate isDeeplyConst() { this.getBaseType().isDeeplyConst() } // Just an alias
override predicate isDeeplyConstBelow() { this.getBaseType().isDeeplyConstBelow() } // Just an alias
@@ -45,6 +47,32 @@ class TypedefType extends UserType {
override Type stripType() { result = getBaseType().stripType() }
}
/**
* A traditional C/C++ typedef type. See 4.9.1.
*/
class CTypedefType extends TypedefType {
CTypedefType() { usertypes(underlyingElement(this), _, 5) }
override string getCanonicalQLClass() { result = "CTypedefType" }
override string explain() {
result = "typedef {" + this.getBaseType().explain() + "} as \"" + this.getName() + "\""
}
}
/**
* A using alias C++ typedef type.
*/
class UsingAliasTypedefType extends TypedefType {
UsingAliasTypedefType() { usertypes(underlyingElement(this), _, 14) }
override string getCanonicalQLClass() { result = "UsingAliasTypedefType" }
override string explain() {
result = "using {" + this.getBaseType().explain() + "} as \"" + this.getName() + "\""
}
}
/**
* A C++ typedef type that is directly enclosed by a function.
*/

View File

@@ -169,7 +169,11 @@ class FormattingFunctionCall extends Expr {
* Gets the number of arguments to this call that are parameters to the
* format string.
*/
int getNumFormatArgument() { result = count(this.getFormatArgument(_)) }
int getNumFormatArgument() {
result = count(this.getFormatArgument(_)) and
// format arguments must be known
exists(getTarget().(FormattingFunction).getFirstFormatArgumentIndex())
}
}
/**

View File

@@ -1,6 +1,7 @@
import cpp
import BasicBlocks
private import semmle.code.cpp.controlflow.internal.ConstantExprs
private import semmle.code.cpp.controlflow.internal.CFG
/**
* A control-flow node is either a statement or an expression; in addition,
@@ -86,11 +87,11 @@ import ControlFlowGraphPublic
class ControlFlowNodeBase extends ElementBase, @cfgnode { }
predicate truecond_base(ControlFlowNodeBase n1, ControlFlowNodeBase n2) {
truecond(unresolveElement(n1), unresolveElement(n2))
qlCFGTrueSuccessor(n1, n2)
}
predicate falsecond_base(ControlFlowNodeBase n1, ControlFlowNodeBase n2) {
falsecond(unresolveElement(n1), unresolveElement(n2))
qlCFGFalseSuccessor(n1, n2)
}
/**
@@ -120,7 +121,7 @@ abstract class AdditionalControlFlowEdge extends ControlFlowNodeBase {
* `AdditionalControlFlowEdge`. Use this relation instead of `successors`.
*/
predicate successors_extended(ControlFlowNodeBase source, ControlFlowNodeBase target) {
successors(unresolveElement(source), unresolveElement(target))
qlCFGSuccessor(source, target)
or
source.(AdditionalControlFlowEdge).getAnEdgeTarget() = target
}

View File

@@ -156,7 +156,7 @@ private predicate compares_eq(
/**
* If `test => part` and `part => left == right + k` then `test => left == right + k`.
* Similarly for the case where `test` is false.
* Similarly for the case where `test` is false.
*/
private predicate logical_comparison_eq(
BinaryLogicalOperation test, Expr left, Expr right, int k, boolean areEqual, boolean testIsTrue
@@ -275,7 +275,7 @@ private predicate compares_ge(
/**
* If `test => part` and `part => left < right + k` then `test => left < right + k`.
* Similarly for the case where `test` evaluates false.
* Similarly for the case where `test` evaluates false.
*/
private predicate logical_comparison_lt(
BinaryLogicalOperation test, Expr left, Expr right, int k, boolean isLt, boolean testIsTrue
@@ -362,7 +362,7 @@ private predicate add_lt(
)
}
/** The int value of integer constant expression. */
/** The `int` value of integer constant expression. */
private int int_value(Expr e) {
e.getUnderlyingType() instanceof IntegralType and
result = e.getValue().toInt()

View File

@@ -29,11 +29,11 @@ class SsaDefinition extends ControlFlowNodeBase {
/**
* Gets a string representation of the SSA variable represented by the pair
* (this, v).
* `(this, v)`.
*/
string toString(LocalScopeVariable v) { exists(StandardSSA x | result = x.toString(this, v)) }
/** Gets a use of the SSA variable represented by the pair (this, v). */
/** Gets a use of the SSA variable represented by the pair `(this, v)`. */
VariableAccess getAUse(LocalScopeVariable v) {
exists(StandardSSA x | result = x.getAUse(this, v))
}

View File

@@ -173,49 +173,36 @@ predicate excludeNode(Node n) {
excludeNode(n.getParentNode())
}
private newtype TPos =
PosBefore() or
PosAt() or
PosAfter() or
PosBeforeDestructors() or
PosAfterDestructors()
/** A `Pos` without a `bindingset` requirement on the constructor. */
private class AnyPos extends TPos {
string toString() { result = "Pos" }
}
/**
* A constant that indicates the type of sub-node in a pair of `(Node, Pos)`.
* See the comment block at the top of this file.
*/
private class Pos extends AnyPos {
// This is to make sure we get compile errors in code that forgets to restrict a `Pos`.
private class Pos extends int {
bindingset[this]
Pos() { any() }
/** Holds if this is the position just _before_ the associated `Node`. */
predicate isBefore() { this = PosBefore() }
predicate isBefore() { this = 0 }
/** Holds if `(n, this)` is the sub-node that represents `n` itself. */
predicate isAt() { this = PosAt() }
predicate isAt() { this = 1 }
/** Holds if this is the position just _after_ the associated `Node`. */
predicate isAfter() { this = PosAfter() }
predicate isAfter() { this = 2 }
/**
* Holds if `(n, this)` is the virtual sub-node that comes just _before_ any
* implicit destructor calls following `n`. The node `n` will be some node
* that may be followed by local variables going out of scope.
*/
predicate isBeforeDestructors() { this = PosBeforeDestructors() }
predicate isBeforeDestructors() { this = 3 }
/**
* Holds if `(n, this)` is the virtual sub-node that comes just _after_ any
* implicit destructor calls following `n`. The node `n` will be some node
* that may be followed by local variables going out of scope.
*/
predicate isAfterDestructors() { this = PosAfterDestructors() }
predicate isAfterDestructors() { this = 4 }
pragma[inline]
predicate nodeBefore(Node n, Node nEq) { this.isBefore() and n = nEq }
@@ -489,17 +476,6 @@ private Node getLastControlOrderChild(Node n) {
result = getControlOrderChildDense(n, max(int i | exists(getControlOrderChildDense(n, i))))
}
private newtype TSpec =
SpecPos(AnyPos p) or
SpecAround() or
SpecAroundDestructors() or
SpecBarrier()
/** A `Spec` without a `bindingset` requirement on the constructor. */
private class AnySpec extends TSpec {
string toString() { result = "Spec" }
}
/**
* A constant that represents two positions: one position for when it's used as
* the _source_ of a sub-edge, and another position for when it's used as the
@@ -507,25 +483,10 @@ private class AnySpec extends TSpec {
* themselves as both source and target, as well as two _around_ values and a
* _barrier_ value.
*/
private class Spec extends AnySpec {
private class Spec extends Pos {
bindingset[this]
Spec() { any() }
/** See Pos.isBefore. */
predicate isBefore() { this = SpecPos(PosBefore()) }
/** See Pos.isAt. */
predicate isAt() { this = SpecPos(PosAt()) }
/** See Pos.isAfter. */
predicate isAfter() { this = SpecPos(PosAfter()) }
/** See Pos.isBeforeDestructors. */
predicate isBeforeDestructors() { this = SpecPos(PosBeforeDestructors()) }
/** See Pos.isAfterDestructors. */
predicate isAfterDestructors() { this = SpecPos(PosAfterDestructors()) }
/**
* Holds if this spec, when used on a node `n` between `(n1, p1)` and
* `(n2, p2)`, should add the following sub-edges.
@@ -533,7 +494,7 @@ private class Spec extends AnySpec {
* (n1, p1) ----> before(n)
* after(n) ----> (n2, p2)
*/
predicate isAround() { this = SpecAround() }
predicate isAround() { this = 5 }
/**
* Holds if this spec, when used on a node `n` between `(n1, p1)` and
@@ -542,16 +503,17 @@ private class Spec extends AnySpec {
* (n1, p1) ----> beforeDestructors(n)
* afterDestructors(n) ----> (n2, p2)
*/
predicate isAroundDestructors() { this = SpecAroundDestructors() }
predicate isAroundDestructors() { this = 6 }
/**
* Holds if this node is a _barrier_. A barrier resolves to no positions and
* can be inserted between nodes that should have no sub-edges between them.
*/
predicate isBarrier() { this = SpecBarrier() }
predicate isBarrier() { this = 7 }
Pos getSourcePos() {
this = SpecPos(result)
this = [0 .. 4] and
result = this
or
this.isAround() and
result.isAfter()
@@ -561,7 +523,8 @@ private class Spec extends AnySpec {
}
Pos getTargetPos() {
this = SpecPos(result)
this = [0 .. 4] and
result = this
or
this.isAround() and
result.isBefore()
@@ -888,6 +851,21 @@ private predicate subEdge(Pos p1, Node n1, Node n2, Pos p2) {
p2.nodeAfter(n2, s)
)
or
// ConstexprIfStmt -> condition ; { then, else } -> // same as IfStmt
exists(ConstexprIfStmt s |
p1.nodeAt(n1, s) and
p2.nodeBefore(n2, s.getCondition())
or
p1.nodeAfter(n1, s.getThen()) and
p2.nodeBeforeDestructors(n2, s)
or
p1.nodeAfter(n1, s.getElse()) and
p2.nodeBeforeDestructors(n2, s)
or
p1.nodeAfterDestructors(n1, s) and
p2.nodeAfter(n2, s)
)
or
// WhileStmt -> condition ; body -> condition ; after dtors -> after
exists(WhileStmt s |
p1.nodeAt(n1, s) and
@@ -1175,9 +1153,8 @@ private class ExceptionSource extends Node {
}
/**
* Holds if `test` is the test of a control-flow construct that will always
* have true/false sub-edges out of it, where the `truth`-sub-edge goes to
* `(n2, p2)`.
* Holds if `test` is the test of a control-flow construct where the `truth`
* sub-edge goes to `(n2, p2)`.
*/
private predicate conditionJumpsTop(Expr test, boolean truth, Node n2, Pos p2) {
exists(IfStmt s | test = s.getCondition() |
@@ -1192,6 +1169,24 @@ private predicate conditionJumpsTop(Expr test, boolean truth, Node n2, Pos p2) {
p2.nodeBeforeDestructors(n2, s)
)
or
exists(ConstexprIfStmt s, string cond |
test = s.getCondition() and
cond = test.getFullyConverted().getValue()
|
truth = true and
cond != "0" and
p2.nodeBefore(n2, s.getThen())
or
truth = false and
cond = "0" and
p2.nodeBefore(n2, s.getElse())
or
not exists(s.getElse()) and
truth = false and
cond = "0" and
p2.nodeBeforeDestructors(n2, s)
)
or
exists(Loop l |
(
l instanceof WhileStmt

View File

@@ -7,7 +7,7 @@
* on each other without introducing mutual recursion among those configurations.
*/
private import DataFlowImplCommon
private import DataFlowImplCommon::Public
private import DataFlowImplSpecific::Private
import DataFlowImplSpecific::Public
@@ -905,30 +905,35 @@ private predicate localFlowExit(Node node, Configuration config) {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
Node node1, Node node2, boolean preservesValue, Configuration config
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
) {
localFlowEntry(node1, config) and
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowStep(node1, node2, config) and preservesValue = true
localFlowEntry(node1, config) and
(
localFlowStep(node1, node2, config) and preservesValue = true
or
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
nodeCand(node2, unbind(config))
or
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
) and
node1 != node2 and
nodeCand(node2, unbind(config))
or
exists(Node mid |
localFlowStepPlus(node1, mid, preservesValue, config) and
localFlowStep(mid, node2, config) and
not mid instanceof CastNode and
nodeCand(node2, unbind(config))
)
or
exists(Node mid |
localFlowStepPlus(node1, mid, _, config) and
additionalLocalFlowStep(mid, node2, config) and
not mid instanceof CastNode and
preservesValue = false and
nodeCand(node2, unbind(config))
exists(Node mid |
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
localFlowStep(mid, node2, config) and
not mid instanceof CastNode and
nodeCand(node2, unbind(config))
)
or
exists(Node mid |
localFlowStepPlus(node1, mid, _, config, cc) and
additionalLocalFlowStep(mid, node2, config) and
not mid instanceof CastNode and
preservesValue = false and
nodeCand(node2, unbind(config))
)
)
}
@@ -936,11 +941,11 @@ private predicate localFlowStepPlus(
* Holds if `node1` can step to `node2` in one or more local steps and this
* path can occur as a maximal subsequence of local steps in a dataflow path.
*/
pragma[noinline]
pragma[nomagic]
private predicate localFlowBigStep(
Node node1, Node node2, boolean preservesValue, Configuration config
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
) {
localFlowStepPlus(node1, node2, preservesValue, config) and
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
localFlowExit(node2, config)
}
@@ -1000,7 +1005,7 @@ private class AccessPathFrontNilNode extends Node {
(
any(Configuration c).isSource(this)
or
localFlowBigStep(_, this, false, _)
localFlowBigStep(_, this, false, _, _)
or
additionalJumpStep(_, this, _)
)
@@ -1023,12 +1028,12 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf,
(
exists(Node mid |
flowCandFwd(mid, fromArg, apf, config) and
localFlowBigStep(mid, node, true, config)
localFlowBigStep(mid, node, true, config, _)
)
or
exists(Node mid, AccessPathFrontNil nil |
flowCandFwd(mid, fromArg, nil, config) and
localFlowBigStep(mid, node, false, config) and
localFlowBigStep(mid, node, false, config, _) and
apf = node.(AccessPathFrontNilNode).getApf()
)
or
@@ -1075,6 +1080,7 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf,
flowCandFwd(mid, fromArg, _, config) and
store(mid, f, node) and
nodeCand(node, unbind(config)) and
readStoreCand(f, unbind(config)) and
apf.headUsesContent(f)
)
or
@@ -1121,13 +1127,13 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co
apf instanceof AccessPathFrontNil
or
exists(Node mid |
localFlowBigStep(node, mid, true, config) and
localFlowBigStep(node, mid, true, config, _) and
flowCand(mid, toReturn, apf, config)
)
or
exists(Node mid, AccessPathFrontNil nil |
flowCandFwd(node, _, apf, config) and
localFlowBigStep(node, mid, false, config) and
localFlowBigStep(node, mid, false, config, _) and
flowCand(mid, toReturn, nil, config) and
apf instanceof AccessPathFrontNil
)
@@ -1175,12 +1181,12 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co
exists(Content f, AccessPathFront apf0 |
flowCandStore(node, f, toReturn, apf0, config) and
apf0.headUsesContent(f) and
consCand(f, apf, unbind(config))
consCand(f, apf, config)
)
or
exists(Content f, AccessPathFront apf0 |
flowCandRead(node, f, toReturn, apf0, config) and
consCandFwd(f, apf0, unbind(config)) and
consCandFwd(f, apf0, config) and
apf.headUsesContent(f)
)
}
@@ -1221,8 +1227,8 @@ private newtype TAccessPath =
TConsCons(Content f1, Content f2, int len) { consCand(f1, TFrontHead(f2), _) and len in [2 .. 5] }
/**
* Conceptually a list of `Content`s followed by a `Type`, but only the first
* element of the list and its length are tracked. If data flows from a source to
* Conceptually a list of `Content`s followed by a `Type`, but only the first two
* elements of the list and its length are tracked. If data flows from a source to
* a given node with a given `AccessPath`, this indicates the sequence of
* dereference operations needed to get from the value in the node to the
* tracked object. The final type indicates the type of the tracked object.
@@ -1260,7 +1266,7 @@ abstract private class AccessPath extends TAccessPath {
private class AccessPathNil extends AccessPath, TNil {
override string toString() {
exists(DataFlowType t | this = TNil(t) | result = concat(" : " + ppReprType(t)))
exists(DataFlowType t | this = TNil(t) | result = concat(": " + ppReprType(t)))
}
override AccessPathFront getFront() {
@@ -1276,7 +1282,7 @@ private class AccessPathConsNil extends AccessPathCons, TConsNil {
override string toString() {
exists(Content f, DataFlowType t | this = TConsNil(f, t) |
// The `concat` becomes "" if `ppReprType` has no result.
result = f.toString() + concat(" : " + ppReprType(t))
result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t))
)
}
@@ -1293,8 +1299,8 @@ private class AccessPathConsCons extends AccessPathCons, TConsCons {
override string toString() {
exists(Content f1, Content f2, int len | this = TConsCons(f1, f2, len) |
if len = 2
then result = f1.toString() + ", " + f2.toString()
else result = f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")"
then result = "[" + f1.toString() + ", " + f2.toString() + "]"
else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]"
)
}
@@ -1362,12 +1368,12 @@ private predicate flowFwd0(
(
exists(Node mid |
flowFwd(mid, fromArg, apf, ap, config) and
localFlowBigStep(mid, node, true, config)
localFlowBigStep(mid, node, true, config, _)
)
or
exists(Node mid, AccessPathNil nil |
flowFwd(mid, fromArg, _, nil, config) and
localFlowBigStep(mid, node, false, config) and
localFlowBigStep(mid, node, false, config, _) and
ap = node.(AccessPathNilNode).getAp() and
apf = ap.(AccessPathNil).getFront()
)
@@ -1471,13 +1477,13 @@ private predicate flow0(Node node, boolean toReturn, AccessPath ap, Configuratio
ap instanceof AccessPathNil
or
exists(Node mid |
localFlowBigStep(node, mid, true, config) and
localFlowBigStep(node, mid, true, config, _) and
flow(mid, toReturn, ap, config)
)
or
exists(Node mid, AccessPathNil nil |
flowFwd(node, _, _, ap, config) and
localFlowBigStep(node, mid, false, config) and
localFlowBigStep(node, mid, false, config, _) and
flow(mid, toReturn, nil, config) and
ap instanceof AccessPathNil
)
@@ -1625,7 +1631,7 @@ abstract class PathNode extends TPathNode {
this instanceof PathNodeSink and result = ""
or
exists(string s | s = this.(PathNodeMid).getAp().toString() |
if s = "" then result = "" else result = " [" + s + "]"
if s = "" then result = "" else result = " " + s
)
}
@@ -1728,14 +1734,20 @@ private class PathNodeSink extends PathNode, TPathNodeSink {
* a callable is recorded by `cc`.
*/
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, AccessPath ap) {
localFlowBigStep(mid.getNode(), node, true, mid.getConfiguration()) and
cc = mid.getCallContext() and
ap = mid.getAp()
or
localFlowBigStep(mid.getNode(), node, false, mid.getConfiguration()) and
cc = mid.getCallContext() and
mid.getAp() instanceof AccessPathNil and
ap = node.(AccessPathNilNode).getAp()
exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf |
midnode = mid.getNode() and
conf = mid.getConfiguration() and
cc = mid.getCallContext() and
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
ap0 = mid.getAp()
|
localFlowBigStep(midnode, node, true, conf, localCC) and
ap = ap0
or
localFlowBigStep(midnode, node, false, conf, localCC) and
ap0 instanceof AccessPathNil and
ap = node.(AccessPathNilNode).getAp()
)
or
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
cc instanceof CallContextAny and
@@ -1879,7 +1891,7 @@ private predicate pathIntoCallable(
pathIntoCallable0(mid, callable, i, outercc, call, emptyAp) and
p.isParameterOf(callable, i)
|
if reducedViableImplInCallContext(_, callable, call)
if recordDataFlowCallSite(call, callable)
then innercc = TSpecificCall(call, i, emptyAp)
else innercc = TSomeCall(p, emptyAp)
)
@@ -2070,7 +2082,7 @@ private module FlowExploration {
private class PartialAccessPathNil extends PartialAccessPath, TPartialNil {
override string toString() {
exists(DataFlowType t | this = TPartialNil(t) | result = concat(" : " + ppReprType(t)))
exists(DataFlowType t | this = TPartialNil(t) | result = concat(": " + ppReprType(t)))
}
override AccessPathFront getFront() {
@@ -2082,8 +2094,8 @@ private module FlowExploration {
override string toString() {
exists(Content f, int len | this = TPartialCons(f, len) |
if len = 1
then result = f.toString()
else result = f.toString() + ", ... (" + len.toString() + ")"
then result = "[" + f.toString() + "]"
else result = "[" + f.toString() + ", ... (" + len.toString() + ")]"
)
}
@@ -2160,7 +2172,7 @@ private module FlowExploration {
private string ppAp() {
exists(string s | s = this.(PartialPathNodePriv).getAp().toString() |
if s = "" then result = "" else result = " [" + s + "]"
if s = "" then result = "" else result = " " + s
)
}
@@ -2204,16 +2216,19 @@ private module FlowExploration {
private predicate partialPathStep(
PartialPathNodePriv mid, Node node, CallContext cc, PartialAccessPath ap, Configuration config
) {
localFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
additionalLocalFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and
mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getErasedRepr(node.getType())) and
config = mid.getConfiguration()
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
(
localFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
additionalLocalFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and
mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getErasedRepr(node.getType())) and
config = mid.getConfiguration()
)
or
jumpStep(mid.getNode(), node, config) and
cc instanceof CallContextAny and
@@ -2377,7 +2392,7 @@ private module FlowExploration {
partialPathIntoCallable0(mid, callable, i, outercc, call, emptyAp, ap, config) and
p.isParameterOf(callable, i)
|
if reducedViableImplInCallContext(_, callable, call)
if recordDataFlowCallSite(call, callable)
then innercc = TSpecificCall(call, i, emptyAp)
else innercc = TSomeCall(p, emptyAp)
)

View File

@@ -7,7 +7,7 @@
* on each other without introducing mutual recursion among those configurations.
*/
private import DataFlowImplCommon
private import DataFlowImplCommon::Public
private import DataFlowImplSpecific::Private
import DataFlowImplSpecific::Public
@@ -905,30 +905,35 @@ private predicate localFlowExit(Node node, Configuration config) {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
Node node1, Node node2, boolean preservesValue, Configuration config
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
) {
localFlowEntry(node1, config) and
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowStep(node1, node2, config) and preservesValue = true
localFlowEntry(node1, config) and
(
localFlowStep(node1, node2, config) and preservesValue = true
or
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
nodeCand(node2, unbind(config))
or
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
) and
node1 != node2 and
nodeCand(node2, unbind(config))
or
exists(Node mid |
localFlowStepPlus(node1, mid, preservesValue, config) and
localFlowStep(mid, node2, config) and
not mid instanceof CastNode and
nodeCand(node2, unbind(config))
)
or
exists(Node mid |
localFlowStepPlus(node1, mid, _, config) and
additionalLocalFlowStep(mid, node2, config) and
not mid instanceof CastNode and
preservesValue = false and
nodeCand(node2, unbind(config))
exists(Node mid |
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
localFlowStep(mid, node2, config) and
not mid instanceof CastNode and
nodeCand(node2, unbind(config))
)
or
exists(Node mid |
localFlowStepPlus(node1, mid, _, config, cc) and
additionalLocalFlowStep(mid, node2, config) and
not mid instanceof CastNode and
preservesValue = false and
nodeCand(node2, unbind(config))
)
)
}
@@ -936,11 +941,11 @@ private predicate localFlowStepPlus(
* Holds if `node1` can step to `node2` in one or more local steps and this
* path can occur as a maximal subsequence of local steps in a dataflow path.
*/
pragma[noinline]
pragma[nomagic]
private predicate localFlowBigStep(
Node node1, Node node2, boolean preservesValue, Configuration config
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
) {
localFlowStepPlus(node1, node2, preservesValue, config) and
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
localFlowExit(node2, config)
}
@@ -1000,7 +1005,7 @@ private class AccessPathFrontNilNode extends Node {
(
any(Configuration c).isSource(this)
or
localFlowBigStep(_, this, false, _)
localFlowBigStep(_, this, false, _, _)
or
additionalJumpStep(_, this, _)
)
@@ -1023,12 +1028,12 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf,
(
exists(Node mid |
flowCandFwd(mid, fromArg, apf, config) and
localFlowBigStep(mid, node, true, config)
localFlowBigStep(mid, node, true, config, _)
)
or
exists(Node mid, AccessPathFrontNil nil |
flowCandFwd(mid, fromArg, nil, config) and
localFlowBigStep(mid, node, false, config) and
localFlowBigStep(mid, node, false, config, _) and
apf = node.(AccessPathFrontNilNode).getApf()
)
or
@@ -1075,6 +1080,7 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf,
flowCandFwd(mid, fromArg, _, config) and
store(mid, f, node) and
nodeCand(node, unbind(config)) and
readStoreCand(f, unbind(config)) and
apf.headUsesContent(f)
)
or
@@ -1121,13 +1127,13 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co
apf instanceof AccessPathFrontNil
or
exists(Node mid |
localFlowBigStep(node, mid, true, config) and
localFlowBigStep(node, mid, true, config, _) and
flowCand(mid, toReturn, apf, config)
)
or
exists(Node mid, AccessPathFrontNil nil |
flowCandFwd(node, _, apf, config) and
localFlowBigStep(node, mid, false, config) and
localFlowBigStep(node, mid, false, config, _) and
flowCand(mid, toReturn, nil, config) and
apf instanceof AccessPathFrontNil
)
@@ -1175,12 +1181,12 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co
exists(Content f, AccessPathFront apf0 |
flowCandStore(node, f, toReturn, apf0, config) and
apf0.headUsesContent(f) and
consCand(f, apf, unbind(config))
consCand(f, apf, config)
)
or
exists(Content f, AccessPathFront apf0 |
flowCandRead(node, f, toReturn, apf0, config) and
consCandFwd(f, apf0, unbind(config)) and
consCandFwd(f, apf0, config) and
apf.headUsesContent(f)
)
}
@@ -1221,8 +1227,8 @@ private newtype TAccessPath =
TConsCons(Content f1, Content f2, int len) { consCand(f1, TFrontHead(f2), _) and len in [2 .. 5] }
/**
* Conceptually a list of `Content`s followed by a `Type`, but only the first
* element of the list and its length are tracked. If data flows from a source to
* Conceptually a list of `Content`s followed by a `Type`, but only the first two
* elements of the list and its length are tracked. If data flows from a source to
* a given node with a given `AccessPath`, this indicates the sequence of
* dereference operations needed to get from the value in the node to the
* tracked object. The final type indicates the type of the tracked object.
@@ -1260,7 +1266,7 @@ abstract private class AccessPath extends TAccessPath {
private class AccessPathNil extends AccessPath, TNil {
override string toString() {
exists(DataFlowType t | this = TNil(t) | result = concat(" : " + ppReprType(t)))
exists(DataFlowType t | this = TNil(t) | result = concat(": " + ppReprType(t)))
}
override AccessPathFront getFront() {
@@ -1276,7 +1282,7 @@ private class AccessPathConsNil extends AccessPathCons, TConsNil {
override string toString() {
exists(Content f, DataFlowType t | this = TConsNil(f, t) |
// The `concat` becomes "" if `ppReprType` has no result.
result = f.toString() + concat(" : " + ppReprType(t))
result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t))
)
}
@@ -1293,8 +1299,8 @@ private class AccessPathConsCons extends AccessPathCons, TConsCons {
override string toString() {
exists(Content f1, Content f2, int len | this = TConsCons(f1, f2, len) |
if len = 2
then result = f1.toString() + ", " + f2.toString()
else result = f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")"
then result = "[" + f1.toString() + ", " + f2.toString() + "]"
else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]"
)
}
@@ -1362,12 +1368,12 @@ private predicate flowFwd0(
(
exists(Node mid |
flowFwd(mid, fromArg, apf, ap, config) and
localFlowBigStep(mid, node, true, config)
localFlowBigStep(mid, node, true, config, _)
)
or
exists(Node mid, AccessPathNil nil |
flowFwd(mid, fromArg, _, nil, config) and
localFlowBigStep(mid, node, false, config) and
localFlowBigStep(mid, node, false, config, _) and
ap = node.(AccessPathNilNode).getAp() and
apf = ap.(AccessPathNil).getFront()
)
@@ -1471,13 +1477,13 @@ private predicate flow0(Node node, boolean toReturn, AccessPath ap, Configuratio
ap instanceof AccessPathNil
or
exists(Node mid |
localFlowBigStep(node, mid, true, config) and
localFlowBigStep(node, mid, true, config, _) and
flow(mid, toReturn, ap, config)
)
or
exists(Node mid, AccessPathNil nil |
flowFwd(node, _, _, ap, config) and
localFlowBigStep(node, mid, false, config) and
localFlowBigStep(node, mid, false, config, _) and
flow(mid, toReturn, nil, config) and
ap instanceof AccessPathNil
)
@@ -1625,7 +1631,7 @@ abstract class PathNode extends TPathNode {
this instanceof PathNodeSink and result = ""
or
exists(string s | s = this.(PathNodeMid).getAp().toString() |
if s = "" then result = "" else result = " [" + s + "]"
if s = "" then result = "" else result = " " + s
)
}
@@ -1728,14 +1734,20 @@ private class PathNodeSink extends PathNode, TPathNodeSink {
* a callable is recorded by `cc`.
*/
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, AccessPath ap) {
localFlowBigStep(mid.getNode(), node, true, mid.getConfiguration()) and
cc = mid.getCallContext() and
ap = mid.getAp()
or
localFlowBigStep(mid.getNode(), node, false, mid.getConfiguration()) and
cc = mid.getCallContext() and
mid.getAp() instanceof AccessPathNil and
ap = node.(AccessPathNilNode).getAp()
exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf |
midnode = mid.getNode() and
conf = mid.getConfiguration() and
cc = mid.getCallContext() and
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
ap0 = mid.getAp()
|
localFlowBigStep(midnode, node, true, conf, localCC) and
ap = ap0
or
localFlowBigStep(midnode, node, false, conf, localCC) and
ap0 instanceof AccessPathNil and
ap = node.(AccessPathNilNode).getAp()
)
or
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
cc instanceof CallContextAny and
@@ -1879,7 +1891,7 @@ private predicate pathIntoCallable(
pathIntoCallable0(mid, callable, i, outercc, call, emptyAp) and
p.isParameterOf(callable, i)
|
if reducedViableImplInCallContext(_, callable, call)
if recordDataFlowCallSite(call, callable)
then innercc = TSpecificCall(call, i, emptyAp)
else innercc = TSomeCall(p, emptyAp)
)
@@ -2070,7 +2082,7 @@ private module FlowExploration {
private class PartialAccessPathNil extends PartialAccessPath, TPartialNil {
override string toString() {
exists(DataFlowType t | this = TPartialNil(t) | result = concat(" : " + ppReprType(t)))
exists(DataFlowType t | this = TPartialNil(t) | result = concat(": " + ppReprType(t)))
}
override AccessPathFront getFront() {
@@ -2082,8 +2094,8 @@ private module FlowExploration {
override string toString() {
exists(Content f, int len | this = TPartialCons(f, len) |
if len = 1
then result = f.toString()
else result = f.toString() + ", ... (" + len.toString() + ")"
then result = "[" + f.toString() + "]"
else result = "[" + f.toString() + ", ... (" + len.toString() + ")]"
)
}
@@ -2160,7 +2172,7 @@ private module FlowExploration {
private string ppAp() {
exists(string s | s = this.(PartialPathNodePriv).getAp().toString() |
if s = "" then result = "" else result = " [" + s + "]"
if s = "" then result = "" else result = " " + s
)
}
@@ -2204,16 +2216,19 @@ private module FlowExploration {
private predicate partialPathStep(
PartialPathNodePriv mid, Node node, CallContext cc, PartialAccessPath ap, Configuration config
) {
localFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
additionalLocalFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and
mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getErasedRepr(node.getType())) and
config = mid.getConfiguration()
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
(
localFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
additionalLocalFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and
mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getErasedRepr(node.getType())) and
config = mid.getConfiguration()
)
or
jumpStep(mid.getNode(), node, config) and
cc instanceof CallContextAny and
@@ -2377,7 +2392,7 @@ private module FlowExploration {
partialPathIntoCallable0(mid, callable, i, outercc, call, emptyAp, ap, config) and
p.isParameterOf(callable, i)
|
if reducedViableImplInCallContext(_, callable, call)
if recordDataFlowCallSite(call, callable)
then innercc = TSpecificCall(call, i, emptyAp)
else innercc = TSomeCall(p, emptyAp)
)

View File

@@ -7,7 +7,7 @@
* on each other without introducing mutual recursion among those configurations.
*/
private import DataFlowImplCommon
private import DataFlowImplCommon::Public
private import DataFlowImplSpecific::Private
import DataFlowImplSpecific::Public
@@ -905,30 +905,35 @@ private predicate localFlowExit(Node node, Configuration config) {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
Node node1, Node node2, boolean preservesValue, Configuration config
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
) {
localFlowEntry(node1, config) and
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowStep(node1, node2, config) and preservesValue = true
localFlowEntry(node1, config) and
(
localFlowStep(node1, node2, config) and preservesValue = true
or
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
nodeCand(node2, unbind(config))
or
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
) and
node1 != node2 and
nodeCand(node2, unbind(config))
or
exists(Node mid |
localFlowStepPlus(node1, mid, preservesValue, config) and
localFlowStep(mid, node2, config) and
not mid instanceof CastNode and
nodeCand(node2, unbind(config))
)
or
exists(Node mid |
localFlowStepPlus(node1, mid, _, config) and
additionalLocalFlowStep(mid, node2, config) and
not mid instanceof CastNode and
preservesValue = false and
nodeCand(node2, unbind(config))
exists(Node mid |
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
localFlowStep(mid, node2, config) and
not mid instanceof CastNode and
nodeCand(node2, unbind(config))
)
or
exists(Node mid |
localFlowStepPlus(node1, mid, _, config, cc) and
additionalLocalFlowStep(mid, node2, config) and
not mid instanceof CastNode and
preservesValue = false and
nodeCand(node2, unbind(config))
)
)
}
@@ -936,11 +941,11 @@ private predicate localFlowStepPlus(
* Holds if `node1` can step to `node2` in one or more local steps and this
* path can occur as a maximal subsequence of local steps in a dataflow path.
*/
pragma[noinline]
pragma[nomagic]
private predicate localFlowBigStep(
Node node1, Node node2, boolean preservesValue, Configuration config
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
) {
localFlowStepPlus(node1, node2, preservesValue, config) and
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
localFlowExit(node2, config)
}
@@ -1000,7 +1005,7 @@ private class AccessPathFrontNilNode extends Node {
(
any(Configuration c).isSource(this)
or
localFlowBigStep(_, this, false, _)
localFlowBigStep(_, this, false, _, _)
or
additionalJumpStep(_, this, _)
)
@@ -1023,12 +1028,12 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf,
(
exists(Node mid |
flowCandFwd(mid, fromArg, apf, config) and
localFlowBigStep(mid, node, true, config)
localFlowBigStep(mid, node, true, config, _)
)
or
exists(Node mid, AccessPathFrontNil nil |
flowCandFwd(mid, fromArg, nil, config) and
localFlowBigStep(mid, node, false, config) and
localFlowBigStep(mid, node, false, config, _) and
apf = node.(AccessPathFrontNilNode).getApf()
)
or
@@ -1075,6 +1080,7 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf,
flowCandFwd(mid, fromArg, _, config) and
store(mid, f, node) and
nodeCand(node, unbind(config)) and
readStoreCand(f, unbind(config)) and
apf.headUsesContent(f)
)
or
@@ -1121,13 +1127,13 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co
apf instanceof AccessPathFrontNil
or
exists(Node mid |
localFlowBigStep(node, mid, true, config) and
localFlowBigStep(node, mid, true, config, _) and
flowCand(mid, toReturn, apf, config)
)
or
exists(Node mid, AccessPathFrontNil nil |
flowCandFwd(node, _, apf, config) and
localFlowBigStep(node, mid, false, config) and
localFlowBigStep(node, mid, false, config, _) and
flowCand(mid, toReturn, nil, config) and
apf instanceof AccessPathFrontNil
)
@@ -1175,12 +1181,12 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co
exists(Content f, AccessPathFront apf0 |
flowCandStore(node, f, toReturn, apf0, config) and
apf0.headUsesContent(f) and
consCand(f, apf, unbind(config))
consCand(f, apf, config)
)
or
exists(Content f, AccessPathFront apf0 |
flowCandRead(node, f, toReturn, apf0, config) and
consCandFwd(f, apf0, unbind(config)) and
consCandFwd(f, apf0, config) and
apf.headUsesContent(f)
)
}
@@ -1221,8 +1227,8 @@ private newtype TAccessPath =
TConsCons(Content f1, Content f2, int len) { consCand(f1, TFrontHead(f2), _) and len in [2 .. 5] }
/**
* Conceptually a list of `Content`s followed by a `Type`, but only the first
* element of the list and its length are tracked. If data flows from a source to
* Conceptually a list of `Content`s followed by a `Type`, but only the first two
* elements of the list and its length are tracked. If data flows from a source to
* a given node with a given `AccessPath`, this indicates the sequence of
* dereference operations needed to get from the value in the node to the
* tracked object. The final type indicates the type of the tracked object.
@@ -1260,7 +1266,7 @@ abstract private class AccessPath extends TAccessPath {
private class AccessPathNil extends AccessPath, TNil {
override string toString() {
exists(DataFlowType t | this = TNil(t) | result = concat(" : " + ppReprType(t)))
exists(DataFlowType t | this = TNil(t) | result = concat(": " + ppReprType(t)))
}
override AccessPathFront getFront() {
@@ -1276,7 +1282,7 @@ private class AccessPathConsNil extends AccessPathCons, TConsNil {
override string toString() {
exists(Content f, DataFlowType t | this = TConsNil(f, t) |
// The `concat` becomes "" if `ppReprType` has no result.
result = f.toString() + concat(" : " + ppReprType(t))
result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t))
)
}
@@ -1293,8 +1299,8 @@ private class AccessPathConsCons extends AccessPathCons, TConsCons {
override string toString() {
exists(Content f1, Content f2, int len | this = TConsCons(f1, f2, len) |
if len = 2
then result = f1.toString() + ", " + f2.toString()
else result = f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")"
then result = "[" + f1.toString() + ", " + f2.toString() + "]"
else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]"
)
}
@@ -1362,12 +1368,12 @@ private predicate flowFwd0(
(
exists(Node mid |
flowFwd(mid, fromArg, apf, ap, config) and
localFlowBigStep(mid, node, true, config)
localFlowBigStep(mid, node, true, config, _)
)
or
exists(Node mid, AccessPathNil nil |
flowFwd(mid, fromArg, _, nil, config) and
localFlowBigStep(mid, node, false, config) and
localFlowBigStep(mid, node, false, config, _) and
ap = node.(AccessPathNilNode).getAp() and
apf = ap.(AccessPathNil).getFront()
)
@@ -1471,13 +1477,13 @@ private predicate flow0(Node node, boolean toReturn, AccessPath ap, Configuratio
ap instanceof AccessPathNil
or
exists(Node mid |
localFlowBigStep(node, mid, true, config) and
localFlowBigStep(node, mid, true, config, _) and
flow(mid, toReturn, ap, config)
)
or
exists(Node mid, AccessPathNil nil |
flowFwd(node, _, _, ap, config) and
localFlowBigStep(node, mid, false, config) and
localFlowBigStep(node, mid, false, config, _) and
flow(mid, toReturn, nil, config) and
ap instanceof AccessPathNil
)
@@ -1625,7 +1631,7 @@ abstract class PathNode extends TPathNode {
this instanceof PathNodeSink and result = ""
or
exists(string s | s = this.(PathNodeMid).getAp().toString() |
if s = "" then result = "" else result = " [" + s + "]"
if s = "" then result = "" else result = " " + s
)
}
@@ -1728,14 +1734,20 @@ private class PathNodeSink extends PathNode, TPathNodeSink {
* a callable is recorded by `cc`.
*/
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, AccessPath ap) {
localFlowBigStep(mid.getNode(), node, true, mid.getConfiguration()) and
cc = mid.getCallContext() and
ap = mid.getAp()
or
localFlowBigStep(mid.getNode(), node, false, mid.getConfiguration()) and
cc = mid.getCallContext() and
mid.getAp() instanceof AccessPathNil and
ap = node.(AccessPathNilNode).getAp()
exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf |
midnode = mid.getNode() and
conf = mid.getConfiguration() and
cc = mid.getCallContext() and
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
ap0 = mid.getAp()
|
localFlowBigStep(midnode, node, true, conf, localCC) and
ap = ap0
or
localFlowBigStep(midnode, node, false, conf, localCC) and
ap0 instanceof AccessPathNil and
ap = node.(AccessPathNilNode).getAp()
)
or
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
cc instanceof CallContextAny and
@@ -1879,7 +1891,7 @@ private predicate pathIntoCallable(
pathIntoCallable0(mid, callable, i, outercc, call, emptyAp) and
p.isParameterOf(callable, i)
|
if reducedViableImplInCallContext(_, callable, call)
if recordDataFlowCallSite(call, callable)
then innercc = TSpecificCall(call, i, emptyAp)
else innercc = TSomeCall(p, emptyAp)
)
@@ -2070,7 +2082,7 @@ private module FlowExploration {
private class PartialAccessPathNil extends PartialAccessPath, TPartialNil {
override string toString() {
exists(DataFlowType t | this = TPartialNil(t) | result = concat(" : " + ppReprType(t)))
exists(DataFlowType t | this = TPartialNil(t) | result = concat(": " + ppReprType(t)))
}
override AccessPathFront getFront() {
@@ -2082,8 +2094,8 @@ private module FlowExploration {
override string toString() {
exists(Content f, int len | this = TPartialCons(f, len) |
if len = 1
then result = f.toString()
else result = f.toString() + ", ... (" + len.toString() + ")"
then result = "[" + f.toString() + "]"
else result = "[" + f.toString() + ", ... (" + len.toString() + ")]"
)
}
@@ -2160,7 +2172,7 @@ private module FlowExploration {
private string ppAp() {
exists(string s | s = this.(PartialPathNodePriv).getAp().toString() |
if s = "" then result = "" else result = " [" + s + "]"
if s = "" then result = "" else result = " " + s
)
}
@@ -2204,16 +2216,19 @@ private module FlowExploration {
private predicate partialPathStep(
PartialPathNodePriv mid, Node node, CallContext cc, PartialAccessPath ap, Configuration config
) {
localFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
additionalLocalFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and
mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getErasedRepr(node.getType())) and
config = mid.getConfiguration()
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
(
localFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
additionalLocalFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and
mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getErasedRepr(node.getType())) and
config = mid.getConfiguration()
)
or
jumpStep(mid.getNode(), node, config) and
cc instanceof CallContextAny and
@@ -2377,7 +2392,7 @@ private module FlowExploration {
partialPathIntoCallable0(mid, callable, i, outercc, call, emptyAp, ap, config) and
p.isParameterOf(callable, i)
|
if reducedViableImplInCallContext(_, callable, call)
if recordDataFlowCallSite(call, callable)
then innercc = TSpecificCall(call, i, emptyAp)
else innercc = TSomeCall(p, emptyAp)
)

View File

@@ -7,7 +7,7 @@
* on each other without introducing mutual recursion among those configurations.
*/
private import DataFlowImplCommon
private import DataFlowImplCommon::Public
private import DataFlowImplSpecific::Private
import DataFlowImplSpecific::Public
@@ -905,30 +905,35 @@ private predicate localFlowExit(Node node, Configuration config) {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
Node node1, Node node2, boolean preservesValue, Configuration config
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
) {
localFlowEntry(node1, config) and
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowStep(node1, node2, config) and preservesValue = true
localFlowEntry(node1, config) and
(
localFlowStep(node1, node2, config) and preservesValue = true
or
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
nodeCand(node2, unbind(config))
or
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
) and
node1 != node2 and
nodeCand(node2, unbind(config))
or
exists(Node mid |
localFlowStepPlus(node1, mid, preservesValue, config) and
localFlowStep(mid, node2, config) and
not mid instanceof CastNode and
nodeCand(node2, unbind(config))
)
or
exists(Node mid |
localFlowStepPlus(node1, mid, _, config) and
additionalLocalFlowStep(mid, node2, config) and
not mid instanceof CastNode and
preservesValue = false and
nodeCand(node2, unbind(config))
exists(Node mid |
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
localFlowStep(mid, node2, config) and
not mid instanceof CastNode and
nodeCand(node2, unbind(config))
)
or
exists(Node mid |
localFlowStepPlus(node1, mid, _, config, cc) and
additionalLocalFlowStep(mid, node2, config) and
not mid instanceof CastNode and
preservesValue = false and
nodeCand(node2, unbind(config))
)
)
}
@@ -936,11 +941,11 @@ private predicate localFlowStepPlus(
* Holds if `node1` can step to `node2` in one or more local steps and this
* path can occur as a maximal subsequence of local steps in a dataflow path.
*/
pragma[noinline]
pragma[nomagic]
private predicate localFlowBigStep(
Node node1, Node node2, boolean preservesValue, Configuration config
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
) {
localFlowStepPlus(node1, node2, preservesValue, config) and
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
localFlowExit(node2, config)
}
@@ -1000,7 +1005,7 @@ private class AccessPathFrontNilNode extends Node {
(
any(Configuration c).isSource(this)
or
localFlowBigStep(_, this, false, _)
localFlowBigStep(_, this, false, _, _)
or
additionalJumpStep(_, this, _)
)
@@ -1023,12 +1028,12 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf,
(
exists(Node mid |
flowCandFwd(mid, fromArg, apf, config) and
localFlowBigStep(mid, node, true, config)
localFlowBigStep(mid, node, true, config, _)
)
or
exists(Node mid, AccessPathFrontNil nil |
flowCandFwd(mid, fromArg, nil, config) and
localFlowBigStep(mid, node, false, config) and
localFlowBigStep(mid, node, false, config, _) and
apf = node.(AccessPathFrontNilNode).getApf()
)
or
@@ -1075,6 +1080,7 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf,
flowCandFwd(mid, fromArg, _, config) and
store(mid, f, node) and
nodeCand(node, unbind(config)) and
readStoreCand(f, unbind(config)) and
apf.headUsesContent(f)
)
or
@@ -1121,13 +1127,13 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co
apf instanceof AccessPathFrontNil
or
exists(Node mid |
localFlowBigStep(node, mid, true, config) and
localFlowBigStep(node, mid, true, config, _) and
flowCand(mid, toReturn, apf, config)
)
or
exists(Node mid, AccessPathFrontNil nil |
flowCandFwd(node, _, apf, config) and
localFlowBigStep(node, mid, false, config) and
localFlowBigStep(node, mid, false, config, _) and
flowCand(mid, toReturn, nil, config) and
apf instanceof AccessPathFrontNil
)
@@ -1175,12 +1181,12 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co
exists(Content f, AccessPathFront apf0 |
flowCandStore(node, f, toReturn, apf0, config) and
apf0.headUsesContent(f) and
consCand(f, apf, unbind(config))
consCand(f, apf, config)
)
or
exists(Content f, AccessPathFront apf0 |
flowCandRead(node, f, toReturn, apf0, config) and
consCandFwd(f, apf0, unbind(config)) and
consCandFwd(f, apf0, config) and
apf.headUsesContent(f)
)
}
@@ -1221,8 +1227,8 @@ private newtype TAccessPath =
TConsCons(Content f1, Content f2, int len) { consCand(f1, TFrontHead(f2), _) and len in [2 .. 5] }
/**
* Conceptually a list of `Content`s followed by a `Type`, but only the first
* element of the list and its length are tracked. If data flows from a source to
* Conceptually a list of `Content`s followed by a `Type`, but only the first two
* elements of the list and its length are tracked. If data flows from a source to
* a given node with a given `AccessPath`, this indicates the sequence of
* dereference operations needed to get from the value in the node to the
* tracked object. The final type indicates the type of the tracked object.
@@ -1260,7 +1266,7 @@ abstract private class AccessPath extends TAccessPath {
private class AccessPathNil extends AccessPath, TNil {
override string toString() {
exists(DataFlowType t | this = TNil(t) | result = concat(" : " + ppReprType(t)))
exists(DataFlowType t | this = TNil(t) | result = concat(": " + ppReprType(t)))
}
override AccessPathFront getFront() {
@@ -1276,7 +1282,7 @@ private class AccessPathConsNil extends AccessPathCons, TConsNil {
override string toString() {
exists(Content f, DataFlowType t | this = TConsNil(f, t) |
// The `concat` becomes "" if `ppReprType` has no result.
result = f.toString() + concat(" : " + ppReprType(t))
result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t))
)
}
@@ -1293,8 +1299,8 @@ private class AccessPathConsCons extends AccessPathCons, TConsCons {
override string toString() {
exists(Content f1, Content f2, int len | this = TConsCons(f1, f2, len) |
if len = 2
then result = f1.toString() + ", " + f2.toString()
else result = f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")"
then result = "[" + f1.toString() + ", " + f2.toString() + "]"
else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]"
)
}
@@ -1362,12 +1368,12 @@ private predicate flowFwd0(
(
exists(Node mid |
flowFwd(mid, fromArg, apf, ap, config) and
localFlowBigStep(mid, node, true, config)
localFlowBigStep(mid, node, true, config, _)
)
or
exists(Node mid, AccessPathNil nil |
flowFwd(mid, fromArg, _, nil, config) and
localFlowBigStep(mid, node, false, config) and
localFlowBigStep(mid, node, false, config, _) and
ap = node.(AccessPathNilNode).getAp() and
apf = ap.(AccessPathNil).getFront()
)
@@ -1471,13 +1477,13 @@ private predicate flow0(Node node, boolean toReturn, AccessPath ap, Configuratio
ap instanceof AccessPathNil
or
exists(Node mid |
localFlowBigStep(node, mid, true, config) and
localFlowBigStep(node, mid, true, config, _) and
flow(mid, toReturn, ap, config)
)
or
exists(Node mid, AccessPathNil nil |
flowFwd(node, _, _, ap, config) and
localFlowBigStep(node, mid, false, config) and
localFlowBigStep(node, mid, false, config, _) and
flow(mid, toReturn, nil, config) and
ap instanceof AccessPathNil
)
@@ -1625,7 +1631,7 @@ abstract class PathNode extends TPathNode {
this instanceof PathNodeSink and result = ""
or
exists(string s | s = this.(PathNodeMid).getAp().toString() |
if s = "" then result = "" else result = " [" + s + "]"
if s = "" then result = "" else result = " " + s
)
}
@@ -1728,14 +1734,20 @@ private class PathNodeSink extends PathNode, TPathNodeSink {
* a callable is recorded by `cc`.
*/
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, AccessPath ap) {
localFlowBigStep(mid.getNode(), node, true, mid.getConfiguration()) and
cc = mid.getCallContext() and
ap = mid.getAp()
or
localFlowBigStep(mid.getNode(), node, false, mid.getConfiguration()) and
cc = mid.getCallContext() and
mid.getAp() instanceof AccessPathNil and
ap = node.(AccessPathNilNode).getAp()
exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf |
midnode = mid.getNode() and
conf = mid.getConfiguration() and
cc = mid.getCallContext() and
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
ap0 = mid.getAp()
|
localFlowBigStep(midnode, node, true, conf, localCC) and
ap = ap0
or
localFlowBigStep(midnode, node, false, conf, localCC) and
ap0 instanceof AccessPathNil and
ap = node.(AccessPathNilNode).getAp()
)
or
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
cc instanceof CallContextAny and
@@ -1879,7 +1891,7 @@ private predicate pathIntoCallable(
pathIntoCallable0(mid, callable, i, outercc, call, emptyAp) and
p.isParameterOf(callable, i)
|
if reducedViableImplInCallContext(_, callable, call)
if recordDataFlowCallSite(call, callable)
then innercc = TSpecificCall(call, i, emptyAp)
else innercc = TSomeCall(p, emptyAp)
)
@@ -2070,7 +2082,7 @@ private module FlowExploration {
private class PartialAccessPathNil extends PartialAccessPath, TPartialNil {
override string toString() {
exists(DataFlowType t | this = TPartialNil(t) | result = concat(" : " + ppReprType(t)))
exists(DataFlowType t | this = TPartialNil(t) | result = concat(": " + ppReprType(t)))
}
override AccessPathFront getFront() {
@@ -2082,8 +2094,8 @@ private module FlowExploration {
override string toString() {
exists(Content f, int len | this = TPartialCons(f, len) |
if len = 1
then result = f.toString()
else result = f.toString() + ", ... (" + len.toString() + ")"
then result = "[" + f.toString() + "]"
else result = "[" + f.toString() + ", ... (" + len.toString() + ")]"
)
}
@@ -2160,7 +2172,7 @@ private module FlowExploration {
private string ppAp() {
exists(string s | s = this.(PartialPathNodePriv).getAp().toString() |
if s = "" then result = "" else result = " [" + s + "]"
if s = "" then result = "" else result = " " + s
)
}
@@ -2204,16 +2216,19 @@ private module FlowExploration {
private predicate partialPathStep(
PartialPathNodePriv mid, Node node, CallContext cc, PartialAccessPath ap, Configuration config
) {
localFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
additionalLocalFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and
mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getErasedRepr(node.getType())) and
config = mid.getConfiguration()
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
(
localFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
additionalLocalFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and
mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getErasedRepr(node.getType())) and
config = mid.getConfiguration()
)
or
jumpStep(mid.getNode(), node, config) and
cc instanceof CallContextAny and
@@ -2377,7 +2392,7 @@ private module FlowExploration {
partialPathIntoCallable0(mid, callable, i, outercc, call, emptyAp, ap, config) and
p.isParameterOf(callable, i)
|
if reducedViableImplInCallContext(_, callable, call)
if recordDataFlowCallSite(call, callable)
then innercc = TSpecificCall(call, i, emptyAp)
else innercc = TSomeCall(p, emptyAp)
)

View File

@@ -7,7 +7,7 @@
* on each other without introducing mutual recursion among those configurations.
*/
private import DataFlowImplCommon
private import DataFlowImplCommon::Public
private import DataFlowImplSpecific::Private
import DataFlowImplSpecific::Public
@@ -905,30 +905,35 @@ private predicate localFlowExit(Node node, Configuration config) {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
Node node1, Node node2, boolean preservesValue, Configuration config
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
) {
localFlowEntry(node1, config) and
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowStep(node1, node2, config) and preservesValue = true
localFlowEntry(node1, config) and
(
localFlowStep(node1, node2, config) and preservesValue = true
or
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
nodeCand(node2, unbind(config))
or
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
) and
node1 != node2 and
nodeCand(node2, unbind(config))
or
exists(Node mid |
localFlowStepPlus(node1, mid, preservesValue, config) and
localFlowStep(mid, node2, config) and
not mid instanceof CastNode and
nodeCand(node2, unbind(config))
)
or
exists(Node mid |
localFlowStepPlus(node1, mid, _, config) and
additionalLocalFlowStep(mid, node2, config) and
not mid instanceof CastNode and
preservesValue = false and
nodeCand(node2, unbind(config))
exists(Node mid |
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
localFlowStep(mid, node2, config) and
not mid instanceof CastNode and
nodeCand(node2, unbind(config))
)
or
exists(Node mid |
localFlowStepPlus(node1, mid, _, config, cc) and
additionalLocalFlowStep(mid, node2, config) and
not mid instanceof CastNode and
preservesValue = false and
nodeCand(node2, unbind(config))
)
)
}
@@ -936,11 +941,11 @@ private predicate localFlowStepPlus(
* Holds if `node1` can step to `node2` in one or more local steps and this
* path can occur as a maximal subsequence of local steps in a dataflow path.
*/
pragma[noinline]
pragma[nomagic]
private predicate localFlowBigStep(
Node node1, Node node2, boolean preservesValue, Configuration config
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
) {
localFlowStepPlus(node1, node2, preservesValue, config) and
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
localFlowExit(node2, config)
}
@@ -1000,7 +1005,7 @@ private class AccessPathFrontNilNode extends Node {
(
any(Configuration c).isSource(this)
or
localFlowBigStep(_, this, false, _)
localFlowBigStep(_, this, false, _, _)
or
additionalJumpStep(_, this, _)
)
@@ -1023,12 +1028,12 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf,
(
exists(Node mid |
flowCandFwd(mid, fromArg, apf, config) and
localFlowBigStep(mid, node, true, config)
localFlowBigStep(mid, node, true, config, _)
)
or
exists(Node mid, AccessPathFrontNil nil |
flowCandFwd(mid, fromArg, nil, config) and
localFlowBigStep(mid, node, false, config) and
localFlowBigStep(mid, node, false, config, _) and
apf = node.(AccessPathFrontNilNode).getApf()
)
or
@@ -1075,6 +1080,7 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf,
flowCandFwd(mid, fromArg, _, config) and
store(mid, f, node) and
nodeCand(node, unbind(config)) and
readStoreCand(f, unbind(config)) and
apf.headUsesContent(f)
)
or
@@ -1121,13 +1127,13 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co
apf instanceof AccessPathFrontNil
or
exists(Node mid |
localFlowBigStep(node, mid, true, config) and
localFlowBigStep(node, mid, true, config, _) and
flowCand(mid, toReturn, apf, config)
)
or
exists(Node mid, AccessPathFrontNil nil |
flowCandFwd(node, _, apf, config) and
localFlowBigStep(node, mid, false, config) and
localFlowBigStep(node, mid, false, config, _) and
flowCand(mid, toReturn, nil, config) and
apf instanceof AccessPathFrontNil
)
@@ -1175,12 +1181,12 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co
exists(Content f, AccessPathFront apf0 |
flowCandStore(node, f, toReturn, apf0, config) and
apf0.headUsesContent(f) and
consCand(f, apf, unbind(config))
consCand(f, apf, config)
)
or
exists(Content f, AccessPathFront apf0 |
flowCandRead(node, f, toReturn, apf0, config) and
consCandFwd(f, apf0, unbind(config)) and
consCandFwd(f, apf0, config) and
apf.headUsesContent(f)
)
}
@@ -1221,8 +1227,8 @@ private newtype TAccessPath =
TConsCons(Content f1, Content f2, int len) { consCand(f1, TFrontHead(f2), _) and len in [2 .. 5] }
/**
* Conceptually a list of `Content`s followed by a `Type`, but only the first
* element of the list and its length are tracked. If data flows from a source to
* Conceptually a list of `Content`s followed by a `Type`, but only the first two
* elements of the list and its length are tracked. If data flows from a source to
* a given node with a given `AccessPath`, this indicates the sequence of
* dereference operations needed to get from the value in the node to the
* tracked object. The final type indicates the type of the tracked object.
@@ -1260,7 +1266,7 @@ abstract private class AccessPath extends TAccessPath {
private class AccessPathNil extends AccessPath, TNil {
override string toString() {
exists(DataFlowType t | this = TNil(t) | result = concat(" : " + ppReprType(t)))
exists(DataFlowType t | this = TNil(t) | result = concat(": " + ppReprType(t)))
}
override AccessPathFront getFront() {
@@ -1276,7 +1282,7 @@ private class AccessPathConsNil extends AccessPathCons, TConsNil {
override string toString() {
exists(Content f, DataFlowType t | this = TConsNil(f, t) |
// The `concat` becomes "" if `ppReprType` has no result.
result = f.toString() + concat(" : " + ppReprType(t))
result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t))
)
}
@@ -1293,8 +1299,8 @@ private class AccessPathConsCons extends AccessPathCons, TConsCons {
override string toString() {
exists(Content f1, Content f2, int len | this = TConsCons(f1, f2, len) |
if len = 2
then result = f1.toString() + ", " + f2.toString()
else result = f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")"
then result = "[" + f1.toString() + ", " + f2.toString() + "]"
else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]"
)
}
@@ -1362,12 +1368,12 @@ private predicate flowFwd0(
(
exists(Node mid |
flowFwd(mid, fromArg, apf, ap, config) and
localFlowBigStep(mid, node, true, config)
localFlowBigStep(mid, node, true, config, _)
)
or
exists(Node mid, AccessPathNil nil |
flowFwd(mid, fromArg, _, nil, config) and
localFlowBigStep(mid, node, false, config) and
localFlowBigStep(mid, node, false, config, _) and
ap = node.(AccessPathNilNode).getAp() and
apf = ap.(AccessPathNil).getFront()
)
@@ -1471,13 +1477,13 @@ private predicate flow0(Node node, boolean toReturn, AccessPath ap, Configuratio
ap instanceof AccessPathNil
or
exists(Node mid |
localFlowBigStep(node, mid, true, config) and
localFlowBigStep(node, mid, true, config, _) and
flow(mid, toReturn, ap, config)
)
or
exists(Node mid, AccessPathNil nil |
flowFwd(node, _, _, ap, config) and
localFlowBigStep(node, mid, false, config) and
localFlowBigStep(node, mid, false, config, _) and
flow(mid, toReturn, nil, config) and
ap instanceof AccessPathNil
)
@@ -1625,7 +1631,7 @@ abstract class PathNode extends TPathNode {
this instanceof PathNodeSink and result = ""
or
exists(string s | s = this.(PathNodeMid).getAp().toString() |
if s = "" then result = "" else result = " [" + s + "]"
if s = "" then result = "" else result = " " + s
)
}
@@ -1728,14 +1734,20 @@ private class PathNodeSink extends PathNode, TPathNodeSink {
* a callable is recorded by `cc`.
*/
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, AccessPath ap) {
localFlowBigStep(mid.getNode(), node, true, mid.getConfiguration()) and
cc = mid.getCallContext() and
ap = mid.getAp()
or
localFlowBigStep(mid.getNode(), node, false, mid.getConfiguration()) and
cc = mid.getCallContext() and
mid.getAp() instanceof AccessPathNil and
ap = node.(AccessPathNilNode).getAp()
exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf |
midnode = mid.getNode() and
conf = mid.getConfiguration() and
cc = mid.getCallContext() and
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
ap0 = mid.getAp()
|
localFlowBigStep(midnode, node, true, conf, localCC) and
ap = ap0
or
localFlowBigStep(midnode, node, false, conf, localCC) and
ap0 instanceof AccessPathNil and
ap = node.(AccessPathNilNode).getAp()
)
or
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
cc instanceof CallContextAny and
@@ -1879,7 +1891,7 @@ private predicate pathIntoCallable(
pathIntoCallable0(mid, callable, i, outercc, call, emptyAp) and
p.isParameterOf(callable, i)
|
if reducedViableImplInCallContext(_, callable, call)
if recordDataFlowCallSite(call, callable)
then innercc = TSpecificCall(call, i, emptyAp)
else innercc = TSomeCall(p, emptyAp)
)
@@ -2070,7 +2082,7 @@ private module FlowExploration {
private class PartialAccessPathNil extends PartialAccessPath, TPartialNil {
override string toString() {
exists(DataFlowType t | this = TPartialNil(t) | result = concat(" : " + ppReprType(t)))
exists(DataFlowType t | this = TPartialNil(t) | result = concat(": " + ppReprType(t)))
}
override AccessPathFront getFront() {
@@ -2082,8 +2094,8 @@ private module FlowExploration {
override string toString() {
exists(Content f, int len | this = TPartialCons(f, len) |
if len = 1
then result = f.toString()
else result = f.toString() + ", ... (" + len.toString() + ")"
then result = "[" + f.toString() + "]"
else result = "[" + f.toString() + ", ... (" + len.toString() + ")]"
)
}
@@ -2160,7 +2172,7 @@ private module FlowExploration {
private string ppAp() {
exists(string s | s = this.(PartialPathNodePriv).getAp().toString() |
if s = "" then result = "" else result = " [" + s + "]"
if s = "" then result = "" else result = " " + s
)
}
@@ -2204,16 +2216,19 @@ private module FlowExploration {
private predicate partialPathStep(
PartialPathNodePriv mid, Node node, CallContext cc, PartialAccessPath ap, Configuration config
) {
localFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
additionalLocalFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and
mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getErasedRepr(node.getType())) and
config = mid.getConfiguration()
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
(
localFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
additionalLocalFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and
mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getErasedRepr(node.getType())) and
config = mid.getConfiguration()
)
or
jumpStep(mid.getNode(), node, config) and
cc instanceof CallContextAny and
@@ -2377,7 +2392,7 @@ private module FlowExploration {
partialPathIntoCallable0(mid, callable, i, outercc, call, emptyAp, ap, config) and
p.isParameterOf(callable, i)
|
if reducedViableImplInCallContext(_, callable, call)
if recordDataFlowCallSite(call, callable)
then innercc = TSpecificCall(call, i, emptyAp)
else innercc = TSomeCall(p, emptyAp)
)

View File

@@ -51,7 +51,9 @@ class ArgumentNode extends Node {
DataFlowCall getCall() { this.argumentOf(result, _) }
}
private newtype TReturnKind = TNormalReturnKind()
private newtype TReturnKind =
TNormalReturnKind() or
TRefReturnKind(int i) { exists(Parameter parameter | i = parameter.getIndex()) }
/**
* A return kind. A return kind describes how a value can be returned
@@ -59,23 +61,54 @@ private newtype TReturnKind = TNormalReturnKind()
*/
class ReturnKind extends TReturnKind {
/** Gets a textual representation of this return kind. */
string toString() { result = "return" }
string toString() {
this instanceof TNormalReturnKind and
result = "return"
or
this instanceof TRefReturnKind and
result = "ref"
}
}
/** A data flow node that occurs as the result of a `ReturnStmt`. */
class ReturnNode extends ExprNode {
ReturnNode() { exists(ReturnStmt ret | this.getExpr() = ret.getExpr()) }
/** A data flow node that represents a returned value in the called function. */
abstract class ReturnNode extends Node {
/** Gets the kind of this returned value. */
abstract ReturnKind getKind();
}
/** A `ReturnNode` that occurs as the result of a `ReturnStmt`. */
private class NormalReturnNode extends ReturnNode, ExprNode {
NormalReturnNode() { exists(ReturnStmt ret | this.getExpr() = ret.getExpr()) }
/** Gets the kind of this returned value. */
ReturnKind getKind() { result = TNormalReturnKind() }
override ReturnKind getKind() { result = TNormalReturnKind() }
}
/** A data flow node that represents the output of a call. */
class OutNode extends ExprNode {
OutNode() { this.getExpr() instanceof Call }
/**
* A `ReturnNode` that occurs as a result of a definition of a reference
* parameter reaching the end of a function body.
*/
private class RefReturnNode extends ReturnNode, RefParameterFinalValueNode {
/** Gets the kind of this returned value. */
override ReturnKind getKind() { result = TRefReturnKind(this.getParameter().getIndex()) }
}
/** A data flow node that represents the output of a call at the call site. */
abstract class OutNode extends Node {
/** Gets the underlying call. */
abstract DataFlowCall getCall();
}
private class ExprOutNode extends OutNode, ExprNode {
ExprOutNode() { this.getExpr() instanceof Call }
/** Gets the underlying call. */
DataFlowCall getCall() { result = this.getExpr() }
override DataFlowCall getCall() { result = this.getExpr() }
}
private class RefOutNode extends OutNode, DefinitionByReferenceNode {
/** Gets the underlying call. */
override DataFlowCall getCall() { result = this.getArgument().getParent() }
}
/**
@@ -85,6 +118,11 @@ class OutNode extends ExprNode {
OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) {
result = call.getNode() and
kind = TNormalReturnKind()
or
exists(int i |
result.asDefiningArgument() = call.getArgument(i) and
kind = TRefReturnKind(i)
)
}
/**
@@ -264,3 +302,5 @@ class DataFlowCall extends Expr {
/** Gets the enclosing callable of this call. */
Function getEnclosingCallable() { result = this.getEnclosingFunction() }
}
predicate isUnreachableInCall(Node n, DataFlowCall call) { none() } // stub implementation

View File

@@ -25,7 +25,8 @@ private newtype TNode =
not c.getTarget().getParameter(i).getUnderlyingType().(PointerType).getBaseType().isConst()
)
} or
TUninitializedNode(LocalVariable v) { not v.hasInitializer() }
TUninitializedNode(LocalVariable v) { not v.hasInitializer() } or
TRefParameterFinalValueNode(Parameter p) { exists(FlowVar var | var.reachesRefParameter(p)) }
/**
* A node in a data flow graph.
@@ -248,6 +249,23 @@ class UninitializedNode extends Node, TUninitializedNode {
LocalVariable getLocalVariable() { result = v }
}
/** INTERNAL: do not use. The final value of a non-const ref parameter. */
class RefParameterFinalValueNode extends Node, TRefParameterFinalValueNode {
Parameter p;
RefParameterFinalValueNode() { this = TRefParameterFinalValueNode(p) }
override Function getFunction() { result = p.getFunction() }
override Type getType() { result = p.getType() }
override string toString() { result = p.toString() }
override Location getLocation() { result = p.getLocation() }
Parameter getParameter() { result = p }
}
/**
* A node associated with an object after an operation that might have
* changed its state.
@@ -490,7 +508,7 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
or
var.definedPartiallyAt(nodeFrom.asPartialDefinition())
) and
varToExprStep(var, nodeTo.asExpr())
varToNodeStep(var, nodeTo)
)
or
// Expr -> DefinitionByReferenceNode
@@ -533,9 +551,13 @@ private predicate exprToVarStep(Expr assignedExpr, FlowVar var) {
}
/**
* Holds if the expression `e` is an access of the variable `var`.
* Holds if the node `n` is an access of the variable `var`.
*/
private predicate varToExprStep(FlowVar var, Expr e) { e = var.getAnAccess() }
private predicate varToNodeStep(FlowVar var, Node n) {
n.asExpr() = var.getAnAccess()
or
var.reachesRefParameter(n.(RefParameterFinalValueNode).getParameter())
}
/**
* Holds if data flows from `fromExpr` to `toExpr` directly, in the case
@@ -578,8 +600,8 @@ private predicate exprToExprStep_nocfg(Expr fromExpr, Expr toExpr) {
exists(DataFlowFunction f, FunctionInput inModel, FunctionOutput outModel, int iIn |
call.getTarget() = f and
f.hasDataFlow(inModel, outModel) and
outModel.isOutReturnValue() and
inModel.isInParameter(iIn) and
outModel.isReturnValue() and
inModel.isParameter(iIn) and
fromExpr = call.getArgument(iIn)
)
)
@@ -589,12 +611,12 @@ private predicate exprToDefinitionByReferenceStep(Expr exprIn, Expr argOut) {
exists(DataFlowFunction f, Call call, FunctionOutput outModel, int argOutIndex |
call.getTarget() = f and
argOut = call.getArgument(argOutIndex) and
outModel.isOutParameterPointer(argOutIndex) and
outModel.isParameterDeref(argOutIndex) and
exists(int argInIndex, FunctionInput inModel | f.hasDataFlow(inModel, outModel) |
inModel.isInParameterPointer(argInIndex) and
inModel.isParameterDeref(argInIndex) and
call.passesByReference(argInIndex, exprIn)
or
inModel.isInParameter(argInIndex) and
inModel.isParameter(argInIndex) and
exprIn = call.getArgument(argInIndex)
)
)

View File

@@ -62,9 +62,20 @@ class FlowVar extends TFlowVar {
cached
abstract predicate definedByReference(Expr arg);
/**
* Holds if this `FlowVar` is a `PartialDefinition` whose defined expression
* is `e`.
*/
cached
abstract predicate definedPartiallyAt(Expr e);
/**
* Holds if this `FlowVar` is a definition of a reference parameter `p` that
* persists until the function returns.
*/
cached
abstract predicate reachesRefParameter(Parameter p);
/**
* Holds if this `FlowVar` corresponds to the initial value of `v`. The following
* is an exhaustive list of cases where this may happen.
@@ -338,6 +349,9 @@ module FlowVar_internal {
param = v
}
// `fullySupportedSsaVariable` excludes reference types
override predicate reachesRefParameter(Parameter p) { none() }
/**
* Holds if this `SsaVar` corresponds to a non-phi definition. Users of this
* library will never directly use an `SsaVar` that comes from a phi node,
@@ -387,6 +401,13 @@ module FlowVar_internal {
sbb = v.(Parameter).getFunction().getEntryPoint()
}
override predicate reachesRefParameter(Parameter p) {
parameterIsNonConstReference(p) and
p = v and
// This definition reaches the exit node of the function CFG
getAReachedBlockVarSBB(this).getANode() = p.getFunction()
}
override predicate definedByInitialValue(LocalScopeVariable lsv) {
blockVarDefinedByVariable(sbb, lsv) and
lsv = v
@@ -490,7 +511,7 @@ module FlowVar_internal {
exists(VariableAccess va |
va.getTarget() = result and
readAccess(va) and
bbNotInLoop(va.getBasicBlock())
exists(BasicBlock bb | bb = va.getBasicBlock() | not this.bbInLoop(bb))
)
}
@@ -513,10 +534,8 @@ module FlowVar_internal {
bbInLoopCondition(bb)
}
predicate bbNotInLoop(BasicBlock bb) {
not this.bbInLoop(bb) and
bb.getEnclosingFunction() = this.getEnclosingFunction()
}
/** Holds if `sbb` is inside this loop. */
predicate sbbInLoop(SubBasicBlock sbb) { this.bbInLoop(sbb.getBasicBlock()) }
/**
* Holds if `bb` is a basic block inside this loop where `v` has not been
@@ -537,22 +556,19 @@ module FlowVar_internal {
}
/**
* Holds if some loop always assigns to `v` before leaving through an edge
* from `bbInside` in its condition to `bbOutside` outside the loop, where
* (`sbbDef`, `v`) is a `BlockVar` defined outside the loop. Also, `v` must
* be used outside the loop.
* Holds if `loop` always assigns to `v` before leaving through an edge
* from `bbInside` in its condition to `bbOutside` outside the loop. Also,
* `v` must be used outside the loop.
*/
predicate skipLoop(
SubBasicBlock sbbInside, SubBasicBlock sbbOutside, SubBasicBlock sbbDef, Variable v
SubBasicBlock sbbInside, SubBasicBlock sbbOutside, Variable v, AlwaysTrueUponEntryLoop loop
) {
exists(AlwaysTrueUponEntryLoop loop, BasicBlock bbInside, BasicBlock bbOutside |
exists(BasicBlock bbInside, BasicBlock bbOutside |
loop.alwaysAssignsBeforeLeavingCondition(bbInside, bbOutside, v) and
bbInside = sbbInside.getBasicBlock() and
bbOutside = sbbOutside.getBasicBlock() and
sbbInside.lastInBB() and
sbbOutside.firstInBB() and
loop.bbNotInLoop(sbbDef.getBasicBlock()) and
exists(TBlockVar(sbbDef, v))
sbbOutside.firstInBB()
)
}
@@ -571,7 +587,7 @@ module FlowVar_internal {
start = TBlockVar(sbbDef, v) and
result = mid.getASuccessor() and
variableLiveInSBB(result, v) and
not skipLoop(mid, result, sbbDef, v) and
forall(AlwaysTrueUponEntryLoop loop | skipLoop(mid, result, v, loop) | loop.sbbInLoop(sbbDef)) and
not assignmentLikeOperation(result, v, _, _)
)
}
@@ -593,12 +609,23 @@ module FlowVar_internal {
private predicate variableLiveInSBB(SubBasicBlock sbb, Variable v) {
variableAccessInSBB(v, sbb, _)
or
// Non-const reference parameters are live at the end of the function
parameterIsNonConstReference(v) and
sbb.contains(v.(Parameter).getFunction())
or
exists(SubBasicBlock succ | succ = sbb.getASuccessor() |
variableLiveInSBB(succ, v) and
not variableNotLiveBefore(succ, v)
)
}
predicate parameterIsNonConstReference(Parameter p) {
exists(ReferenceType refType |
refType = p.getUnderlyingType() and
not refType.getBaseType().isConst()
)
}
/**
* Holds if liveness of `v` should stop propagating backwards from `sbb`.
*/
@@ -679,10 +706,11 @@ module FlowVar_internal {
predicate dominatedByOverwrite(UninitializedLocalVariable v, VariableAccess va) {
exists(BasicBlock bb, int vaIndex |
va = bb.getNode(vaIndex) and
va.getTarget() = v
|
va.getTarget() = v and
vaIndex > indexOfFirstOverwriteInBB(v, bb)
or
va = bb.getNode(vaIndex) and
va.getTarget() = v and
bbStrictlyDominates(getAnOverwritingBB(v), bb)
)
}

View File

@@ -122,11 +122,11 @@ private predicate exprToDefinitionByReferenceStep(Expr exprIn, Expr argOut) {
exists(DataFlowFunction f, Call call, FunctionOutput outModel, int argOutIndex |
call.getTarget() = f and
argOut = call.getArgument(argOutIndex) and
outModel.isOutParameterPointer(argOutIndex) and
outModel.isParameterDeref(argOutIndex) and
exists(int argInIndex, FunctionInput inModel | f.hasDataFlow(inModel, outModel) |
// Taint flows from a pointer to a dereference, which DataFlow does not handle
// memcpy(&dest_var, tainted_ptr, len)
inModel.isInParameterPointer(argInIndex) and
inModel.isParameterDeref(argInIndex) and
exprIn = call.getArgument(argInIndex)
)
)
@@ -134,15 +134,15 @@ private predicate exprToDefinitionByReferenceStep(Expr exprIn, Expr argOut) {
exists(TaintFunction f, Call call, FunctionOutput outModel, int argOutIndex |
call.getTarget() = f and
argOut = call.getArgument(argOutIndex) and
outModel.isOutParameterPointer(argOutIndex) and
outModel.isParameterDeref(argOutIndex) and
exists(int argInIndex, FunctionInput inModel | f.hasTaintFlow(inModel, outModel) |
inModel.isInParameterPointer(argInIndex) and
inModel.isParameterDeref(argInIndex) and
exprIn = call.getArgument(argInIndex)
or
inModel.isInParameterPointer(argInIndex) and
inModel.isParameterDeref(argInIndex) and
call.passesByReference(argInIndex, exprIn)
or
inModel.isInParameter(argInIndex) and
inModel.isParameter(argInIndex) and
exprIn = call.getArgument(argInIndex)
)
)

View File

@@ -18,7 +18,18 @@ abstract class Access extends Expr, NameQualifiableElement {
}
/**
* A C/C++ enum constant access expression.
* A C/C++ `enum` constant access expression. For example the access to
* `MYENUMCONST1` in `myFunction` in the following code:
* ```
* enum MyEnum {
* MYENUMCONST1,
* MYENUMCONST2
* };
*
* void myFunction() {
* MyEnum v = MYENUMCONST1;
* };
* ```
*/
class EnumConstantAccess extends Access, @varaccess {
override string getCanonicalQLClass() { result = "EnumConstantAccess" }
@@ -27,15 +38,23 @@ class EnumConstantAccess extends Access, @varaccess {
exists(EnumConstant c | varbind(underlyingElement(this), unresolveElement(c)))
}
/** Gets the accessed enum constant. */
/** Gets the accessed `enum` constant. */
override EnumConstant getTarget() { varbind(underlyingElement(this), unresolveElement(result)) }
/** Gets a textual representation of this enum constant access. */
/** Gets a textual representation of this `enum` constant access. */
override string toString() { result = this.getTarget().getName() }
}
/**
* A C/C++ variable access expression.
* A C/C++ variable access expression. For example the accesses to
* `x` and `y` in `myFunction` in the following code:
* ```
* int x;
*
* void myFunction(int y) {
* x = y;
* };
* ```
*/
class VariableAccess extends Access, @varaccess {
override string getCanonicalQLClass() { result = "VariableAccess" }
@@ -129,7 +148,18 @@ class VariableAccess extends Access, @varaccess {
}
/**
* A C/C++ field access expression.
* A C/C++ field access expression. For example the accesses to
* `x` and `y` in `myMethod` in the following code:
* ```
* class MyClass {
* public:
* void myMethod(MyClass &other) {
* x = other.y;
* }
*
* int x, y;
* };
* ```
*/
class FieldAccess extends VariableAccess {
override string getCanonicalQLClass() { result = "FieldAccess" }
@@ -141,8 +171,23 @@ class FieldAccess extends VariableAccess {
}
/**
* A field access of the form `obj->field`. The type of `obj` is a pointer,
* so this is equivalent to `(*obj).field`.
* A field access whose qualifier is a pointer to a class, struct or union.
* These typically take the form `obj->field`. Another case is a field access
* with an implicit `this->` qualifier, which is often a `PointerFieldAccess`
* (but see also `ImplicitThisFieldAccess`).
*
* For example the accesses to `x` and `y` in `myMethod` in the following code
* are each a `PointerFieldAccess`:
* ```
* class MyClass {
* public:
* void myMethod(MyClass *other) {
* other->x = y;
* }
*
* int x, y;
* };
* ```
*/
class PointerFieldAccess extends FieldAccess {
override string getCanonicalQLClass() { result = "PointerFieldAccess" }
@@ -169,7 +214,18 @@ class DotFieldAccess extends FieldAccess {
/**
* A field access of the form `obj.field`, where the type of `obj` is a
* reference to a class/struct/union.
* reference to a class/struct/union. For example the accesses to `y` in
* `myMethod` in the following code:
* ```
* class MyClass {
* public:
* void myMethod(MyClass a, MyClass &b) {
* a.x = b.y;
* }
*
* int x, y;
* };
* ```
*/
class ReferenceFieldAccess extends DotFieldAccess {
override string getCanonicalQLClass() { result = "ReferenceFieldAccess" }
@@ -179,7 +235,18 @@ class ReferenceFieldAccess extends DotFieldAccess {
/**
* A field access of the form `obj.field`, where the type of `obj` is a
* class/struct/union (and not a reference).
* class/struct/union (and not a reference). For example the accesses to `x`
* in `myMethod` in the following code:
* ```
* class MyClass {
* public:
* void myMethod(MyClass a, MyClass &b) {
* a.x = b.y;
* }
*
* int x, y;
* };
* ```
*/
class ValueFieldAccess extends DotFieldAccess {
override string getCanonicalQLClass() { result = "ValueFieldAccess" }
@@ -198,25 +265,40 @@ private predicate referenceConversion(Conversion c) {
/**
* Holds if `e` is a reference expression (that is, it has a type of the
* form `T&`), which is converted to a value. For example:
*
* ```
* int myfcn(MyStruct &x) {
* return x.field;
* }
* ```
*
* In this example, the type of `x` is `MyStruct&`, but it gets implicitly
* converted to `MyStruct` in the expression `x.field`.
*/
private predicate exprHasReferenceConversion(Expr e) { referenceConversion(e.getConversion+()) }
/**
* A field access of a field of `this`. The access has no qualifier because
* the use of `this` is implicit. For example, `field` is equivalent to
* `this->field` if `field` is a member of `this`.
* A field access of a field of `this` which has no qualifier because
* the use of `this` is implicit. For example, in the following code the
* implicit call to the destructor of `A` has no qualifier because the
* use of `this` is implicit:
* ```
* class A {
* public:
* ~A() {
* // ...
* }
* };
*
* class B {
* public:
* A a;
*
* ~B() {
* // Implicit call to the destructor of `A`.
* }
* };
* ```
* Note: the C++ front-end often automatically desugars `field` to
* `this->field`, so most implicit accesses of `this->field` are instances
* `this->field`, so most accesses of `this->field` are instances
* of `PointerFieldAccess` (with `ThisExpr` as the qualifier), not
* `ImplicitThisFieldAccess`.
*/
@@ -250,7 +332,15 @@ class PointerToFieldLiteral extends ImplicitThisFieldAccess {
}
/**
* A C/C++ function access expression.
* A C/C++ function access expression. For example the access to
* `myFunctionTarget` in `myFunction` in the following code:
* ```
* int myFunctionTarget(int);
*
* void myFunction() {
* int (*myFunctionPointer)(int) = &myTarget;
* }
* ```
*/
class FunctionAccess extends Access, @routineexpr {
FunctionAccess() { not iscall(underlyingElement(this), _) }
@@ -269,7 +359,7 @@ class FunctionAccess extends Access, @routineexpr {
}
/**
* An access to a parameter of a function signature for the purposes of a decltype.
* An access to a parameter of a function signature for the purposes of a `decltype`.
*
* For example, given the following code:
* ```
@@ -279,7 +369,7 @@ class FunctionAccess extends Access, @routineexpr {
* }
* ```
* The return type of the function is a decltype, the expression of which contains
* an add expression, which in turn has two ParamAccessForType children.
* an add expression, which in turn has two `ParamAccessForType` children.
*/
class ParamAccessForType extends Expr, @param_ref {
override string toString() { result = "param access" }
@@ -287,7 +377,22 @@ class ParamAccessForType extends Expr, @param_ref {
/**
* An access to a type. This occurs in certain contexts where a built-in
* works on types directly rather than variables, expressions etc.
* works on types directly rather than variables, expressions etc. For
* example the reference to `MyClass` in `__is_pod` in the following code:
* ```
* class MyClass {
* ...
* };
*
* void myFunction() {
* if (__is_pod(MyClass))
* {
* ...
* } else {
* ...
* }
* }
* ```
*/
class TypeName extends Expr, @type_operand {
override string getCanonicalQLClass() { result = "TypeName" }
@@ -296,9 +401,17 @@ class TypeName extends Expr, @type_operand {
}
/**
* A C/C++ array access expression.
* A C/C++ array access expression. For example, the access to `as` in
* `myFunction` in the following code:
* ```
* int as[10];
*
* For calls to operator[], which look syntactically identical, see OverloadedArrayExpr.
* void myFunction() {
* as[0]++;
* }
* ```
* For calls to `operator[]`, which look syntactically identical, see
* `OverloadedArrayExpr`.
*/
class ArrayExpr extends Expr, @subscriptexpr {
override string getCanonicalQLClass() { result = "ArrayExpr" }
@@ -306,14 +419,14 @@ class ArrayExpr extends Expr, @subscriptexpr {
/**
* Gets the array or pointer expression being subscripted.
*
* This is arr in both arr[0] and 0[arr].
* This is `arr` in both `arr[0]` and `0[arr]`.
*/
Expr getArrayBase() { result = this.getChild(0) }
/**
* Gets the expression giving the index into the array.
*
* This is 0 in both arr[0] and 0[arr].
* This is `0` in both `arr[0]` and `0[arr]`.
*/
Expr getArrayOffset() { result = this.getChild(1) }

View File

@@ -32,6 +32,8 @@ class UnaryPlusExpr extends UnaryArithmeticOperation, @unaryplusexpr {
*/
class ConjugationExpr extends UnaryArithmeticOperation, @conjugation {
override string getOperator() { result = "~" }
override string getCanonicalQLClass() { result = "ConjugationExpr" }
}
/**
@@ -142,6 +144,8 @@ class PostfixDecrExpr extends DecrementOperation, PostfixCrementOperation, @post
*/
class RealPartExpr extends UnaryArithmeticOperation, @realpartexpr {
override string getOperator() { result = "__real" }
override string getCanonicalQLClass() { result = "RealPartExpr" }
}
/**
@@ -149,6 +153,8 @@ class RealPartExpr extends UnaryArithmeticOperation, @realpartexpr {
*/
class ImaginaryPartExpr extends UnaryArithmeticOperation, @imagpartexpr {
override string getOperator() { result = "__imag" }
override string getCanonicalQLClass() { result = "ImaginaryPartExpr" }
}
/**
@@ -217,6 +223,8 @@ class RemExpr extends BinaryArithmeticOperation, @remexpr {
class ImaginaryMulExpr extends BinaryArithmeticOperation, @jmulexpr {
override string getOperator() { result = "*" }
override string getCanonicalQLClass() { result = "ImaginaryMulExpr" }
override int getPrecedence() { result = 13 }
}
@@ -226,6 +234,8 @@ class ImaginaryMulExpr extends BinaryArithmeticOperation, @jmulexpr {
class ImaginaryDivExpr extends BinaryArithmeticOperation, @jdivexpr {
override string getOperator() { result = "/" }
override string getCanonicalQLClass() { result = "ImaginaryDivExpr" }
override int getPrecedence() { result = 13 }
}
@@ -235,6 +245,8 @@ class ImaginaryDivExpr extends BinaryArithmeticOperation, @jdivexpr {
class RealImaginaryAddExpr extends BinaryArithmeticOperation, @fjaddexpr {
override string getOperator() { result = "+" }
override string getCanonicalQLClass() { result = "RealImaginaryAddExpr" }
override int getPrecedence() { result = 12 }
}
@@ -244,6 +256,8 @@ class RealImaginaryAddExpr extends BinaryArithmeticOperation, @fjaddexpr {
class ImaginaryRealAddExpr extends BinaryArithmeticOperation, @jfaddexpr {
override string getOperator() { result = "+" }
override string getCanonicalQLClass() { result = "ImaginaryRealAddExpr" }
override int getPrecedence() { result = 12 }
}
@@ -253,6 +267,8 @@ class ImaginaryRealAddExpr extends BinaryArithmeticOperation, @jfaddexpr {
class RealImaginarySubExpr extends BinaryArithmeticOperation, @fjsubexpr {
override string getOperator() { result = "-" }
override string getCanonicalQLClass() { result = "RealImaginarySubExpr" }
override int getPrecedence() { result = 12 }
}
@@ -262,6 +278,8 @@ class RealImaginarySubExpr extends BinaryArithmeticOperation, @fjsubexpr {
class ImaginaryRealSubExpr extends BinaryArithmeticOperation, @jfsubexpr {
override string getOperator() { result = "-" }
override string getCanonicalQLClass() { result = "ImaginaryRealSubExpr" }
override int getPrecedence() { result = 12 }
}
@@ -270,6 +288,8 @@ class ImaginaryRealSubExpr extends BinaryArithmeticOperation, @jfsubexpr {
*/
class MinExpr extends BinaryArithmeticOperation, @minexpr {
override string getOperator() { result = "<?" }
override string getCanonicalQLClass() { result = "MinExpr" }
}
/**
@@ -277,6 +297,8 @@ class MinExpr extends BinaryArithmeticOperation, @minexpr {
*/
class MaxExpr extends BinaryArithmeticOperation, @maxexpr {
override string getOperator() { result = ">?" }
override string getCanonicalQLClass() { result = "MaxExpr" }
}
/**

View File

@@ -519,3 +519,18 @@ class BuiltInChooseExpr extends BuiltInOperation, @builtinchooseexpr {
class VectorFillOperation extends UnaryOperation, @vec_fill {
override string getOperator() { result = "(vector fill)" }
}
/**
* The GNU `__builtin_complex` operation.
*/
class BuiltInComplexOperation extends BuiltInOperation, @builtincomplex {
override string toString() { result = "__builtin_complex" }
override string getCanonicalQLClass() { result = "BuiltInComplexOperation" }
/** Gets the operand corresponding to the real part of the complex number. */
Expr getRealOperand() { this.hasChild(result, 0) }
/** Gets the operand corresponding to the imaginary part of the complex number. */
Expr getImaginaryOperand() { this.hasChild(result, 1) }
}

View File

@@ -131,6 +131,8 @@ class Expr extends StmtParent, @expr {
valuebind(_, underlyingElement(this))
or
addressConstantExpression(this)
or
constantTemplateLiteral(this)
}
/**
@@ -1119,3 +1121,17 @@ private predicate isStandardPlacementNewAllocator(Function operatorNew) {
// Pulled out for performance. See QL-796.
private predicate hasNoConversions(Expr e) { not e.hasConversion() }
/**
* Holds if `e` is a literal of unknown value in a template, or a cast thereof.
* We assume that such literals are constant.
*/
private predicate constantTemplateLiteral(Expr e) {
// Unknown literals in uninstantiated templates could be enum constant
// accesses or pointer-to-member literals.
e instanceof Literal and
e.isFromUninstantiatedTemplate(_) and
not exists(e.getValue())
or
constantTemplateLiteral(e.(Cast).getExpr())
}

View File

@@ -132,7 +132,6 @@ class HexLiteral extends Literal {
* A C/C++ aggregate literal.
*/
class AggregateLiteral extends Expr, @aggregateliteral {
// if this is turned into a Literal we need to change mayBeImpure
override string getCanonicalQLClass() { result = "AggregateLiteral" }
/**
@@ -145,6 +144,10 @@ class AggregateLiteral extends Expr, @aggregateliteral {
result = this.(ClassAggregateLiteral).getFieldExpr(f)
}
override predicate mayBeImpure() { this.getAChild().mayBeImpure() }
override predicate mayBeGloballyImpure() { this.getAChild().mayBeGloballyImpure() }
/** Gets a textual representation of this aggregate literal. */
override string toString() { result = "{...}" }
}

View File

@@ -32,6 +32,11 @@ private predicate constantAddressLValue(Expr lvalue) {
// tells us how it's going to be used.
lvalue.(FunctionAccess).getType() instanceof RoutineType
or
// Pointer-to-member literals in uninstantiated templates
lvalue instanceof Literal and
not exists(lvalue.getValue()) and
lvalue.isFromUninstantiatedTemplate(_)
or
// String literals have array types and undergo array-to-pointer conversion.
lvalue instanceof StringLiteral
or
@@ -61,6 +66,10 @@ private predicate constantAddressPointer(Expr pointer) {
// tells us how it's going to be used.
pointer.(FunctionAccess).getType() instanceof FunctionPointerType
or
// Pointer to member function. These accesses are always pointers even though
// their type is `RoutineType`.
pointer.(FunctionAccess).getTarget() instanceof MemberFunction
or
addressConstantVariable(pointer.(VariableAccess).getTarget()) and
pointer.getType().getUnderlyingType() instanceof PointerType
or

View File

@@ -4,25 +4,17 @@ private import semmle.code.cpp.ir.dataflow.DataFlow
private import semmle.code.cpp.ir.IR
/**
* A predictable expression is one where an external user can predict
* A predictable instruction is one where an external user can predict
* the value. For example, a literal in the source code is considered
* predictable.
*/
// TODO: Change to use Instruction instead of Expr. Naive attempt breaks
// TaintedAllocationSize qltest.
private predicate predictable(Expr expr) {
expr instanceof Literal
or
exists(BinaryOperation binop | binop = expr |
predictable(binop.getLeftOperand()) and predictable(binop.getRightOperand())
)
or
exists(UnaryOperation unop | unop = expr | predictable(unop.getOperand()))
}
// TODO: remove when `predictable` has an `Instruction` parameter instead of `Expr`.
private predicate predictableInstruction(Instruction instr) {
predictable(DataFlow::instructionNode(instr).asExpr())
instr instanceof ConstantInstruction
or
instr instanceof StringConstantInstruction
or
// This could be a conversion on a string literal
predictableInstruction(instr.(UnaryInstruction).getUnary())
}
private class DefaultTaintTrackingCfg extends DataFlow::Configuration {

View File

@@ -7,7 +7,7 @@
* on each other without introducing mutual recursion among those configurations.
*/
private import DataFlowImplCommon
private import DataFlowImplCommon::Public
private import DataFlowImplSpecific::Private
import DataFlowImplSpecific::Public
@@ -905,30 +905,35 @@ private predicate localFlowExit(Node node, Configuration config) {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
Node node1, Node node2, boolean preservesValue, Configuration config
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
) {
localFlowEntry(node1, config) and
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowStep(node1, node2, config) and preservesValue = true
localFlowEntry(node1, config) and
(
localFlowStep(node1, node2, config) and preservesValue = true
or
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
nodeCand(node2, unbind(config))
or
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
) and
node1 != node2 and
nodeCand(node2, unbind(config))
or
exists(Node mid |
localFlowStepPlus(node1, mid, preservesValue, config) and
localFlowStep(mid, node2, config) and
not mid instanceof CastNode and
nodeCand(node2, unbind(config))
)
or
exists(Node mid |
localFlowStepPlus(node1, mid, _, config) and
additionalLocalFlowStep(mid, node2, config) and
not mid instanceof CastNode and
preservesValue = false and
nodeCand(node2, unbind(config))
exists(Node mid |
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
localFlowStep(mid, node2, config) and
not mid instanceof CastNode and
nodeCand(node2, unbind(config))
)
or
exists(Node mid |
localFlowStepPlus(node1, mid, _, config, cc) and
additionalLocalFlowStep(mid, node2, config) and
not mid instanceof CastNode and
preservesValue = false and
nodeCand(node2, unbind(config))
)
)
}
@@ -936,11 +941,11 @@ private predicate localFlowStepPlus(
* Holds if `node1` can step to `node2` in one or more local steps and this
* path can occur as a maximal subsequence of local steps in a dataflow path.
*/
pragma[noinline]
pragma[nomagic]
private predicate localFlowBigStep(
Node node1, Node node2, boolean preservesValue, Configuration config
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
) {
localFlowStepPlus(node1, node2, preservesValue, config) and
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
localFlowExit(node2, config)
}
@@ -1000,7 +1005,7 @@ private class AccessPathFrontNilNode extends Node {
(
any(Configuration c).isSource(this)
or
localFlowBigStep(_, this, false, _)
localFlowBigStep(_, this, false, _, _)
or
additionalJumpStep(_, this, _)
)
@@ -1023,12 +1028,12 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf,
(
exists(Node mid |
flowCandFwd(mid, fromArg, apf, config) and
localFlowBigStep(mid, node, true, config)
localFlowBigStep(mid, node, true, config, _)
)
or
exists(Node mid, AccessPathFrontNil nil |
flowCandFwd(mid, fromArg, nil, config) and
localFlowBigStep(mid, node, false, config) and
localFlowBigStep(mid, node, false, config, _) and
apf = node.(AccessPathFrontNilNode).getApf()
)
or
@@ -1075,6 +1080,7 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf,
flowCandFwd(mid, fromArg, _, config) and
store(mid, f, node) and
nodeCand(node, unbind(config)) and
readStoreCand(f, unbind(config)) and
apf.headUsesContent(f)
)
or
@@ -1121,13 +1127,13 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co
apf instanceof AccessPathFrontNil
or
exists(Node mid |
localFlowBigStep(node, mid, true, config) and
localFlowBigStep(node, mid, true, config, _) and
flowCand(mid, toReturn, apf, config)
)
or
exists(Node mid, AccessPathFrontNil nil |
flowCandFwd(node, _, apf, config) and
localFlowBigStep(node, mid, false, config) and
localFlowBigStep(node, mid, false, config, _) and
flowCand(mid, toReturn, nil, config) and
apf instanceof AccessPathFrontNil
)
@@ -1175,12 +1181,12 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co
exists(Content f, AccessPathFront apf0 |
flowCandStore(node, f, toReturn, apf0, config) and
apf0.headUsesContent(f) and
consCand(f, apf, unbind(config))
consCand(f, apf, config)
)
or
exists(Content f, AccessPathFront apf0 |
flowCandRead(node, f, toReturn, apf0, config) and
consCandFwd(f, apf0, unbind(config)) and
consCandFwd(f, apf0, config) and
apf.headUsesContent(f)
)
}
@@ -1221,8 +1227,8 @@ private newtype TAccessPath =
TConsCons(Content f1, Content f2, int len) { consCand(f1, TFrontHead(f2), _) and len in [2 .. 5] }
/**
* Conceptually a list of `Content`s followed by a `Type`, but only the first
* element of the list and its length are tracked. If data flows from a source to
* Conceptually a list of `Content`s followed by a `Type`, but only the first two
* elements of the list and its length are tracked. If data flows from a source to
* a given node with a given `AccessPath`, this indicates the sequence of
* dereference operations needed to get from the value in the node to the
* tracked object. The final type indicates the type of the tracked object.
@@ -1260,7 +1266,7 @@ abstract private class AccessPath extends TAccessPath {
private class AccessPathNil extends AccessPath, TNil {
override string toString() {
exists(DataFlowType t | this = TNil(t) | result = concat(" : " + ppReprType(t)))
exists(DataFlowType t | this = TNil(t) | result = concat(": " + ppReprType(t)))
}
override AccessPathFront getFront() {
@@ -1276,7 +1282,7 @@ private class AccessPathConsNil extends AccessPathCons, TConsNil {
override string toString() {
exists(Content f, DataFlowType t | this = TConsNil(f, t) |
// The `concat` becomes "" if `ppReprType` has no result.
result = f.toString() + concat(" : " + ppReprType(t))
result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t))
)
}
@@ -1293,8 +1299,8 @@ private class AccessPathConsCons extends AccessPathCons, TConsCons {
override string toString() {
exists(Content f1, Content f2, int len | this = TConsCons(f1, f2, len) |
if len = 2
then result = f1.toString() + ", " + f2.toString()
else result = f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")"
then result = "[" + f1.toString() + ", " + f2.toString() + "]"
else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]"
)
}
@@ -1362,12 +1368,12 @@ private predicate flowFwd0(
(
exists(Node mid |
flowFwd(mid, fromArg, apf, ap, config) and
localFlowBigStep(mid, node, true, config)
localFlowBigStep(mid, node, true, config, _)
)
or
exists(Node mid, AccessPathNil nil |
flowFwd(mid, fromArg, _, nil, config) and
localFlowBigStep(mid, node, false, config) and
localFlowBigStep(mid, node, false, config, _) and
ap = node.(AccessPathNilNode).getAp() and
apf = ap.(AccessPathNil).getFront()
)
@@ -1471,13 +1477,13 @@ private predicate flow0(Node node, boolean toReturn, AccessPath ap, Configuratio
ap instanceof AccessPathNil
or
exists(Node mid |
localFlowBigStep(node, mid, true, config) and
localFlowBigStep(node, mid, true, config, _) and
flow(mid, toReturn, ap, config)
)
or
exists(Node mid, AccessPathNil nil |
flowFwd(node, _, _, ap, config) and
localFlowBigStep(node, mid, false, config) and
localFlowBigStep(node, mid, false, config, _) and
flow(mid, toReturn, nil, config) and
ap instanceof AccessPathNil
)
@@ -1625,7 +1631,7 @@ abstract class PathNode extends TPathNode {
this instanceof PathNodeSink and result = ""
or
exists(string s | s = this.(PathNodeMid).getAp().toString() |
if s = "" then result = "" else result = " [" + s + "]"
if s = "" then result = "" else result = " " + s
)
}
@@ -1728,14 +1734,20 @@ private class PathNodeSink extends PathNode, TPathNodeSink {
* a callable is recorded by `cc`.
*/
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, AccessPath ap) {
localFlowBigStep(mid.getNode(), node, true, mid.getConfiguration()) and
cc = mid.getCallContext() and
ap = mid.getAp()
or
localFlowBigStep(mid.getNode(), node, false, mid.getConfiguration()) and
cc = mid.getCallContext() and
mid.getAp() instanceof AccessPathNil and
ap = node.(AccessPathNilNode).getAp()
exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf |
midnode = mid.getNode() and
conf = mid.getConfiguration() and
cc = mid.getCallContext() and
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
ap0 = mid.getAp()
|
localFlowBigStep(midnode, node, true, conf, localCC) and
ap = ap0
or
localFlowBigStep(midnode, node, false, conf, localCC) and
ap0 instanceof AccessPathNil and
ap = node.(AccessPathNilNode).getAp()
)
or
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
cc instanceof CallContextAny and
@@ -1879,7 +1891,7 @@ private predicate pathIntoCallable(
pathIntoCallable0(mid, callable, i, outercc, call, emptyAp) and
p.isParameterOf(callable, i)
|
if reducedViableImplInCallContext(_, callable, call)
if recordDataFlowCallSite(call, callable)
then innercc = TSpecificCall(call, i, emptyAp)
else innercc = TSomeCall(p, emptyAp)
)
@@ -2070,7 +2082,7 @@ private module FlowExploration {
private class PartialAccessPathNil extends PartialAccessPath, TPartialNil {
override string toString() {
exists(DataFlowType t | this = TPartialNil(t) | result = concat(" : " + ppReprType(t)))
exists(DataFlowType t | this = TPartialNil(t) | result = concat(": " + ppReprType(t)))
}
override AccessPathFront getFront() {
@@ -2082,8 +2094,8 @@ private module FlowExploration {
override string toString() {
exists(Content f, int len | this = TPartialCons(f, len) |
if len = 1
then result = f.toString()
else result = f.toString() + ", ... (" + len.toString() + ")"
then result = "[" + f.toString() + "]"
else result = "[" + f.toString() + ", ... (" + len.toString() + ")]"
)
}
@@ -2160,7 +2172,7 @@ private module FlowExploration {
private string ppAp() {
exists(string s | s = this.(PartialPathNodePriv).getAp().toString() |
if s = "" then result = "" else result = " [" + s + "]"
if s = "" then result = "" else result = " " + s
)
}
@@ -2204,16 +2216,19 @@ private module FlowExploration {
private predicate partialPathStep(
PartialPathNodePriv mid, Node node, CallContext cc, PartialAccessPath ap, Configuration config
) {
localFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
additionalLocalFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and
mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getErasedRepr(node.getType())) and
config = mid.getConfiguration()
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
(
localFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
additionalLocalFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and
mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getErasedRepr(node.getType())) and
config = mid.getConfiguration()
)
or
jumpStep(mid.getNode(), node, config) and
cc instanceof CallContextAny and
@@ -2377,7 +2392,7 @@ private module FlowExploration {
partialPathIntoCallable0(mid, callable, i, outercc, call, emptyAp, ap, config) and
p.isParameterOf(callable, i)
|
if reducedViableImplInCallContext(_, callable, call)
if recordDataFlowCallSite(call, callable)
then innercc = TSpecificCall(call, i, emptyAp)
else innercc = TSomeCall(p, emptyAp)
)

View File

@@ -7,7 +7,7 @@
* on each other without introducing mutual recursion among those configurations.
*/
private import DataFlowImplCommon
private import DataFlowImplCommon::Public
private import DataFlowImplSpecific::Private
import DataFlowImplSpecific::Public
@@ -905,30 +905,35 @@ private predicate localFlowExit(Node node, Configuration config) {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
Node node1, Node node2, boolean preservesValue, Configuration config
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
) {
localFlowEntry(node1, config) and
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowStep(node1, node2, config) and preservesValue = true
localFlowEntry(node1, config) and
(
localFlowStep(node1, node2, config) and preservesValue = true
or
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
nodeCand(node2, unbind(config))
or
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
) and
node1 != node2 and
nodeCand(node2, unbind(config))
or
exists(Node mid |
localFlowStepPlus(node1, mid, preservesValue, config) and
localFlowStep(mid, node2, config) and
not mid instanceof CastNode and
nodeCand(node2, unbind(config))
)
or
exists(Node mid |
localFlowStepPlus(node1, mid, _, config) and
additionalLocalFlowStep(mid, node2, config) and
not mid instanceof CastNode and
preservesValue = false and
nodeCand(node2, unbind(config))
exists(Node mid |
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
localFlowStep(mid, node2, config) and
not mid instanceof CastNode and
nodeCand(node2, unbind(config))
)
or
exists(Node mid |
localFlowStepPlus(node1, mid, _, config, cc) and
additionalLocalFlowStep(mid, node2, config) and
not mid instanceof CastNode and
preservesValue = false and
nodeCand(node2, unbind(config))
)
)
}
@@ -936,11 +941,11 @@ private predicate localFlowStepPlus(
* Holds if `node1` can step to `node2` in one or more local steps and this
* path can occur as a maximal subsequence of local steps in a dataflow path.
*/
pragma[noinline]
pragma[nomagic]
private predicate localFlowBigStep(
Node node1, Node node2, boolean preservesValue, Configuration config
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
) {
localFlowStepPlus(node1, node2, preservesValue, config) and
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
localFlowExit(node2, config)
}
@@ -1000,7 +1005,7 @@ private class AccessPathFrontNilNode extends Node {
(
any(Configuration c).isSource(this)
or
localFlowBigStep(_, this, false, _)
localFlowBigStep(_, this, false, _, _)
or
additionalJumpStep(_, this, _)
)
@@ -1023,12 +1028,12 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf,
(
exists(Node mid |
flowCandFwd(mid, fromArg, apf, config) and
localFlowBigStep(mid, node, true, config)
localFlowBigStep(mid, node, true, config, _)
)
or
exists(Node mid, AccessPathFrontNil nil |
flowCandFwd(mid, fromArg, nil, config) and
localFlowBigStep(mid, node, false, config) and
localFlowBigStep(mid, node, false, config, _) and
apf = node.(AccessPathFrontNilNode).getApf()
)
or
@@ -1075,6 +1080,7 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf,
flowCandFwd(mid, fromArg, _, config) and
store(mid, f, node) and
nodeCand(node, unbind(config)) and
readStoreCand(f, unbind(config)) and
apf.headUsesContent(f)
)
or
@@ -1121,13 +1127,13 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co
apf instanceof AccessPathFrontNil
or
exists(Node mid |
localFlowBigStep(node, mid, true, config) and
localFlowBigStep(node, mid, true, config, _) and
flowCand(mid, toReturn, apf, config)
)
or
exists(Node mid, AccessPathFrontNil nil |
flowCandFwd(node, _, apf, config) and
localFlowBigStep(node, mid, false, config) and
localFlowBigStep(node, mid, false, config, _) and
flowCand(mid, toReturn, nil, config) and
apf instanceof AccessPathFrontNil
)
@@ -1175,12 +1181,12 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co
exists(Content f, AccessPathFront apf0 |
flowCandStore(node, f, toReturn, apf0, config) and
apf0.headUsesContent(f) and
consCand(f, apf, unbind(config))
consCand(f, apf, config)
)
or
exists(Content f, AccessPathFront apf0 |
flowCandRead(node, f, toReturn, apf0, config) and
consCandFwd(f, apf0, unbind(config)) and
consCandFwd(f, apf0, config) and
apf.headUsesContent(f)
)
}
@@ -1221,8 +1227,8 @@ private newtype TAccessPath =
TConsCons(Content f1, Content f2, int len) { consCand(f1, TFrontHead(f2), _) and len in [2 .. 5] }
/**
* Conceptually a list of `Content`s followed by a `Type`, but only the first
* element of the list and its length are tracked. If data flows from a source to
* Conceptually a list of `Content`s followed by a `Type`, but only the first two
* elements of the list and its length are tracked. If data flows from a source to
* a given node with a given `AccessPath`, this indicates the sequence of
* dereference operations needed to get from the value in the node to the
* tracked object. The final type indicates the type of the tracked object.
@@ -1260,7 +1266,7 @@ abstract private class AccessPath extends TAccessPath {
private class AccessPathNil extends AccessPath, TNil {
override string toString() {
exists(DataFlowType t | this = TNil(t) | result = concat(" : " + ppReprType(t)))
exists(DataFlowType t | this = TNil(t) | result = concat(": " + ppReprType(t)))
}
override AccessPathFront getFront() {
@@ -1276,7 +1282,7 @@ private class AccessPathConsNil extends AccessPathCons, TConsNil {
override string toString() {
exists(Content f, DataFlowType t | this = TConsNil(f, t) |
// The `concat` becomes "" if `ppReprType` has no result.
result = f.toString() + concat(" : " + ppReprType(t))
result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t))
)
}
@@ -1293,8 +1299,8 @@ private class AccessPathConsCons extends AccessPathCons, TConsCons {
override string toString() {
exists(Content f1, Content f2, int len | this = TConsCons(f1, f2, len) |
if len = 2
then result = f1.toString() + ", " + f2.toString()
else result = f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")"
then result = "[" + f1.toString() + ", " + f2.toString() + "]"
else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]"
)
}
@@ -1362,12 +1368,12 @@ private predicate flowFwd0(
(
exists(Node mid |
flowFwd(mid, fromArg, apf, ap, config) and
localFlowBigStep(mid, node, true, config)
localFlowBigStep(mid, node, true, config, _)
)
or
exists(Node mid, AccessPathNil nil |
flowFwd(mid, fromArg, _, nil, config) and
localFlowBigStep(mid, node, false, config) and
localFlowBigStep(mid, node, false, config, _) and
ap = node.(AccessPathNilNode).getAp() and
apf = ap.(AccessPathNil).getFront()
)
@@ -1471,13 +1477,13 @@ private predicate flow0(Node node, boolean toReturn, AccessPath ap, Configuratio
ap instanceof AccessPathNil
or
exists(Node mid |
localFlowBigStep(node, mid, true, config) and
localFlowBigStep(node, mid, true, config, _) and
flow(mid, toReturn, ap, config)
)
or
exists(Node mid, AccessPathNil nil |
flowFwd(node, _, _, ap, config) and
localFlowBigStep(node, mid, false, config) and
localFlowBigStep(node, mid, false, config, _) and
flow(mid, toReturn, nil, config) and
ap instanceof AccessPathNil
)
@@ -1625,7 +1631,7 @@ abstract class PathNode extends TPathNode {
this instanceof PathNodeSink and result = ""
or
exists(string s | s = this.(PathNodeMid).getAp().toString() |
if s = "" then result = "" else result = " [" + s + "]"
if s = "" then result = "" else result = " " + s
)
}
@@ -1728,14 +1734,20 @@ private class PathNodeSink extends PathNode, TPathNodeSink {
* a callable is recorded by `cc`.
*/
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, AccessPath ap) {
localFlowBigStep(mid.getNode(), node, true, mid.getConfiguration()) and
cc = mid.getCallContext() and
ap = mid.getAp()
or
localFlowBigStep(mid.getNode(), node, false, mid.getConfiguration()) and
cc = mid.getCallContext() and
mid.getAp() instanceof AccessPathNil and
ap = node.(AccessPathNilNode).getAp()
exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf |
midnode = mid.getNode() and
conf = mid.getConfiguration() and
cc = mid.getCallContext() and
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
ap0 = mid.getAp()
|
localFlowBigStep(midnode, node, true, conf, localCC) and
ap = ap0
or
localFlowBigStep(midnode, node, false, conf, localCC) and
ap0 instanceof AccessPathNil and
ap = node.(AccessPathNilNode).getAp()
)
or
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
cc instanceof CallContextAny and
@@ -1879,7 +1891,7 @@ private predicate pathIntoCallable(
pathIntoCallable0(mid, callable, i, outercc, call, emptyAp) and
p.isParameterOf(callable, i)
|
if reducedViableImplInCallContext(_, callable, call)
if recordDataFlowCallSite(call, callable)
then innercc = TSpecificCall(call, i, emptyAp)
else innercc = TSomeCall(p, emptyAp)
)
@@ -2070,7 +2082,7 @@ private module FlowExploration {
private class PartialAccessPathNil extends PartialAccessPath, TPartialNil {
override string toString() {
exists(DataFlowType t | this = TPartialNil(t) | result = concat(" : " + ppReprType(t)))
exists(DataFlowType t | this = TPartialNil(t) | result = concat(": " + ppReprType(t)))
}
override AccessPathFront getFront() {
@@ -2082,8 +2094,8 @@ private module FlowExploration {
override string toString() {
exists(Content f, int len | this = TPartialCons(f, len) |
if len = 1
then result = f.toString()
else result = f.toString() + ", ... (" + len.toString() + ")"
then result = "[" + f.toString() + "]"
else result = "[" + f.toString() + ", ... (" + len.toString() + ")]"
)
}
@@ -2160,7 +2172,7 @@ private module FlowExploration {
private string ppAp() {
exists(string s | s = this.(PartialPathNodePriv).getAp().toString() |
if s = "" then result = "" else result = " [" + s + "]"
if s = "" then result = "" else result = " " + s
)
}
@@ -2204,16 +2216,19 @@ private module FlowExploration {
private predicate partialPathStep(
PartialPathNodePriv mid, Node node, CallContext cc, PartialAccessPath ap, Configuration config
) {
localFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
additionalLocalFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and
mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getErasedRepr(node.getType())) and
config = mid.getConfiguration()
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
(
localFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
additionalLocalFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and
mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getErasedRepr(node.getType())) and
config = mid.getConfiguration()
)
or
jumpStep(mid.getNode(), node, config) and
cc instanceof CallContextAny and
@@ -2377,7 +2392,7 @@ private module FlowExploration {
partialPathIntoCallable0(mid, callable, i, outercc, call, emptyAp, ap, config) and
p.isParameterOf(callable, i)
|
if reducedViableImplInCallContext(_, callable, call)
if recordDataFlowCallSite(call, callable)
then innercc = TSpecificCall(call, i, emptyAp)
else innercc = TSomeCall(p, emptyAp)
)

View File

@@ -7,7 +7,7 @@
* on each other without introducing mutual recursion among those configurations.
*/
private import DataFlowImplCommon
private import DataFlowImplCommon::Public
private import DataFlowImplSpecific::Private
import DataFlowImplSpecific::Public
@@ -905,30 +905,35 @@ private predicate localFlowExit(Node node, Configuration config) {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
Node node1, Node node2, boolean preservesValue, Configuration config
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
) {
localFlowEntry(node1, config) and
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowStep(node1, node2, config) and preservesValue = true
localFlowEntry(node1, config) and
(
localFlowStep(node1, node2, config) and preservesValue = true
or
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
nodeCand(node2, unbind(config))
or
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
) and
node1 != node2 and
nodeCand(node2, unbind(config))
or
exists(Node mid |
localFlowStepPlus(node1, mid, preservesValue, config) and
localFlowStep(mid, node2, config) and
not mid instanceof CastNode and
nodeCand(node2, unbind(config))
)
or
exists(Node mid |
localFlowStepPlus(node1, mid, _, config) and
additionalLocalFlowStep(mid, node2, config) and
not mid instanceof CastNode and
preservesValue = false and
nodeCand(node2, unbind(config))
exists(Node mid |
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
localFlowStep(mid, node2, config) and
not mid instanceof CastNode and
nodeCand(node2, unbind(config))
)
or
exists(Node mid |
localFlowStepPlus(node1, mid, _, config, cc) and
additionalLocalFlowStep(mid, node2, config) and
not mid instanceof CastNode and
preservesValue = false and
nodeCand(node2, unbind(config))
)
)
}
@@ -936,11 +941,11 @@ private predicate localFlowStepPlus(
* Holds if `node1` can step to `node2` in one or more local steps and this
* path can occur as a maximal subsequence of local steps in a dataflow path.
*/
pragma[noinline]
pragma[nomagic]
private predicate localFlowBigStep(
Node node1, Node node2, boolean preservesValue, Configuration config
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
) {
localFlowStepPlus(node1, node2, preservesValue, config) and
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
localFlowExit(node2, config)
}
@@ -1000,7 +1005,7 @@ private class AccessPathFrontNilNode extends Node {
(
any(Configuration c).isSource(this)
or
localFlowBigStep(_, this, false, _)
localFlowBigStep(_, this, false, _, _)
or
additionalJumpStep(_, this, _)
)
@@ -1023,12 +1028,12 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf,
(
exists(Node mid |
flowCandFwd(mid, fromArg, apf, config) and
localFlowBigStep(mid, node, true, config)
localFlowBigStep(mid, node, true, config, _)
)
or
exists(Node mid, AccessPathFrontNil nil |
flowCandFwd(mid, fromArg, nil, config) and
localFlowBigStep(mid, node, false, config) and
localFlowBigStep(mid, node, false, config, _) and
apf = node.(AccessPathFrontNilNode).getApf()
)
or
@@ -1075,6 +1080,7 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf,
flowCandFwd(mid, fromArg, _, config) and
store(mid, f, node) and
nodeCand(node, unbind(config)) and
readStoreCand(f, unbind(config)) and
apf.headUsesContent(f)
)
or
@@ -1121,13 +1127,13 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co
apf instanceof AccessPathFrontNil
or
exists(Node mid |
localFlowBigStep(node, mid, true, config) and
localFlowBigStep(node, mid, true, config, _) and
flowCand(mid, toReturn, apf, config)
)
or
exists(Node mid, AccessPathFrontNil nil |
flowCandFwd(node, _, apf, config) and
localFlowBigStep(node, mid, false, config) and
localFlowBigStep(node, mid, false, config, _) and
flowCand(mid, toReturn, nil, config) and
apf instanceof AccessPathFrontNil
)
@@ -1175,12 +1181,12 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co
exists(Content f, AccessPathFront apf0 |
flowCandStore(node, f, toReturn, apf0, config) and
apf0.headUsesContent(f) and
consCand(f, apf, unbind(config))
consCand(f, apf, config)
)
or
exists(Content f, AccessPathFront apf0 |
flowCandRead(node, f, toReturn, apf0, config) and
consCandFwd(f, apf0, unbind(config)) and
consCandFwd(f, apf0, config) and
apf.headUsesContent(f)
)
}
@@ -1221,8 +1227,8 @@ private newtype TAccessPath =
TConsCons(Content f1, Content f2, int len) { consCand(f1, TFrontHead(f2), _) and len in [2 .. 5] }
/**
* Conceptually a list of `Content`s followed by a `Type`, but only the first
* element of the list and its length are tracked. If data flows from a source to
* Conceptually a list of `Content`s followed by a `Type`, but only the first two
* elements of the list and its length are tracked. If data flows from a source to
* a given node with a given `AccessPath`, this indicates the sequence of
* dereference operations needed to get from the value in the node to the
* tracked object. The final type indicates the type of the tracked object.
@@ -1260,7 +1266,7 @@ abstract private class AccessPath extends TAccessPath {
private class AccessPathNil extends AccessPath, TNil {
override string toString() {
exists(DataFlowType t | this = TNil(t) | result = concat(" : " + ppReprType(t)))
exists(DataFlowType t | this = TNil(t) | result = concat(": " + ppReprType(t)))
}
override AccessPathFront getFront() {
@@ -1276,7 +1282,7 @@ private class AccessPathConsNil extends AccessPathCons, TConsNil {
override string toString() {
exists(Content f, DataFlowType t | this = TConsNil(f, t) |
// The `concat` becomes "" if `ppReprType` has no result.
result = f.toString() + concat(" : " + ppReprType(t))
result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t))
)
}
@@ -1293,8 +1299,8 @@ private class AccessPathConsCons extends AccessPathCons, TConsCons {
override string toString() {
exists(Content f1, Content f2, int len | this = TConsCons(f1, f2, len) |
if len = 2
then result = f1.toString() + ", " + f2.toString()
else result = f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")"
then result = "[" + f1.toString() + ", " + f2.toString() + "]"
else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]"
)
}
@@ -1362,12 +1368,12 @@ private predicate flowFwd0(
(
exists(Node mid |
flowFwd(mid, fromArg, apf, ap, config) and
localFlowBigStep(mid, node, true, config)
localFlowBigStep(mid, node, true, config, _)
)
or
exists(Node mid, AccessPathNil nil |
flowFwd(mid, fromArg, _, nil, config) and
localFlowBigStep(mid, node, false, config) and
localFlowBigStep(mid, node, false, config, _) and
ap = node.(AccessPathNilNode).getAp() and
apf = ap.(AccessPathNil).getFront()
)
@@ -1471,13 +1477,13 @@ private predicate flow0(Node node, boolean toReturn, AccessPath ap, Configuratio
ap instanceof AccessPathNil
or
exists(Node mid |
localFlowBigStep(node, mid, true, config) and
localFlowBigStep(node, mid, true, config, _) and
flow(mid, toReturn, ap, config)
)
or
exists(Node mid, AccessPathNil nil |
flowFwd(node, _, _, ap, config) and
localFlowBigStep(node, mid, false, config) and
localFlowBigStep(node, mid, false, config, _) and
flow(mid, toReturn, nil, config) and
ap instanceof AccessPathNil
)
@@ -1625,7 +1631,7 @@ abstract class PathNode extends TPathNode {
this instanceof PathNodeSink and result = ""
or
exists(string s | s = this.(PathNodeMid).getAp().toString() |
if s = "" then result = "" else result = " [" + s + "]"
if s = "" then result = "" else result = " " + s
)
}
@@ -1728,14 +1734,20 @@ private class PathNodeSink extends PathNode, TPathNodeSink {
* a callable is recorded by `cc`.
*/
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, AccessPath ap) {
localFlowBigStep(mid.getNode(), node, true, mid.getConfiguration()) and
cc = mid.getCallContext() and
ap = mid.getAp()
or
localFlowBigStep(mid.getNode(), node, false, mid.getConfiguration()) and
cc = mid.getCallContext() and
mid.getAp() instanceof AccessPathNil and
ap = node.(AccessPathNilNode).getAp()
exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf |
midnode = mid.getNode() and
conf = mid.getConfiguration() and
cc = mid.getCallContext() and
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
ap0 = mid.getAp()
|
localFlowBigStep(midnode, node, true, conf, localCC) and
ap = ap0
or
localFlowBigStep(midnode, node, false, conf, localCC) and
ap0 instanceof AccessPathNil and
ap = node.(AccessPathNilNode).getAp()
)
or
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
cc instanceof CallContextAny and
@@ -1879,7 +1891,7 @@ private predicate pathIntoCallable(
pathIntoCallable0(mid, callable, i, outercc, call, emptyAp) and
p.isParameterOf(callable, i)
|
if reducedViableImplInCallContext(_, callable, call)
if recordDataFlowCallSite(call, callable)
then innercc = TSpecificCall(call, i, emptyAp)
else innercc = TSomeCall(p, emptyAp)
)
@@ -2070,7 +2082,7 @@ private module FlowExploration {
private class PartialAccessPathNil extends PartialAccessPath, TPartialNil {
override string toString() {
exists(DataFlowType t | this = TPartialNil(t) | result = concat(" : " + ppReprType(t)))
exists(DataFlowType t | this = TPartialNil(t) | result = concat(": " + ppReprType(t)))
}
override AccessPathFront getFront() {
@@ -2082,8 +2094,8 @@ private module FlowExploration {
override string toString() {
exists(Content f, int len | this = TPartialCons(f, len) |
if len = 1
then result = f.toString()
else result = f.toString() + ", ... (" + len.toString() + ")"
then result = "[" + f.toString() + "]"
else result = "[" + f.toString() + ", ... (" + len.toString() + ")]"
)
}
@@ -2160,7 +2172,7 @@ private module FlowExploration {
private string ppAp() {
exists(string s | s = this.(PartialPathNodePriv).getAp().toString() |
if s = "" then result = "" else result = " [" + s + "]"
if s = "" then result = "" else result = " " + s
)
}
@@ -2204,16 +2216,19 @@ private module FlowExploration {
private predicate partialPathStep(
PartialPathNodePriv mid, Node node, CallContext cc, PartialAccessPath ap, Configuration config
) {
localFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
additionalLocalFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and
mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getErasedRepr(node.getType())) and
config = mid.getConfiguration()
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
(
localFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
additionalLocalFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and
mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getErasedRepr(node.getType())) and
config = mid.getConfiguration()
)
or
jumpStep(mid.getNode(), node, config) and
cc instanceof CallContextAny and
@@ -2377,7 +2392,7 @@ private module FlowExploration {
partialPathIntoCallable0(mid, callable, i, outercc, call, emptyAp, ap, config) and
p.isParameterOf(callable, i)
|
if reducedViableImplInCallContext(_, callable, call)
if recordDataFlowCallSite(call, callable)
then innercc = TSpecificCall(call, i, emptyAp)
else innercc = TSomeCall(p, emptyAp)
)

View File

@@ -7,7 +7,7 @@
* on each other without introducing mutual recursion among those configurations.
*/
private import DataFlowImplCommon
private import DataFlowImplCommon::Public
private import DataFlowImplSpecific::Private
import DataFlowImplSpecific::Public
@@ -905,30 +905,35 @@ private predicate localFlowExit(Node node, Configuration config) {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
Node node1, Node node2, boolean preservesValue, Configuration config
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext cc
) {
localFlowEntry(node1, config) and
not isUnreachableInCall(node2, cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowStep(node1, node2, config) and preservesValue = true
localFlowEntry(node1, config) and
(
localFlowStep(node1, node2, config) and preservesValue = true
or
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
not isUnreachableInCall(node1, cc.(LocalCallContextSpecificCall).getCall()) and
nodeCand(node2, unbind(config))
or
additionalLocalFlowStep(node1, node2, config) and preservesValue = false
) and
node1 != node2 and
nodeCand(node2, unbind(config))
or
exists(Node mid |
localFlowStepPlus(node1, mid, preservesValue, config) and
localFlowStep(mid, node2, config) and
not mid instanceof CastNode and
nodeCand(node2, unbind(config))
)
or
exists(Node mid |
localFlowStepPlus(node1, mid, _, config) and
additionalLocalFlowStep(mid, node2, config) and
not mid instanceof CastNode and
preservesValue = false and
nodeCand(node2, unbind(config))
exists(Node mid |
localFlowStepPlus(node1, mid, preservesValue, config, cc) and
localFlowStep(mid, node2, config) and
not mid instanceof CastNode and
nodeCand(node2, unbind(config))
)
or
exists(Node mid |
localFlowStepPlus(node1, mid, _, config, cc) and
additionalLocalFlowStep(mid, node2, config) and
not mid instanceof CastNode and
preservesValue = false and
nodeCand(node2, unbind(config))
)
)
}
@@ -936,11 +941,11 @@ private predicate localFlowStepPlus(
* Holds if `node1` can step to `node2` in one or more local steps and this
* path can occur as a maximal subsequence of local steps in a dataflow path.
*/
pragma[noinline]
pragma[nomagic]
private predicate localFlowBigStep(
Node node1, Node node2, boolean preservesValue, Configuration config
Node node1, Node node2, boolean preservesValue, Configuration config, LocalCallContext callContext
) {
localFlowStepPlus(node1, node2, preservesValue, config) and
localFlowStepPlus(node1, node2, preservesValue, config, callContext) and
localFlowExit(node2, config)
}
@@ -1000,7 +1005,7 @@ private class AccessPathFrontNilNode extends Node {
(
any(Configuration c).isSource(this)
or
localFlowBigStep(_, this, false, _)
localFlowBigStep(_, this, false, _, _)
or
additionalJumpStep(_, this, _)
)
@@ -1023,12 +1028,12 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf,
(
exists(Node mid |
flowCandFwd(mid, fromArg, apf, config) and
localFlowBigStep(mid, node, true, config)
localFlowBigStep(mid, node, true, config, _)
)
or
exists(Node mid, AccessPathFrontNil nil |
flowCandFwd(mid, fromArg, nil, config) and
localFlowBigStep(mid, node, false, config) and
localFlowBigStep(mid, node, false, config, _) and
apf = node.(AccessPathFrontNilNode).getApf()
)
or
@@ -1075,6 +1080,7 @@ private predicate flowCandFwd0(Node node, boolean fromArg, AccessPathFront apf,
flowCandFwd(mid, fromArg, _, config) and
store(mid, f, node) and
nodeCand(node, unbind(config)) and
readStoreCand(f, unbind(config)) and
apf.headUsesContent(f)
)
or
@@ -1121,13 +1127,13 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co
apf instanceof AccessPathFrontNil
or
exists(Node mid |
localFlowBigStep(node, mid, true, config) and
localFlowBigStep(node, mid, true, config, _) and
flowCand(mid, toReturn, apf, config)
)
or
exists(Node mid, AccessPathFrontNil nil |
flowCandFwd(node, _, apf, config) and
localFlowBigStep(node, mid, false, config) and
localFlowBigStep(node, mid, false, config, _) and
flowCand(mid, toReturn, nil, config) and
apf instanceof AccessPathFrontNil
)
@@ -1175,12 +1181,12 @@ private predicate flowCand0(Node node, boolean toReturn, AccessPathFront apf, Co
exists(Content f, AccessPathFront apf0 |
flowCandStore(node, f, toReturn, apf0, config) and
apf0.headUsesContent(f) and
consCand(f, apf, unbind(config))
consCand(f, apf, config)
)
or
exists(Content f, AccessPathFront apf0 |
flowCandRead(node, f, toReturn, apf0, config) and
consCandFwd(f, apf0, unbind(config)) and
consCandFwd(f, apf0, config) and
apf.headUsesContent(f)
)
}
@@ -1221,8 +1227,8 @@ private newtype TAccessPath =
TConsCons(Content f1, Content f2, int len) { consCand(f1, TFrontHead(f2), _) and len in [2 .. 5] }
/**
* Conceptually a list of `Content`s followed by a `Type`, but only the first
* element of the list and its length are tracked. If data flows from a source to
* Conceptually a list of `Content`s followed by a `Type`, but only the first two
* elements of the list and its length are tracked. If data flows from a source to
* a given node with a given `AccessPath`, this indicates the sequence of
* dereference operations needed to get from the value in the node to the
* tracked object. The final type indicates the type of the tracked object.
@@ -1260,7 +1266,7 @@ abstract private class AccessPath extends TAccessPath {
private class AccessPathNil extends AccessPath, TNil {
override string toString() {
exists(DataFlowType t | this = TNil(t) | result = concat(" : " + ppReprType(t)))
exists(DataFlowType t | this = TNil(t) | result = concat(": " + ppReprType(t)))
}
override AccessPathFront getFront() {
@@ -1276,7 +1282,7 @@ private class AccessPathConsNil extends AccessPathCons, TConsNil {
override string toString() {
exists(Content f, DataFlowType t | this = TConsNil(f, t) |
// The `concat` becomes "" if `ppReprType` has no result.
result = f.toString() + concat(" : " + ppReprType(t))
result = "[" + f.toString() + "]" + concat(" : " + ppReprType(t))
)
}
@@ -1293,8 +1299,8 @@ private class AccessPathConsCons extends AccessPathCons, TConsCons {
override string toString() {
exists(Content f1, Content f2, int len | this = TConsCons(f1, f2, len) |
if len = 2
then result = f1.toString() + ", " + f2.toString()
else result = f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")"
then result = "[" + f1.toString() + ", " + f2.toString() + "]"
else result = "[" + f1.toString() + ", " + f2.toString() + ", ... (" + len.toString() + ")]"
)
}
@@ -1362,12 +1368,12 @@ private predicate flowFwd0(
(
exists(Node mid |
flowFwd(mid, fromArg, apf, ap, config) and
localFlowBigStep(mid, node, true, config)
localFlowBigStep(mid, node, true, config, _)
)
or
exists(Node mid, AccessPathNil nil |
flowFwd(mid, fromArg, _, nil, config) and
localFlowBigStep(mid, node, false, config) and
localFlowBigStep(mid, node, false, config, _) and
ap = node.(AccessPathNilNode).getAp() and
apf = ap.(AccessPathNil).getFront()
)
@@ -1471,13 +1477,13 @@ private predicate flow0(Node node, boolean toReturn, AccessPath ap, Configuratio
ap instanceof AccessPathNil
or
exists(Node mid |
localFlowBigStep(node, mid, true, config) and
localFlowBigStep(node, mid, true, config, _) and
flow(mid, toReturn, ap, config)
)
or
exists(Node mid, AccessPathNil nil |
flowFwd(node, _, _, ap, config) and
localFlowBigStep(node, mid, false, config) and
localFlowBigStep(node, mid, false, config, _) and
flow(mid, toReturn, nil, config) and
ap instanceof AccessPathNil
)
@@ -1625,7 +1631,7 @@ abstract class PathNode extends TPathNode {
this instanceof PathNodeSink and result = ""
or
exists(string s | s = this.(PathNodeMid).getAp().toString() |
if s = "" then result = "" else result = " [" + s + "]"
if s = "" then result = "" else result = " " + s
)
}
@@ -1728,14 +1734,20 @@ private class PathNodeSink extends PathNode, TPathNodeSink {
* a callable is recorded by `cc`.
*/
private predicate pathStep(PathNodeMid mid, Node node, CallContext cc, AccessPath ap) {
localFlowBigStep(mid.getNode(), node, true, mid.getConfiguration()) and
cc = mid.getCallContext() and
ap = mid.getAp()
or
localFlowBigStep(mid.getNode(), node, false, mid.getConfiguration()) and
cc = mid.getCallContext() and
mid.getAp() instanceof AccessPathNil and
ap = node.(AccessPathNilNode).getAp()
exists(LocalCallContext localCC, AccessPath ap0, Node midnode, Configuration conf |
midnode = mid.getNode() and
conf = mid.getConfiguration() and
cc = mid.getCallContext() and
localCC = getLocalCallContext(cc, midnode.getEnclosingCallable()) and
ap0 = mid.getAp()
|
localFlowBigStep(midnode, node, true, conf, localCC) and
ap = ap0
or
localFlowBigStep(midnode, node, false, conf, localCC) and
ap0 instanceof AccessPathNil and
ap = node.(AccessPathNilNode).getAp()
)
or
jumpStep(mid.getNode(), node, mid.getConfiguration()) and
cc instanceof CallContextAny and
@@ -1879,7 +1891,7 @@ private predicate pathIntoCallable(
pathIntoCallable0(mid, callable, i, outercc, call, emptyAp) and
p.isParameterOf(callable, i)
|
if reducedViableImplInCallContext(_, callable, call)
if recordDataFlowCallSite(call, callable)
then innercc = TSpecificCall(call, i, emptyAp)
else innercc = TSomeCall(p, emptyAp)
)
@@ -2070,7 +2082,7 @@ private module FlowExploration {
private class PartialAccessPathNil extends PartialAccessPath, TPartialNil {
override string toString() {
exists(DataFlowType t | this = TPartialNil(t) | result = concat(" : " + ppReprType(t)))
exists(DataFlowType t | this = TPartialNil(t) | result = concat(": " + ppReprType(t)))
}
override AccessPathFront getFront() {
@@ -2082,8 +2094,8 @@ private module FlowExploration {
override string toString() {
exists(Content f, int len | this = TPartialCons(f, len) |
if len = 1
then result = f.toString()
else result = f.toString() + ", ... (" + len.toString() + ")"
then result = "[" + f.toString() + "]"
else result = "[" + f.toString() + ", ... (" + len.toString() + ")]"
)
}
@@ -2160,7 +2172,7 @@ private module FlowExploration {
private string ppAp() {
exists(string s | s = this.(PartialPathNodePriv).getAp().toString() |
if s = "" then result = "" else result = " [" + s + "]"
if s = "" then result = "" else result = " " + s
)
}
@@ -2204,16 +2216,19 @@ private module FlowExploration {
private predicate partialPathStep(
PartialPathNodePriv mid, Node node, CallContext cc, PartialAccessPath ap, Configuration config
) {
localFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
additionalLocalFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and
mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getErasedRepr(node.getType())) and
config = mid.getConfiguration()
not isUnreachableInCall(node, cc.(CallContextSpecificCall).getCall()) and
(
localFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and
ap = mid.getAp() and
config = mid.getConfiguration()
or
additionalLocalFlowStep(mid.getNode(), node, config) and
cc = mid.getCallContext() and
mid.getAp() instanceof PartialAccessPathNil and
ap = TPartialNil(getErasedRepr(node.getType())) and
config = mid.getConfiguration()
)
or
jumpStep(mid.getNode(), node, config) and
cc instanceof CallContextAny and
@@ -2377,7 +2392,7 @@ private module FlowExploration {
partialPathIntoCallable0(mid, callable, i, outercc, call, emptyAp, ap, config) and
p.isParameterOf(callable, i)
|
if reducedViableImplInCallContext(_, callable, call)
if recordDataFlowCallSite(call, callable)
then innercc = TSpecificCall(call, i, emptyAp)
else innercc = TSomeCall(p, emptyAp)
)

View File

@@ -204,3 +204,5 @@ class DataFlowCall extends CallInstruction {
Function getEnclosingCallable() { result = this.getEnclosingFunction() }
}
predicate isUnreachableInCall(Node n, DataFlowCall call) { none() } // stub implementation

View File

@@ -66,11 +66,14 @@ private newtype TOpcode =
TCallSideEffect() or
TCallReadSideEffect() or
TIndirectReadSideEffect() or
TIndirectWriteSideEffect() or
TIndirectMustWriteSideEffect() or
TIndirectMayWriteSideEffect() or
TBufferReadSideEffect() or
TBufferWriteSideEffect() or
TBufferMustWriteSideEffect() or
TBufferMayWriteSideEffect() or
TSizedBufferReadSideEffect() or
TSizedBufferMustWriteSideEffect() or
TSizedBufferMayWriteSideEffect() or
TChi() or
TInlineAsm() or
TUnreached() or
@@ -135,17 +138,28 @@ abstract class ReadSideEffectOpcode extends SideEffectOpcode { }
*/
abstract class WriteSideEffectOpcode extends SideEffectOpcode { }
/**
* An opcode that definitely writes to a set of memory locations as a side effect.
*/
abstract class MustWriteSideEffectOpcode extends WriteSideEffectOpcode { }
/**
* An opcode that may overwrite some, all, or none of an existing set of memory locations. Modeled
* as a read of the original contents, plus a "may" write of the new contents.
*/
abstract class MayWriteSideEffectOpcode extends SideEffectOpcode { }
abstract class MayWriteSideEffectOpcode extends WriteSideEffectOpcode { }
/**
* An opcode that accesses a buffer via an `AddressOperand` and a `BufferSizeOperand`.
* An opcode that accesses a buffer via an `AddressOperand`.
*/
abstract class BufferAccessOpcode extends MemoryAccessOpcode { }
/**
* An opcode that accesses a buffer via an `AddressOperand` with a `BufferSizeOperand` specifying
* the number of elements accessed.
*/
abstract class SizedBufferAccessOpcode extends BufferAccessOpcode { }
module Opcode {
class NoOp extends Opcode, TNoOp {
final override string toString() { result = "NoOp" }
@@ -416,9 +430,9 @@ module Opcode {
final override string toString() { result = "IndirectReadSideEffect" }
}
class IndirectWriteSideEffect extends WriteSideEffectOpcode, MemoryAccessOpcode,
TIndirectWriteSideEffect {
final override string toString() { result = "IndirectWriteSideEffect" }
class IndirectMustWriteSideEffect extends MustWriteSideEffectOpcode, MemoryAccessOpcode,
TIndirectMustWriteSideEffect {
final override string toString() { result = "IndirectMustWriteSideEffect" }
}
class IndirectMayWriteSideEffect extends MayWriteSideEffectOpcode, MemoryAccessOpcode,
@@ -430,9 +444,9 @@ module Opcode {
final override string toString() { result = "BufferReadSideEffect" }
}
class BufferWriteSideEffect extends WriteSideEffectOpcode, BufferAccessOpcode,
TBufferWriteSideEffect {
final override string toString() { result = "BufferWriteSideEffect" }
class BufferMustWriteSideEffect extends MustWriteSideEffectOpcode, BufferAccessOpcode,
TBufferMustWriteSideEffect {
final override string toString() { result = "BufferMustWriteSideEffect" }
}
class BufferMayWriteSideEffect extends MayWriteSideEffectOpcode, BufferAccessOpcode,
@@ -440,6 +454,21 @@ module Opcode {
final override string toString() { result = "BufferMayWriteSideEffect" }
}
class SizedBufferReadSideEffect extends ReadSideEffectOpcode, SizedBufferAccessOpcode,
TSizedBufferReadSideEffect {
final override string toString() { result = "SizedBufferReadSideEffect" }
}
class SizedBufferMustWriteSideEffect extends MustWriteSideEffectOpcode, SizedBufferAccessOpcode,
TSizedBufferMustWriteSideEffect {
final override string toString() { result = "SizedBufferMustWriteSideEffect" }
}
class SizedBufferMayWriteSideEffect extends MayWriteSideEffectOpcode, SizedBufferAccessOpcode,
TSizedBufferMayWriteSideEffect {
final override string toString() { result = "SizedBufferMayWriteSideEffect" }
}
class Chi extends Opcode, TChi {
final override string toString() { result = "Chi" }
}

View File

@@ -30,7 +30,7 @@ module InstructionSanity {
or
opcode instanceof MemoryAccessOpcode and tag instanceof AddressOperandTag
or
opcode instanceof BufferAccessOpcode and tag instanceof BufferSizeOperand
opcode instanceof SizedBufferAccessOpcode and tag instanceof BufferSizeOperandTag
or
opcode instanceof OpcodeWithCondition and tag instanceof ConditionOperandTag
or
@@ -48,8 +48,8 @@ module InstructionSanity {
or
(
opcode instanceof ReadSideEffectOpcode or
opcode instanceof MayWriteSideEffectOpcode or
opcode instanceof Opcode::InlineAsm
opcode instanceof Opcode::InlineAsm or
opcode instanceof Opcode::CallSideEffect
) and
tag instanceof SideEffectOperandTag
)
@@ -120,6 +120,15 @@ module InstructionSanity {
)
}
query predicate sideEffectWithoutPrimary(
SideEffectInstruction instr, string message, IRFunction func, string funcText
) {
not exists(instr.getPrimaryInstruction()) and
message = "Side effect instruction missing primary instruction in function $@" and
func = instr.getEnclosingIRFunction() and
funcText = Language::getIdentityString(func.getFunction())
}
/**
* Holds if an instruction, other than `ExitFunction`, has no successors.
*/
@@ -609,9 +618,14 @@ class VariableInstruction extends Instruction {
VariableInstruction() { var = Construction::getInstructionVariable(this) }
final override string getImmediateString() { result = var.toString() }
override string getImmediateString() { result = var.toString() }
final IRVariable getVariable() { result = var }
final IRVariable getIRVariable() { result = var }
/**
* Gets the AST variable that this instruction's IR variable refers to, if one exists.
*/
final Language::Variable getASTVariable() { result = var.(IRUserVariable).getVariable() }
}
class FieldInstruction extends Instruction {
@@ -644,6 +658,16 @@ class ConstantValueInstruction extends Instruction {
final string getValue() { result = value }
}
class IndexedInstruction extends Instruction {
int index;
IndexedInstruction() { index = Construction::getInstructionIndex(this) }
final override string getImmediateString() { result = index.toString() }
final int getIndex() { result = index }
}
class EnterFunctionInstruction extends Instruction {
EnterFunctionInstruction() { getOpcode() instanceof Opcode::EnterFunction }
}
@@ -1175,6 +1199,8 @@ class CallReadSideEffectInstruction extends SideEffectInstruction {
*/
class IndirectReadSideEffectInstruction extends SideEffectInstruction {
IndirectReadSideEffectInstruction() { getOpcode() instanceof Opcode::IndirectReadSideEffect }
Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() }
}
/**
@@ -1182,13 +1208,39 @@ class IndirectReadSideEffectInstruction extends SideEffectInstruction {
*/
class BufferReadSideEffectInstruction extends SideEffectInstruction {
BufferReadSideEffectInstruction() { getOpcode() instanceof Opcode::BufferReadSideEffect }
Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() }
}
/**
* An instruction representing the read of an indirect buffer parameter within a function call.
*/
class SizedBufferReadSideEffectInstruction extends SideEffectInstruction {
SizedBufferReadSideEffectInstruction() {
getOpcode() instanceof Opcode::SizedBufferReadSideEffect
}
Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() }
Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() }
}
/**
* An instruction representing a side effect of a function call.
*/
class WriteSideEffectInstruction extends SideEffectInstruction {
WriteSideEffectInstruction() { getOpcode() instanceof WriteSideEffectOpcode }
Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() }
}
/**
* An instruction representing the write of an indirect parameter within a function call.
*/
class IndirectWriteSideEffectInstruction extends SideEffectInstruction {
IndirectWriteSideEffectInstruction() { getOpcode() instanceof Opcode::IndirectWriteSideEffect }
class IndirectMustWriteSideEffectInstruction extends WriteSideEffectInstruction {
IndirectMustWriteSideEffectInstruction() {
getOpcode() instanceof Opcode::IndirectMustWriteSideEffect
}
final override MemoryAccessKind getResultMemoryAccess() { result instanceof IndirectMemoryAccess }
}
@@ -1197,18 +1249,34 @@ class IndirectWriteSideEffectInstruction extends SideEffectInstruction {
* An instruction representing the write of an indirect buffer parameter within a function call. The
* entire buffer is overwritten.
*/
class BufferWriteSideEffectInstruction extends SideEffectInstruction {
BufferWriteSideEffectInstruction() { getOpcode() instanceof Opcode::BufferWriteSideEffect }
class BufferMustWriteSideEffectInstruction extends WriteSideEffectInstruction {
BufferMustWriteSideEffectInstruction() {
getOpcode() instanceof Opcode::BufferMustWriteSideEffect
}
final override MemoryAccessKind getResultMemoryAccess() { result instanceof BufferMemoryAccess }
}
/**
* An instruction representing the write of an indirect buffer parameter within a function call. The
* entire buffer is overwritten.
*/
class SizedBufferMustWriteSideEffectInstruction extends WriteSideEffectInstruction {
SizedBufferMustWriteSideEffectInstruction() {
getOpcode() instanceof Opcode::SizedBufferMustWriteSideEffect
}
final override MemoryAccessKind getResultMemoryAccess() { result instanceof BufferMemoryAccess }
Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() }
}
/**
* An instruction representing the potential write of an indirect parameter within a function call.
* Unlike `IndirectWriteSideEffectInstruction`, the location might not be completely overwritten.
* written.
*/
class IndirectMayWriteSideEffectInstruction extends SideEffectInstruction {
class IndirectMayWriteSideEffectInstruction extends WriteSideEffectInstruction {
IndirectMayWriteSideEffectInstruction() {
getOpcode() instanceof Opcode::IndirectMayWriteSideEffect
}
@@ -1222,7 +1290,7 @@ class IndirectMayWriteSideEffectInstruction extends SideEffectInstruction {
* An instruction representing the write of an indirect buffer parameter within a function call.
* Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten.
*/
class BufferMayWriteSideEffectInstruction extends SideEffectInstruction {
class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction {
BufferMayWriteSideEffectInstruction() { getOpcode() instanceof Opcode::BufferMayWriteSideEffect }
final override MemoryAccessKind getResultMemoryAccess() {
@@ -1230,6 +1298,22 @@ class BufferMayWriteSideEffectInstruction extends SideEffectInstruction {
}
}
/**
* An instruction representing the write of an indirect buffer parameter within a function call.
* Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten.
*/
class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction {
SizedBufferMayWriteSideEffectInstruction() {
getOpcode() instanceof Opcode::SizedBufferMayWriteSideEffect
}
final override MemoryAccessKind getResultMemoryAccess() {
result instanceof BufferMayMemoryAccess
}
Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() }
}
/**
* An instruction representing a GNU or MSVC inline assembly statement.
*/

View File

@@ -254,6 +254,16 @@ class AddressOperand extends RegisterOperand {
override string toString() { result = "Address" }
}
/**
* The buffer size operand of an instruction that represents a read or write of
* a buffer.
*/
class BufferSizeOperand extends RegisterOperand {
override BufferSizeOperandTag tag;
override string toString() { result = "BufferSize" }
}
/**
* The source value operand of an instruction that loads a value from memory (e.g. `Load`,
* `ReturnValue`, `ThrowValue`).
@@ -390,10 +400,10 @@ class SideEffectOperand extends TypedOperand {
useInstr instanceof BufferReadSideEffectInstruction and
result instanceof BufferMemoryAccess
or
useInstr instanceof IndirectWriteSideEffectInstruction and
useInstr instanceof IndirectMustWriteSideEffectInstruction and
result instanceof IndirectMemoryAccess
or
useInstr instanceof BufferWriteSideEffectInstruction and
useInstr instanceof BufferMustWriteSideEffectInstruction and
result instanceof BufferMemoryAccess
or
useInstr instanceof IndirectMayWriteSideEffectInstruction and

View File

@@ -135,14 +135,14 @@ private predicate variableAddressValueNumber(
VariableAddressInstruction instr, IRFunction irFunc, IRVariable var
) {
instr.getEnclosingIRFunction() = irFunc and
instr.getVariable() = var
instr.getIRVariable() = var
}
private predicate initializeParameterValueNumber(
InitializeParameterInstruction instr, IRFunction irFunc, IRVariable var
) {
instr.getEnclosingIRFunction() = irFunc and
instr.getVariable() = var
instr.getIRVariable() = var
}
private predicate initializeThisValueNumber(InitializeThisInstruction instr, IRFunction irFunc) {

View File

@@ -282,7 +282,7 @@ private predicate automaticVariableAddressEscapes(IRAutomaticVariable var) {
// The variable's address escapes if the result of any
// VariableAddressInstruction that computes the variable's address escapes.
exists(VariableAddressInstruction instr |
instr.getVariable() = var and
instr.getIRVariable() = var and
resultEscapesNonReturn(instr)
)
}
@@ -305,7 +305,7 @@ predicate variableAddressEscapes(IRVariable var) {
*/
predicate resultPointsTo(Instruction instr, IRVariable var, IntValue bitOffset) {
// The address of a variable points to that variable, at offset 0.
instr.(VariableAddressInstruction).getVariable() = var and
instr.(VariableAddressInstruction).getIRVariable() = var and
bitOffset = 0
or
exists(Operand operand, IntValue originalBitOffset, IntValue propagatedBitOffset |

View File

@@ -334,7 +334,7 @@ private module Cached {
IRVariable getInstructionVariable(Instruction instruction) {
result = getNewIRVariable(getOldInstruction(instruction)
.(OldIR::VariableInstruction)
.getVariable())
.getIRVariable())
}
cached
@@ -342,6 +342,11 @@ private module Cached {
result = getOldInstruction(instruction).(OldIR::FieldInstruction).getField()
}
cached
int getInstructionIndex(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::IndexedInstruction).getIndex()
}
cached
Function getInstructionFunction(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::FunctionInstruction).getFunctionSymbol()

View File

@@ -66,12 +66,14 @@ AddressOperandTag addressOperand() { result = TAddressOperand() }
* The buffer size operand of an instruction that represents a read or write of
* a buffer.
*/
class BufferSizeOperand extends RegisterOperandTag, TBufferSizeOperand {
class BufferSizeOperandTag extends RegisterOperandTag, TBufferSizeOperand {
final override string toString() { result = "BufferSize" }
final override int getSortOrder() { result = 1 }
}
BufferSizeOperandTag bufferSizeOperand() { result = TBufferSizeOperand() }
/**
* The operand representing the read side effect of a `SideEffectInstruction`.
*/

View File

@@ -30,7 +30,7 @@ module InstructionSanity {
or
opcode instanceof MemoryAccessOpcode and tag instanceof AddressOperandTag
or
opcode instanceof BufferAccessOpcode and tag instanceof BufferSizeOperand
opcode instanceof SizedBufferAccessOpcode and tag instanceof BufferSizeOperandTag
or
opcode instanceof OpcodeWithCondition and tag instanceof ConditionOperandTag
or
@@ -48,8 +48,8 @@ module InstructionSanity {
or
(
opcode instanceof ReadSideEffectOpcode or
opcode instanceof MayWriteSideEffectOpcode or
opcode instanceof Opcode::InlineAsm
opcode instanceof Opcode::InlineAsm or
opcode instanceof Opcode::CallSideEffect
) and
tag instanceof SideEffectOperandTag
)
@@ -120,6 +120,15 @@ module InstructionSanity {
)
}
query predicate sideEffectWithoutPrimary(
SideEffectInstruction instr, string message, IRFunction func, string funcText
) {
not exists(instr.getPrimaryInstruction()) and
message = "Side effect instruction missing primary instruction in function $@" and
func = instr.getEnclosingIRFunction() and
funcText = Language::getIdentityString(func.getFunction())
}
/**
* Holds if an instruction, other than `ExitFunction`, has no successors.
*/
@@ -609,9 +618,14 @@ class VariableInstruction extends Instruction {
VariableInstruction() { var = Construction::getInstructionVariable(this) }
final override string getImmediateString() { result = var.toString() }
override string getImmediateString() { result = var.toString() }
final IRVariable getVariable() { result = var }
final IRVariable getIRVariable() { result = var }
/**
* Gets the AST variable that this instruction's IR variable refers to, if one exists.
*/
final Language::Variable getASTVariable() { result = var.(IRUserVariable).getVariable() }
}
class FieldInstruction extends Instruction {
@@ -644,6 +658,16 @@ class ConstantValueInstruction extends Instruction {
final string getValue() { result = value }
}
class IndexedInstruction extends Instruction {
int index;
IndexedInstruction() { index = Construction::getInstructionIndex(this) }
final override string getImmediateString() { result = index.toString() }
final int getIndex() { result = index }
}
class EnterFunctionInstruction extends Instruction {
EnterFunctionInstruction() { getOpcode() instanceof Opcode::EnterFunction }
}
@@ -1175,6 +1199,8 @@ class CallReadSideEffectInstruction extends SideEffectInstruction {
*/
class IndirectReadSideEffectInstruction extends SideEffectInstruction {
IndirectReadSideEffectInstruction() { getOpcode() instanceof Opcode::IndirectReadSideEffect }
Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() }
}
/**
@@ -1182,13 +1208,39 @@ class IndirectReadSideEffectInstruction extends SideEffectInstruction {
*/
class BufferReadSideEffectInstruction extends SideEffectInstruction {
BufferReadSideEffectInstruction() { getOpcode() instanceof Opcode::BufferReadSideEffect }
Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() }
}
/**
* An instruction representing the read of an indirect buffer parameter within a function call.
*/
class SizedBufferReadSideEffectInstruction extends SideEffectInstruction {
SizedBufferReadSideEffectInstruction() {
getOpcode() instanceof Opcode::SizedBufferReadSideEffect
}
Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() }
Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() }
}
/**
* An instruction representing a side effect of a function call.
*/
class WriteSideEffectInstruction extends SideEffectInstruction {
WriteSideEffectInstruction() { getOpcode() instanceof WriteSideEffectOpcode }
Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() }
}
/**
* An instruction representing the write of an indirect parameter within a function call.
*/
class IndirectWriteSideEffectInstruction extends SideEffectInstruction {
IndirectWriteSideEffectInstruction() { getOpcode() instanceof Opcode::IndirectWriteSideEffect }
class IndirectMustWriteSideEffectInstruction extends WriteSideEffectInstruction {
IndirectMustWriteSideEffectInstruction() {
getOpcode() instanceof Opcode::IndirectMustWriteSideEffect
}
final override MemoryAccessKind getResultMemoryAccess() { result instanceof IndirectMemoryAccess }
}
@@ -1197,18 +1249,34 @@ class IndirectWriteSideEffectInstruction extends SideEffectInstruction {
* An instruction representing the write of an indirect buffer parameter within a function call. The
* entire buffer is overwritten.
*/
class BufferWriteSideEffectInstruction extends SideEffectInstruction {
BufferWriteSideEffectInstruction() { getOpcode() instanceof Opcode::BufferWriteSideEffect }
class BufferMustWriteSideEffectInstruction extends WriteSideEffectInstruction {
BufferMustWriteSideEffectInstruction() {
getOpcode() instanceof Opcode::BufferMustWriteSideEffect
}
final override MemoryAccessKind getResultMemoryAccess() { result instanceof BufferMemoryAccess }
}
/**
* An instruction representing the write of an indirect buffer parameter within a function call. The
* entire buffer is overwritten.
*/
class SizedBufferMustWriteSideEffectInstruction extends WriteSideEffectInstruction {
SizedBufferMustWriteSideEffectInstruction() {
getOpcode() instanceof Opcode::SizedBufferMustWriteSideEffect
}
final override MemoryAccessKind getResultMemoryAccess() { result instanceof BufferMemoryAccess }
Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() }
}
/**
* An instruction representing the potential write of an indirect parameter within a function call.
* Unlike `IndirectWriteSideEffectInstruction`, the location might not be completely overwritten.
* written.
*/
class IndirectMayWriteSideEffectInstruction extends SideEffectInstruction {
class IndirectMayWriteSideEffectInstruction extends WriteSideEffectInstruction {
IndirectMayWriteSideEffectInstruction() {
getOpcode() instanceof Opcode::IndirectMayWriteSideEffect
}
@@ -1222,7 +1290,7 @@ class IndirectMayWriteSideEffectInstruction extends SideEffectInstruction {
* An instruction representing the write of an indirect buffer parameter within a function call.
* Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten.
*/
class BufferMayWriteSideEffectInstruction extends SideEffectInstruction {
class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction {
BufferMayWriteSideEffectInstruction() { getOpcode() instanceof Opcode::BufferMayWriteSideEffect }
final override MemoryAccessKind getResultMemoryAccess() {
@@ -1230,6 +1298,22 @@ class BufferMayWriteSideEffectInstruction extends SideEffectInstruction {
}
}
/**
* An instruction representing the write of an indirect buffer parameter within a function call.
* Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten.
*/
class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction {
SizedBufferMayWriteSideEffectInstruction() {
getOpcode() instanceof Opcode::SizedBufferMayWriteSideEffect
}
final override MemoryAccessKind getResultMemoryAccess() {
result instanceof BufferMayMemoryAccess
}
Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() }
}
/**
* An instruction representing a GNU or MSVC inline assembly statement.
*/

View File

@@ -254,6 +254,16 @@ class AddressOperand extends RegisterOperand {
override string toString() { result = "Address" }
}
/**
* The buffer size operand of an instruction that represents a read or write of
* a buffer.
*/
class BufferSizeOperand extends RegisterOperand {
override BufferSizeOperandTag tag;
override string toString() { result = "BufferSize" }
}
/**
* The source value operand of an instruction that loads a value from memory (e.g. `Load`,
* `ReturnValue`, `ThrowValue`).
@@ -390,10 +400,10 @@ class SideEffectOperand extends TypedOperand {
useInstr instanceof BufferReadSideEffectInstruction and
result instanceof BufferMemoryAccess
or
useInstr instanceof IndirectWriteSideEffectInstruction and
useInstr instanceof IndirectMustWriteSideEffectInstruction and
result instanceof IndirectMemoryAccess
or
useInstr instanceof BufferWriteSideEffectInstruction and
useInstr instanceof BufferMustWriteSideEffectInstruction and
result instanceof BufferMemoryAccess
or
useInstr instanceof IndirectMayWriteSideEffectInstruction and

View File

@@ -135,14 +135,14 @@ private predicate variableAddressValueNumber(
VariableAddressInstruction instr, IRFunction irFunc, IRVariable var
) {
instr.getEnclosingIRFunction() = irFunc and
instr.getVariable() = var
instr.getIRVariable() = var
}
private predicate initializeParameterValueNumber(
InitializeParameterInstruction instr, IRFunction irFunc, IRVariable var
) {
instr.getEnclosingIRFunction() = irFunc and
instr.getVariable() = var
instr.getIRVariable() = var
}
private predicate initializeThisValueNumber(InitializeThisInstruction instr, IRFunction irFunc) {

View File

@@ -259,6 +259,14 @@ private module Cached {
.getInstructionConstantValue(getInstructionTag(instruction))
}
cached
int getInstructionIndex(Instruction instruction) {
exists(TranslatedElement element, InstructionTag tag |
instructionOrigin(instruction, element, tag) and
result = element.getInstructionIndex(tag)
)
}
cached
StringLiteral getInstructionStringLiteral(Instruction instruction) {
result = getInstructionTranslatedElement(instruction)

View File

@@ -5,6 +5,7 @@ private import semmle.code.cpp.models.interfaces.SideEffect
private import InstructionTag
private import TranslatedElement
private import TranslatedExpr
private import TranslatedFunction
/**
* The IR translation of a call to a function. The call may be from an actual
@@ -22,6 +23,8 @@ abstract class TranslatedCall extends TranslatedExpr {
id = -1 and result = getCallTarget()
or
result = getArgument(id)
or
id = getNumberOfArguments() and result = getSideEffects()
}
final override Instruction getFirstInstruction() {
@@ -66,6 +69,9 @@ abstract class TranslatedCall extends TranslatedExpr {
then result = getArgument(argIndex + 1).getFirstInstruction()
else result = getInstruction(CallTag())
)
or
child = getSideEffects() and
result = getParent().getChildSuccessor(this)
}
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
@@ -75,12 +81,19 @@ abstract class TranslatedCall extends TranslatedExpr {
tag = CallTag() and
if hasSideEffect()
then result = getInstruction(CallSideEffectTag())
else result = getParent().getChildSuccessor(this)
else
if hasPreciseSideEffect()
then result = getSideEffects().getFirstInstruction()
else result = getParent().getChildSuccessor(this)
)
or
hasSideEffect() and
tag = CallSideEffectTag() and
result = getParent().getChildSuccessor(this)
(
hasSideEffect() and
tag = CallSideEffectTag() and
if hasPreciseSideEffect()
then result = getSideEffects().getFirstInstruction()
else result = getParent().getChildSuccessor(this)
)
)
}
@@ -165,6 +178,8 @@ abstract class TranslatedCall extends TranslatedExpr {
*/
abstract TranslatedExpr getArgument(int index);
abstract int getNumberOfArguments();
/**
* If there are any arguments, gets the first instruction of the first
* argument. Otherwise, returns the call instruction.
@@ -191,6 +206,10 @@ abstract class TranslatedCall extends TranslatedExpr {
tag = CallSideEffectTag() and
result = getResult()
}
predicate hasPreciseSideEffect() { exists(getSideEffects()) }
TranslatedSideEffects getSideEffects() { result.getCall() = expr }
}
/**
@@ -245,6 +264,8 @@ abstract class TranslatedCallExpr extends TranslatedNonConstantExpr, TranslatedC
final override TranslatedExpr getArgument(int index) {
result = getTranslatedExpr(expr.getArgument(index).getFullyConverted())
}
final override int getNumberOfArguments() { result = expr.getNumberOfArguments() }
}
/**
@@ -269,11 +290,11 @@ class TranslatedFunctionCall extends TranslatedCallExpr, TranslatedDirectCall {
}
override predicate hasReadSideEffect() {
not expr.getTarget().(SideEffectFunction).neverReadsMemory()
not expr.getTarget().(SideEffectFunction).hasOnlySpecificReadSideEffects()
}
override predicate hasWriteSideEffect() {
not expr.getTarget().(SideEffectFunction).neverWritesMemory()
not expr.getTarget().(SideEffectFunction).hasOnlySpecificWriteSideEffects()
}
}
@@ -295,3 +316,229 @@ class TranslatedStructorCall extends TranslatedFunctionCall {
override predicate hasQualifier() { any() }
}
class TranslatedSideEffects extends TranslatedElement, TTranslatedSideEffects {
Call expr;
TranslatedSideEffects() { this = TTranslatedSideEffects(expr) }
override string toString() { result = "(side effects for " + expr.toString() + ")" }
override Locatable getAST() { result = expr }
Call getCall() { result = expr }
override TranslatedElement getChild(int i) {
result = rank[i + 1](TranslatedSideEffect tse, int isWrite, int index |
(
tse.getCall() = getCall() and
tse.getArgumentIndex() = index and
if tse.isWrite() then isWrite = 1 else isWrite = 0
)
|
tse order by isWrite, index
)
}
override Instruction getChildSuccessor(TranslatedElement te) {
exists(int i |
getChild(i) = te and
if exists(getChild(i + 1))
then result = getChild(i + 1).getFirstInstruction()
else result = getParent().getChildSuccessor(this)
)
}
override predicate hasInstruction(Opcode opcode, InstructionTag tag, Type t, boolean isGLValue) {
none()
}
override Instruction getFirstInstruction() { result = getChild(0).getFirstInstruction() }
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) { none() }
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) { none() }
override Type getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) { none() }
/**
* Gets the `TranslatedFunction` containing this expression.
*/
final TranslatedFunction getEnclosingFunction() {
result = getTranslatedFunction(expr.getEnclosingFunction())
}
/**
* Gets the `Function` containing this expression.
*/
override Function getFunction() { result = expr.getEnclosingFunction() }
}
class TranslatedSideEffect extends TranslatedElement, TTranslatedArgumentSideEffect {
Call call;
Expr arg;
int index;
boolean write;
TranslatedSideEffect() { this = TTranslatedArgumentSideEffect(call, arg, index, write) }
override Locatable getAST() { result = arg }
Expr getExpr() { result = arg }
Call getCall() { result = call }
int getArgumentIndex() { result = index }
predicate isWrite() { write = true }
override string toString() {
write = true and
result = "(write side effect for " + arg.toString() + ")"
or
write = false and
result = "(read side effect for " + arg.toString() + ")"
}
override TranslatedElement getChild(int n) { none() }
override Instruction getChildSuccessor(TranslatedElement child) { none() }
override Instruction getFirstInstruction() { result = getInstruction(OnlyInstructionTag()) }
override predicate hasInstruction(Opcode opcode, InstructionTag tag, Type t, boolean isGLValue) {
isWrite() and
hasSpecificWriteSideEffect(opcode) and
tag = OnlyInstructionTag() and
(
opcode instanceof BufferAccessOpcode and
t instanceof UnknownType
or
not opcode instanceof BufferAccessOpcode and
(
t = arg.getUnspecifiedType().(DerivedType).getBaseType() and
not t instanceof VoidType
or
arg.getUnspecifiedType().(DerivedType).getBaseType() instanceof VoidType and
t instanceof UnknownType
)
or
index = -1 and
not arg.getUnspecifiedType() instanceof DerivedType and
t = arg.getUnspecifiedType()
) and
isGLValue = false
or
not isWrite() and
hasSpecificReadSideEffect(opcode) and
tag = OnlyInstructionTag() and
t instanceof VoidType and
isGLValue = false
}
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
result = getParent().getChildSuccessor(this) and
tag = OnlyInstructionTag() and
kind instanceof GotoEdge
}
override Instruction getInstructionOperand(InstructionTag tag, OperandTag operandTag) {
tag instanceof OnlyInstructionTag and
operandTag instanceof AddressOperandTag and
result = getTranslatedExpr(arg).getResult()
or
tag instanceof OnlyInstructionTag and
operandTag instanceof SideEffectOperandTag and
not isWrite() and
result = getEnclosingFunction().getUnmodeledDefinitionInstruction()
or
tag instanceof OnlyInstructionTag and
operandTag instanceof BufferSizeOperandTag and
result = getTranslatedExpr(call
.getArgument(call.getTarget().(SideEffectFunction).getParameterSizeIndex(index))
.getFullyConverted()).getResult()
}
override Type getInstructionOperandType(InstructionTag tag, TypedOperandTag operandTag) {
tag instanceof OnlyInstructionTag and
result = arg.getType().getUnspecifiedType().(DerivedType).getBaseType() and
operandTag instanceof SideEffectOperandTag
or
tag instanceof OnlyInstructionTag and
result = arg.getType().getUnspecifiedType() and
not result instanceof DerivedType and
operandTag instanceof SideEffectOperandTag
}
predicate hasSpecificWriteSideEffect(Opcode op) {
exists(boolean buffer, boolean mustWrite |
if exists(call.getTarget().(SideEffectFunction).getParameterSizeIndex(index))
then
call.getTarget().(SideEffectFunction).hasSpecificWriteSideEffect(index, true, mustWrite) and
buffer = true and
(
mustWrite = false and op instanceof Opcode::SizedBufferMayWriteSideEffect
or
mustWrite = true and op instanceof Opcode::SizedBufferMustWriteSideEffect
)
else (
call.getTarget().(SideEffectFunction).hasSpecificWriteSideEffect(index, buffer, mustWrite) and
(
buffer = true and mustWrite = false and op instanceof Opcode::BufferMayWriteSideEffect
or
buffer = false and mustWrite = false and op instanceof Opcode::IndirectMayWriteSideEffect
or
buffer = true and mustWrite = true and op instanceof Opcode::BufferMustWriteSideEffect
or
buffer = false and mustWrite = true and op instanceof Opcode::IndirectMustWriteSideEffect
)
)
)
or
not call.getTarget() instanceof SideEffectFunction and
getArgumentIndex() != -1 and
op instanceof Opcode::BufferMayWriteSideEffect
or
not call.getTarget() instanceof SideEffectFunction and
getArgumentIndex() = -1 and
op instanceof Opcode::IndirectMayWriteSideEffect
}
predicate hasSpecificReadSideEffect(Opcode op) {
exists(boolean buffer |
call.getTarget().(SideEffectFunction).hasSpecificReadSideEffect(index, buffer) and
if exists(call.getTarget().(SideEffectFunction).getParameterSizeIndex(index))
then buffer = true and op instanceof Opcode::SizedBufferReadSideEffect
else (
buffer = true and op instanceof Opcode::BufferReadSideEffect
or
buffer = false and op instanceof Opcode::IndirectReadSideEffect
)
)
or
not call.getTarget() instanceof SideEffectFunction and
op instanceof Opcode::IndirectReadSideEffect
}
override Instruction getPrimaryInstructionForSideEffect(InstructionTag tag) {
tag = OnlyInstructionTag() and
result = getTranslatedExpr(call).getInstruction(CallTag())
}
final override int getInstructionIndex(InstructionTag tag) {
tag = OnlyInstructionTag() and
result = index
}
/**
* Gets the `TranslatedFunction` containing this expression.
*/
final TranslatedFunction getEnclosingFunction() {
result = getTranslatedFunction(arg.getEnclosingFunction())
}
/**
* Gets the `Function` containing this expression.
*/
override Function getFunction() { result = arg.getEnclosingFunction() }
}

View File

@@ -10,6 +10,7 @@ private import TranslatedFunction
private import TranslatedStmt
private import TranslatedExpr
private import IRConstruction
private import semmle.code.cpp.models.interfaces.SideEffect
/**
* Gets the built-in `int` type.
@@ -379,7 +380,44 @@ newtype TTranslatedElement =
// An allocation size for a `new` or `new[]` expression
TTranslatedAllocationSize(NewOrNewArrayExpr newExpr) { not ignoreExpr(newExpr) } or
// The declaration/initialization part of a `ConditionDeclExpr`
TTranslatedConditionDecl(ConditionDeclExpr expr) { not ignoreExpr(expr) }
TTranslatedConditionDecl(ConditionDeclExpr expr) { not ignoreExpr(expr) } or
// The side effects of a `Call` {
TTranslatedSideEffects(Call expr) { exists(TTranslatedArgumentSideEffect(expr, _, _, _)) } or // A precise side effect of an argument to a `Call` {
TTranslatedArgumentSideEffect(Call call, Expr expr, int n, boolean isWrite) {
(
expr = call.getArgument(n).getFullyConverted()
or
expr = call.getQualifier().getFullyConverted() and
n = -1
) and
(
call.getTarget().(SideEffectFunction).hasSpecificReadSideEffect(n, _) and
isWrite = false
or
call.getTarget().(SideEffectFunction).hasSpecificWriteSideEffect(n, _, _) and
isWrite = true
or
not call.getTarget() instanceof SideEffectFunction and
exists(Type t | t = expr.getUnspecifiedType() |
t instanceof ArrayType or
t instanceof PointerType or
t instanceof ReferenceType
) and
(
isWrite = true or
isWrite = false
)
or
not call.getTarget() instanceof SideEffectFunction and
n = -1 and
(
isWrite = true or
isWrite = false
)
) and
not ignoreExpr(expr) and
not ignoreExpr(call)
}
/**
* Gets the index of the first explicitly initialized element in `initList`
@@ -572,6 +610,12 @@ abstract class TranslatedElement extends TTranslatedElement {
*/
string getInstructionConstantValue(InstructionTag tag) { none() }
/**
* If the instruction specified by `tag` is an `IndexedInstruction`, gets the
* index for that instruction.
*/
int getInstructionIndex(InstructionTag tag) { none() }
/**
* If the instruction specified by `tag` is a `PointerArithmeticInstruction`,
* gets the size of the type pointed to by the pointer.

View File

@@ -1690,6 +1690,10 @@ class TranslatedAllocatorCall extends TTranslatedAllocatorCall, TranslatedDirect
any()
}
final override int getNumberOfArguments() {
result = expr.getAllocatorCall().getNumberOfArguments()
}
final override TranslatedExpr getArgument(int index) {
// If the allocator is the default operator new(void*), there will be no
// allocator call in the AST. Otherwise, there will be an allocator call

View File

@@ -30,7 +30,7 @@ module InstructionSanity {
or
opcode instanceof MemoryAccessOpcode and tag instanceof AddressOperandTag
or
opcode instanceof BufferAccessOpcode and tag instanceof BufferSizeOperand
opcode instanceof SizedBufferAccessOpcode and tag instanceof BufferSizeOperandTag
or
opcode instanceof OpcodeWithCondition and tag instanceof ConditionOperandTag
or
@@ -48,8 +48,8 @@ module InstructionSanity {
or
(
opcode instanceof ReadSideEffectOpcode or
opcode instanceof MayWriteSideEffectOpcode or
opcode instanceof Opcode::InlineAsm
opcode instanceof Opcode::InlineAsm or
opcode instanceof Opcode::CallSideEffect
) and
tag instanceof SideEffectOperandTag
)
@@ -120,6 +120,15 @@ module InstructionSanity {
)
}
query predicate sideEffectWithoutPrimary(
SideEffectInstruction instr, string message, IRFunction func, string funcText
) {
not exists(instr.getPrimaryInstruction()) and
message = "Side effect instruction missing primary instruction in function $@" and
func = instr.getEnclosingIRFunction() and
funcText = Language::getIdentityString(func.getFunction())
}
/**
* Holds if an instruction, other than `ExitFunction`, has no successors.
*/
@@ -609,9 +618,14 @@ class VariableInstruction extends Instruction {
VariableInstruction() { var = Construction::getInstructionVariable(this) }
final override string getImmediateString() { result = var.toString() }
override string getImmediateString() { result = var.toString() }
final IRVariable getVariable() { result = var }
final IRVariable getIRVariable() { result = var }
/**
* Gets the AST variable that this instruction's IR variable refers to, if one exists.
*/
final Language::Variable getASTVariable() { result = var.(IRUserVariable).getVariable() }
}
class FieldInstruction extends Instruction {
@@ -644,6 +658,16 @@ class ConstantValueInstruction extends Instruction {
final string getValue() { result = value }
}
class IndexedInstruction extends Instruction {
int index;
IndexedInstruction() { index = Construction::getInstructionIndex(this) }
final override string getImmediateString() { result = index.toString() }
final int getIndex() { result = index }
}
class EnterFunctionInstruction extends Instruction {
EnterFunctionInstruction() { getOpcode() instanceof Opcode::EnterFunction }
}
@@ -1175,6 +1199,8 @@ class CallReadSideEffectInstruction extends SideEffectInstruction {
*/
class IndirectReadSideEffectInstruction extends SideEffectInstruction {
IndirectReadSideEffectInstruction() { getOpcode() instanceof Opcode::IndirectReadSideEffect }
Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() }
}
/**
@@ -1182,13 +1208,39 @@ class IndirectReadSideEffectInstruction extends SideEffectInstruction {
*/
class BufferReadSideEffectInstruction extends SideEffectInstruction {
BufferReadSideEffectInstruction() { getOpcode() instanceof Opcode::BufferReadSideEffect }
Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() }
}
/**
* An instruction representing the read of an indirect buffer parameter within a function call.
*/
class SizedBufferReadSideEffectInstruction extends SideEffectInstruction {
SizedBufferReadSideEffectInstruction() {
getOpcode() instanceof Opcode::SizedBufferReadSideEffect
}
Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() }
Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() }
}
/**
* An instruction representing a side effect of a function call.
*/
class WriteSideEffectInstruction extends SideEffectInstruction {
WriteSideEffectInstruction() { getOpcode() instanceof WriteSideEffectOpcode }
Instruction getArgumentDef() { result = getAnOperand().(AddressOperand).getDef() }
}
/**
* An instruction representing the write of an indirect parameter within a function call.
*/
class IndirectWriteSideEffectInstruction extends SideEffectInstruction {
IndirectWriteSideEffectInstruction() { getOpcode() instanceof Opcode::IndirectWriteSideEffect }
class IndirectMustWriteSideEffectInstruction extends WriteSideEffectInstruction {
IndirectMustWriteSideEffectInstruction() {
getOpcode() instanceof Opcode::IndirectMustWriteSideEffect
}
final override MemoryAccessKind getResultMemoryAccess() { result instanceof IndirectMemoryAccess }
}
@@ -1197,18 +1249,34 @@ class IndirectWriteSideEffectInstruction extends SideEffectInstruction {
* An instruction representing the write of an indirect buffer parameter within a function call. The
* entire buffer is overwritten.
*/
class BufferWriteSideEffectInstruction extends SideEffectInstruction {
BufferWriteSideEffectInstruction() { getOpcode() instanceof Opcode::BufferWriteSideEffect }
class BufferMustWriteSideEffectInstruction extends WriteSideEffectInstruction {
BufferMustWriteSideEffectInstruction() {
getOpcode() instanceof Opcode::BufferMustWriteSideEffect
}
final override MemoryAccessKind getResultMemoryAccess() { result instanceof BufferMemoryAccess }
}
/**
* An instruction representing the write of an indirect buffer parameter within a function call. The
* entire buffer is overwritten.
*/
class SizedBufferMustWriteSideEffectInstruction extends WriteSideEffectInstruction {
SizedBufferMustWriteSideEffectInstruction() {
getOpcode() instanceof Opcode::SizedBufferMustWriteSideEffect
}
final override MemoryAccessKind getResultMemoryAccess() { result instanceof BufferMemoryAccess }
Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() }
}
/**
* An instruction representing the potential write of an indirect parameter within a function call.
* Unlike `IndirectWriteSideEffectInstruction`, the location might not be completely overwritten.
* written.
*/
class IndirectMayWriteSideEffectInstruction extends SideEffectInstruction {
class IndirectMayWriteSideEffectInstruction extends WriteSideEffectInstruction {
IndirectMayWriteSideEffectInstruction() {
getOpcode() instanceof Opcode::IndirectMayWriteSideEffect
}
@@ -1222,7 +1290,7 @@ class IndirectMayWriteSideEffectInstruction extends SideEffectInstruction {
* An instruction representing the write of an indirect buffer parameter within a function call.
* Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten.
*/
class BufferMayWriteSideEffectInstruction extends SideEffectInstruction {
class BufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction {
BufferMayWriteSideEffectInstruction() { getOpcode() instanceof Opcode::BufferMayWriteSideEffect }
final override MemoryAccessKind getResultMemoryAccess() {
@@ -1230,6 +1298,22 @@ class BufferMayWriteSideEffectInstruction extends SideEffectInstruction {
}
}
/**
* An instruction representing the write of an indirect buffer parameter within a function call.
* Unlike `BufferWriteSideEffectInstruction`, the buffer might not be completely overwritten.
*/
class SizedBufferMayWriteSideEffectInstruction extends WriteSideEffectInstruction {
SizedBufferMayWriteSideEffectInstruction() {
getOpcode() instanceof Opcode::SizedBufferMayWriteSideEffect
}
final override MemoryAccessKind getResultMemoryAccess() {
result instanceof BufferMayMemoryAccess
}
Instruction getSizeDef() { result = getAnOperand().(BufferSizeOperand).getDef() }
}
/**
* An instruction representing a GNU or MSVC inline assembly statement.
*/

View File

@@ -254,6 +254,16 @@ class AddressOperand extends RegisterOperand {
override string toString() { result = "Address" }
}
/**
* The buffer size operand of an instruction that represents a read or write of
* a buffer.
*/
class BufferSizeOperand extends RegisterOperand {
override BufferSizeOperandTag tag;
override string toString() { result = "BufferSize" }
}
/**
* The source value operand of an instruction that loads a value from memory (e.g. `Load`,
* `ReturnValue`, `ThrowValue`).
@@ -390,10 +400,10 @@ class SideEffectOperand extends TypedOperand {
useInstr instanceof BufferReadSideEffectInstruction and
result instanceof BufferMemoryAccess
or
useInstr instanceof IndirectWriteSideEffectInstruction and
useInstr instanceof IndirectMustWriteSideEffectInstruction and
result instanceof IndirectMemoryAccess
or
useInstr instanceof BufferWriteSideEffectInstruction and
useInstr instanceof BufferMustWriteSideEffectInstruction and
result instanceof BufferMemoryAccess
or
useInstr instanceof IndirectMayWriteSideEffectInstruction and

View File

@@ -135,14 +135,14 @@ private predicate variableAddressValueNumber(
VariableAddressInstruction instr, IRFunction irFunc, IRVariable var
) {
instr.getEnclosingIRFunction() = irFunc and
instr.getVariable() = var
instr.getIRVariable() = var
}
private predicate initializeParameterValueNumber(
InitializeParameterInstruction instr, IRFunction irFunc, IRVariable var
) {
instr.getEnclosingIRFunction() = irFunc and
instr.getVariable() = var
instr.getIRVariable() = var
}
private predicate initializeThisValueNumber(InitializeThisInstruction instr, IRFunction irFunc) {

View File

@@ -282,7 +282,7 @@ private predicate automaticVariableAddressEscapes(IRAutomaticVariable var) {
// The variable's address escapes if the result of any
// VariableAddressInstruction that computes the variable's address escapes.
exists(VariableAddressInstruction instr |
instr.getVariable() = var and
instr.getIRVariable() = var and
resultEscapesNonReturn(instr)
)
}
@@ -305,7 +305,7 @@ predicate variableAddressEscapes(IRVariable var) {
*/
predicate resultPointsTo(Instruction instr, IRVariable var, IntValue bitOffset) {
// The address of a variable points to that variable, at offset 0.
instr.(VariableAddressInstruction).getVariable() = var and
instr.(VariableAddressInstruction).getIRVariable() = var and
bitOffset = 0
or
exists(Operand operand, IntValue originalBitOffset, IntValue propagatedBitOffset |

View File

@@ -334,7 +334,7 @@ private module Cached {
IRVariable getInstructionVariable(Instruction instruction) {
result = getNewIRVariable(getOldInstruction(instruction)
.(OldIR::VariableInstruction)
.getVariable())
.getIRVariable())
}
cached
@@ -342,6 +342,11 @@ private module Cached {
result = getOldInstruction(instruction).(OldIR::FieldInstruction).getField()
}
cached
int getInstructionIndex(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::IndexedInstruction).getIndex()
}
cached
Function getInstructionFunction(Instruction instruction) {
result = getOldInstruction(instruction).(OldIR::FunctionInstruction).getFunctionSymbol()

View File

@@ -1,6 +1,7 @@
private import implementations.IdentityFunction
private import implementations.Inet
private import implementations.Memcpy
private import implementations.Memset
private import implementations.Printf
private import implementations.Pure
private import implementations.Strcat

View File

@@ -16,9 +16,9 @@ class IdentityFunction extends DataFlowFunction, SideEffectFunction, AliasFuncti
)
}
override predicate neverReadsMemory() { any() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate neverWritesMemory() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate parameterNeverEscapes(int index) { none() }
@@ -34,6 +34,6 @@ class IdentityFunction extends DataFlowFunction, SideEffectFunction, AliasFuncti
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
// These functions simply return the argument value.
input.isInParameter(0) and output.isOutReturnValue()
input.isParameter(0) and output.isReturnValue()
}
}

View File

@@ -5,8 +5,8 @@ class InetNtoa extends TaintFunction {
InetNtoa() { hasGlobalName("inet_ntoa") }
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
input.isInParameter(0) and
output.isOutReturnPointer()
input.isParameter(0) and
output.isReturnValueDeref()
}
}
@@ -14,8 +14,8 @@ class InetAton extends TaintFunction, ArrayFunction {
InetAton() { hasGlobalName("inet_aton") }
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
input.isInParameterPointer(0) and
output.isOutParameterPointer(1)
input.isParameterDeref(0) and
output.isParameterDeref(1)
}
override predicate hasArrayInput(int bufParam) { bufParam = 0 }
@@ -34,8 +34,8 @@ class InetAddr extends TaintFunction, ArrayFunction {
InetAddr() { hasGlobalName("inet_addr") }
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
input.isInParameterPointer(0) and
output.isOutReturnValue()
input.isParameterDeref(0) and
output.isReturnValue()
}
override predicate hasArrayInput(int bufParam) { bufParam = 0 }
@@ -47,8 +47,8 @@ class InetNetwork extends TaintFunction, ArrayFunction {
InetNetwork() { hasGlobalName("inet_network") }
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
input.isInParameterPointer(1) and
output.isOutReturnValue()
input.isParameterDeref(1) and
output.isReturnValue()
}
override predicate hasArrayInput(int bufParam) { bufParam = 0 }
@@ -61,10 +61,10 @@ class InetMakeaddr extends TaintFunction {
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
(
input.isInParameter(0) or
input.isInParameter(1)
input.isParameter(0) or
input.isParameter(1)
) and
output.isOutReturnValue()
output.isReturnValue()
}
}
@@ -72,8 +72,8 @@ class InetLnaof extends TaintFunction {
InetLnaof() { hasGlobalName("inet_lnaof") }
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
input.isInParameter(0) and
output.isOutReturnValue()
input.isParameter(0) and
output.isReturnValue()
}
}
@@ -81,8 +81,8 @@ class InetNetof extends TaintFunction {
InetNetof() { hasGlobalName("inet_netof") }
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
input.isInParameter(0) and
output.isOutReturnValue()
input.isParameter(0) and
output.isReturnValue()
}
}
@@ -91,10 +91,10 @@ class InetPton extends TaintFunction, ArrayFunction {
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
(
input.isInParameter(0) or
input.isInParameterPointer(1)
input.isParameter(0) or
input.isParameterDeref(1)
) and
output.isOutParameterPointer(2)
output.isParameterDeref(2)
}
override predicate hasArrayInput(int bufParam) { bufParam = 1 }
@@ -110,8 +110,8 @@ class Gethostbyname extends TaintFunction, ArrayFunction {
Gethostbyname() { hasGlobalName("gethostbyname") }
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
input.isInParameterPointer(0) and
output.isOutReturnPointer()
input.isParameterDeref(0) and
output.isReturnValueDeref()
}
override predicate hasArrayInput(int bufParam) { bufParam = 0 }
@@ -124,11 +124,11 @@ class Gethostbyaddr extends TaintFunction, ArrayFunction {
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
(
input.isInParameterPointer(0) or
input.isInParameter(1) or
input.isInParameter(2)
input.isParameterDeref(0) or
input.isParameter(1) or
input.isParameter(2)
) and
output.isOutReturnPointer()
output.isReturnValueDeref()
}
override predicate hasArrayInput(int bufParam) { bufParam = 0 }

View File

@@ -1,13 +1,14 @@
import semmle.code.cpp.Function
import semmle.code.cpp.models.interfaces.ArrayFunction
import semmle.code.cpp.models.interfaces.DataFlow
import semmle.code.cpp.models.interfaces.SideEffect
import semmle.code.cpp.models.interfaces.Taint
/**
* The standard functions `memcpy` and `memmove`, and the gcc variant
* `__builtin___memcpy_chk`
*/
class MemcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction {
class MemcpyFunction extends ArrayFunction, DataFlowFunction, SideEffectFunction, TaintFunction {
MemcpyFunction() {
this.hasName("memcpy") or
this.hasName("memmove") or
@@ -19,22 +20,22 @@ class MemcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction {
override predicate hasArrayOutput(int bufParam) { bufParam = 0 }
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
input.isInParameterPointer(1) and
output.isOutParameterPointer(0)
input.isParameterDeref(1) and
output.isParameterDeref(0)
or
input.isInParameterPointer(1) and
output.isOutReturnPointer()
input.isParameterDeref(1) and
output.isReturnValueDeref()
or
input.isInParameter(0) and
output.isOutReturnValue()
input.isParameter(0) and
output.isReturnValue()
}
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
input.isInParameter(2) and
output.isOutParameterPointer(0)
input.isParameter(2) and
output.isParameterDeref(0)
or
input.isInParameter(2) and
output.isOutReturnPointer()
input.isParameter(2) and
output.isReturnValueDeref()
}
override predicate hasArrayWithVariableSize(int bufParam, int countParam) {
@@ -44,4 +45,24 @@ class MemcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction {
) and
countParam = 2
}
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = 0 and buffer = true and mustWrite = true
}
override predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) {
i = 1 and buffer = true
}
override ParameterIndex getParameterSizeIndex(ParameterIndex i) {
result = 2 and
(
i = 0 or
i = 1
)
}
}

View File

@@ -0,0 +1,55 @@
import semmle.code.cpp.Function
import semmle.code.cpp.models.interfaces.ArrayFunction
import semmle.code.cpp.models.interfaces.DataFlow
import semmle.code.cpp.models.interfaces.Alias
import semmle.code.cpp.models.interfaces.SideEffect
/**
* The standard function `memset` and its assorted variants
*/
class MemsetFunction extends ArrayFunction, DataFlowFunction, AliasFunction, SideEffectFunction {
MemsetFunction() {
hasGlobalName("memset") or
hasGlobalName("wmemset") or
hasGlobalName("bzero") or
hasGlobalName("__builtin_memset") or
hasGlobalName("__builtin_memset_chk") or
hasQualifiedName("std", "memset") or
hasQualifiedName("std", "wmemset")
}
override predicate hasArrayOutput(int bufParam) { bufParam = 0 }
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
input.isParameter(0) and
output.isReturnValue()
}
override predicate hasArrayWithVariableSize(int bufParam, int countParam) {
bufParam = 0 and
(if hasGlobalName("bzero") then countParam = 1 else countParam = 2)
}
override predicate parameterNeverEscapes(int index) { hasGlobalName("bzero") and index = 0 }
override predicate parameterEscapesOnlyViaReturn(int index) {
not hasGlobalName("bzero") and index = 0
}
override predicate parameterIsAlwaysReturned(int index) {
not hasGlobalName("bzero") and index = 0
}
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
override predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
i = 0 and buffer = true and mustWrite = true
}
override ParameterIndex getParameterSizeIndex(ParameterIndex i) {
i = 0 and
if hasGlobalName("bzero") then result = 1 else result = 2
}
}

View File

@@ -41,17 +41,17 @@ class PureStrFunction extends AliasFunction, ArrayFunction, TaintFunction, SideE
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
exists(ParameterIndex i |
input.isInParameter(i) and
input.isParameter(i) and
exists(getParameter(i))
or
input.isInParameterPointer(i) and
input.isParameterDeref(i) and
getParameter(i).getUnspecifiedType() instanceof PointerType
) and
(
output.isOutReturnPointer() and
output.isReturnValueDeref() and
getUnspecifiedType() instanceof PointerType
or
output.isOutReturnValue()
output.isReturnValue()
)
}
@@ -67,9 +67,9 @@ class PureStrFunction extends AliasFunction, ArrayFunction, TaintFunction, SideE
override predicate parameterIsAlwaysReturned(int i) { none() }
override predicate neverReadsMemory() { none() }
override predicate hasOnlySpecificReadSideEffects() { none() }
override predicate neverWritesMemory() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
}
class PureFunction extends TaintFunction, SideEffectFunction {
@@ -85,13 +85,13 @@ class PureFunction extends TaintFunction, SideEffectFunction {
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
exists(ParameterIndex i |
input.isInParameter(i) and
input.isParameter(i) and
exists(getParameter(i))
) and
output.isOutReturnValue()
output.isReturnValue()
}
override predicate neverReadsMemory() { any() }
override predicate hasOnlySpecificReadSideEffects() { any() }
override predicate neverWritesMemory() { any() }
override predicate hasOnlySpecificWriteSideEffects() { any() }
}

View File

@@ -19,8 +19,8 @@ class StrcatFunction extends TaintFunction, DataFlowFunction, ArrayFunction {
}
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
input.isInParameter(0) and
output.isOutReturnValue()
input.isParameter(0) and
output.isReturnValue()
}
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
@@ -31,19 +31,19 @@ class StrcatFunction extends TaintFunction, DataFlowFunction, ArrayFunction {
name = "_mbsncat" or
name = "_mbsncat_l"
) and
input.isInParameter(2) and
output.isOutParameterPointer(0)
input.isParameter(2) and
output.isParameterDeref(0)
or
name = "_mbsncat_l" and
input.isInParameter(3) and
output.isOutParameterPointer(0)
input.isParameter(3) and
output.isParameterDeref(0)
)
or
input.isInParameterPointer(0) and
output.isOutParameterPointer(0)
input.isParameterDeref(0) and
output.isParameterDeref(0)
or
input.isInParameter(1) and
output.isOutParameterPointer(0)
input.isParameter(1) and
output.isParameterDeref(0)
}
override predicate hasArrayInput(int param) {

View File

@@ -55,15 +55,15 @@ class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction {
this.hasName("wcscpy")
) and
(
input.isInParameterPointer(1) and
output.isOutParameterPointer(0)
input.isParameterDeref(1) and
output.isParameterDeref(0)
or
input.isInParameterPointer(1) and
output.isOutReturnPointer()
input.isParameterDeref(1) and
output.isReturnValueDeref()
)
or
input.isInParameter(0) and
output.isOutReturnValue()
input.isParameter(0) and
output.isReturnValue()
}
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
@@ -78,12 +78,12 @@ class StrcpyFunction extends ArrayFunction, DataFlowFunction, TaintFunction {
this.hasName("_wcsncpy_l")
) and
(
input.isInParameter(2) or
input.isInParameterPointer(1)
input.isParameter(2) or
input.isParameterDeref(1)
) and
(
output.isOutParameterPointer(0) or
output.isOutReturnPointer()
output.isParameterDeref(0) or
output.isReturnValueDeref()
)
}
}

View File

@@ -6,13 +6,13 @@ class Strftime extends TaintFunction, ArrayFunction {
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
(
input.isInParameter(1) or
input.isInParameterPointer(2) or
input.isInParameterPointer(3)
input.isParameter(1) or
input.isParameterDeref(2) or
input.isParameterDeref(3)
) and
(
output.isOutParameterPointer(0) or
output.isOutReturnValue()
output.isParameterDeref(0) or
output.isReturnValue()
)
}

View File

@@ -8,10 +8,10 @@ class Swap extends DataFlowFunction {
Swap() { this.hasQualifiedName("std", "swap") }
override predicate hasDataFlow(FunctionInput input, FunctionOutput output) {
input.isInParameterPointer(0) and
output.isOutParameterPointer(1)
input.isParameterDeref(0) and
output.isParameterDeref(1)
or
input.isInParameterPointer(1) and
output.isOutParameterPointer(0)
input.isParameterDeref(1) and
output.isParameterDeref(0)
}
}

View File

@@ -1,11 +1,11 @@
/**
* Provides an abstract class for accurate modeling of input and output buffers
* in library functions when source code is not available. To use this QL
* library, create a QL class extending `BufferFunction` with a characteristic
* library, create a QL class extending `ArrayFunction` with a characteristic
* predicate that selects the function or set of functions you are trying to
* model. Within that class, override the predicates provided by `BufferFunction`
* model. Within that class, override the predicates provided by `ArrayFunction`
* to match the flow within that function. Finally, add a private import
* statement to `CustomModels.qll`
* statement to `Models.qll`
*/
import semmle.code.cpp.Function

View File

@@ -115,7 +115,19 @@ abstract class FormattingFunction extends Function {
* Gets the position of the first format argument, corresponding with
* the first format specifier in the format string.
*/
int getFirstFormatArgumentIndex() { result = getNumberOfParameters() }
int getFirstFormatArgumentIndex() {
result = getNumberOfParameters() and
// the formatting function either has a definition in the snapshot, or all
// `DeclarationEntry`s agree on the number of parameters (otherwise we don't
// really know the correct number)
(
hasDefinition()
or
forall(FunctionDeclarationEntry fde | fde = getADeclarationEntry() |
result = fde.getNumberOfParameters()
)
)
}
/**
* Gets the position of the buffer size argument, if any.

View File

@@ -6,26 +6,106 @@
import semmle.code.cpp.Parameter
/**
* An `int` that is a parameter index for some function. This is needed for binding in certain cases.
*/
class ParameterIndex extends int {
ParameterIndex() { exists(Parameter p | this = p.getIndex()) }
}
newtype TFunctionInput =
private newtype TFunctionInput =
TInParameter(ParameterIndex i) or
TInParameterPointer(ParameterIndex i) or
TInQualifier()
TInParameterDeref(ParameterIndex i) or
TInQualifierObject() or
TInQualifierAddress()
/**
* An input to a function. This can be:
* - The value of one of the function's parameters
* - The value pointed to by one of function's pointer or reference parameters
* - The value of the function's `this` pointer
* - The value pointed to by the function's `this` pointer
*/
class FunctionInput extends TFunctionInput {
abstract string toString();
predicate isInParameter(ParameterIndex index) { none() }
/**
* Holds if this is the input value of the parameter with index `index`.
*
* Example:
* ```
* void func(int n, char* p, float& r);
* ```
* - `isParameter(0)` holds for the `FunctionInput` that represents the value of `n` (with type
* `int`) on entry to the function.
* - `isParameter(1)` holds for the `FunctionInput` that represents the value of `p` (with type
* `char*`) on entry to the function.
* - `isParameter(2)` holds for the `FunctionInput` that represents the "value" of the reference
* `r` (with type `float&`) on entry to the function, _not_ the value of the referred-to
* `float`.
*/
predicate isParameter(ParameterIndex index) { none() }
predicate isInParameterPointer(ParameterIndex index) { none() }
/**
* Holds if this is the input value of the parameter with index `index`.
* DEPRECATED: Use `isParameter(index)` instead.
*/
deprecated final predicate isInParameter(ParameterIndex index) { isParameter(index) }
predicate isInQualifier() { none() }
/**
* Holds if this is the input value pointed to by a pointer parameter to a function, or the input
* value referred to by a reference parameter to a function, where the parameter has index
* `index`.
*
* Example:
* ```
* void func(int n, char* p, float& r);
* ```
* - `isParameterDeref(1)` holds for the `FunctionInput` that represents the value of `*p` (with
* type `char`) on entry to the function.
* - `isParameterDeref(2)` holds for the `FunctionInput` that represents the value of `r` (with type
* `float`) on entry to the function.
* - There is no `FunctionInput` for which `isParameterDeref(0)` holds, because `n` is neither a
* pointer nor a reference.
*/
predicate isParameterDeref(ParameterIndex index) { none() }
/**
* Holds if this is the input value pointed to by a pointer parameter to a function, or the input
* value referred to by a reference parameter to a function, where the parameter has index
* `index`.
* DEPRECATED: Use `isParameterDeref(index)` instead.
*/
deprecated final predicate isInParameterPointer(ParameterIndex index) { isParameterDeref(index) }
/**
* Holds if this is the input value pointed to by the `this` pointer of an instance member
* function.
*
* Example:
* ```
* struct C {
* void mfunc(int n, char* p, float& r) const;
* };
* ```
* - `isQualifierObject()` holds for the `FunctionInput` that represents the value of `*this`
* (with type `C const`) on entry to the function.
*/
predicate isQualifierObject() { none() }
/**
* Holds if this is the input value pointed to by the `this` pointer of an instance member
* function.
* DEPRECATED: Use `isQualifierObject()` instead.
*/
deprecated final predicate isInQualifier() { isQualifierObject() }
/**
* Holds if this is the input value of the `this` pointer of an instance member function.
*
* Example:
* ```
* struct C {
* void mfunc(int n, char* p, float& r) const;
* };
* ```
* - `isQualifierAddress()` holds for the `FunctionInput` that represents the value of `this`
* (with type `C const *`) on entry to the function.
*/
predicate isQualifierAddress() { none() }
}
class InParameter extends FunctionInput, TInParameter {
@@ -35,73 +115,182 @@ class InParameter extends FunctionInput, TInParameter {
override string toString() { result = "InParameter " + index.toString() }
/** Gets the zero-based index of the parameter. */
ParameterIndex getIndex() { result = index }
override predicate isInParameter(ParameterIndex i) { i = index }
override predicate isParameter(ParameterIndex i) { i = index }
}
class InParameterPointer extends FunctionInput, TInParameterPointer {
class InParameterDeref extends FunctionInput, TInParameterDeref {
ParameterIndex index;
InParameterPointer() { this = TInParameterPointer(index) }
InParameterDeref() { this = TInParameterDeref(index) }
override string toString() { result = "InParameterPointer " + index.toString() }
override string toString() { result = "InParameterDeref " + index.toString() }
/** Gets the zero-based index of the parameter. */
ParameterIndex getIndex() { result = index }
override predicate isInParameterPointer(ParameterIndex i) { i = index }
override predicate isParameterDeref(ParameterIndex i) { i = index }
}
class InQualifier extends FunctionInput, TInQualifier {
override string toString() { result = "InQualifier" }
class InQualifierObject extends FunctionInput, TInQualifierObject {
override string toString() { result = "InQualifierObject" }
override predicate isInQualifier() { any() }
override predicate isQualifierObject() { any() }
}
newtype TFunctionOutput =
TOutParameterPointer(ParameterIndex i) or
TOutQualifier() or
class InQualifierAddress extends FunctionInput, TInQualifierAddress {
override string toString() { result = "InQualifierAddress" }
override predicate isQualifierAddress() { any() }
}
private newtype TFunctionOutput =
TOutParameterDeref(ParameterIndex i) or
TOutQualifierObject() or
TOutReturnValue() or
TOutReturnPointer()
TOutReturnValueDeref()
/**
* An output from a function. This can be:
* - The value pointed to by one of function's pointer or reference parameters
* - The value pointed to by the function's `this` pointer
* - The function's return value
* - The value pointed to by the function's return value, if the return value is a pointer or
* reference
*/
class FunctionOutput extends TFunctionOutput {
abstract string toString();
predicate isOutParameterPointer(ParameterIndex i) { none() }
/**
* Holds if this is the output value pointed to by a pointer parameter to a function, or the
* output value referred to by a reference parameter to a function, where the parameter has
* index `index`.
*
* Example:
* ```
* void func(int n, char* p, float& r);
* ```
* - `isParameterDeref(1)` holds for the `FunctionOutput` that represents the value of `*p` (with
* type `char`) on return from the function.
* - `isParameterDeref(2)` holds for the `FunctionOutput` that represents the value of `r` (with
* type `float`) on return from the function.
* - There is no `FunctionOutput` for which `isParameterDeref(0)` holds, because `n` is neither a
* pointer nor a reference.
*/
predicate isParameterDeref(ParameterIndex i) { none() }
predicate isOutQualifier() { none() }
/**
* Holds if this is the output value pointed to by a pointer parameter to a function, or the
* output value referred to by a reference parameter to a function, where the parameter has
* index `index`.
* DEPRECATED: Use `isParameterDeref(index)` instead.
*/
deprecated final predicate isOutParameterPointer(ParameterIndex index) { isParameterDeref(index) }
predicate isOutReturnValue() { none() }
/**
* Holds if this is the output value pointed to by the `this` pointer of an instance member
* function.
*
* Example:
* ```
* struct C {
* void mfunc(int n, char* p, float& r);
* };
* ```
* - `isQualifierObject()` holds for the `FunctionOutput` that represents the value of `*this`
* (with type `C`) on return from the function.
*/
predicate isQualifierObject() { none() }
predicate isOutReturnPointer() { none() }
/**
* Holds if this is the output value pointed to by the `this` pointer of an instance member
* function.
* DEPRECATED: Use `isQualifierObject()` instead.
*/
deprecated final predicate isOutQualifier() { isQualifierObject() }
/**
* Holds if this is the value returned by a function.
*
* Example:
* ```
* int getInt();
* char* getPointer();
* float& getReference();
* ```
* - `isReturnValue()` holds for the `FunctionOutput` that represents the value returned by
* `getInt()` (with type `int`).
* - `isReturnValue()` holds for the `FunctionOutput` that represents the value returned by
* `getPointer()` (with type `char*`).
* - `isReturnValue()` holds for the `FunctionOutput` that represents the "value" of the reference
* returned by `getReference()` (with type `float&`), _not_ the value of the referred-to
* `float`.
*/
predicate isReturnValue() { none() }
/**
* Holds if this is the value returned by a function.
* DEPRECATED: Use `isReturnValue()` instead.
*/
deprecated final predicate isOutReturnValue() { isReturnValue() }
/**
* Holds if this is the output value pointed to by the return value of a function, if the function
* returns a pointer, or the output value referred to by the return value of a function, if the
* function returns a reference.
*
* Example:
* ```
* char* getPointer();
* float& getReference();
* int getInt();
* ```
* - `isReturnValueDeref()` holds for the `FunctionOutput` that represents the value of
* `*getPointer()` (with type `char`).
* - `isReturnValueDeref()` holds for the `FunctionOutput` that represents the value of
* `getReference()` (with type `float`).
* - There is no `FunctionOutput` of `getInt()` for which `isReturnValueDeref()` holds because the
* return type of `getInt()` is neither a pointer nor a reference.
*/
predicate isReturnValueDeref() { none() }
/**
* Holds if this is the output value pointed to by the return value of a function, if the function
* returns a pointer, or the output value referred to by the return value of a function, if the
* function returns a reference.
* DEPRECATED: Use `isReturnValueDeref()` instead.
*/
deprecated final predicate isOutReturnPointer() { isReturnValueDeref() }
}
class OutParameterPointer extends FunctionOutput, TOutParameterPointer {
class OutParameterDeref extends FunctionOutput, TOutParameterDeref {
ParameterIndex index;
OutParameterPointer() { this = TOutParameterPointer(index) }
OutParameterDeref() { this = TOutParameterDeref(index) }
override string toString() { result = "OutParameterPointer " + index.toString() }
override string toString() { result = "OutParameterDeref " + index.toString() }
ParameterIndex getIndex() { result = index }
override predicate isOutParameterPointer(ParameterIndex i) { i = index }
override predicate isParameterDeref(ParameterIndex i) { i = index }
}
class OutQualifier extends FunctionOutput, TOutQualifier {
override string toString() { result = "OutQualifier" }
class OutQualifierObject extends FunctionOutput, TOutQualifierObject {
override string toString() { result = "OutQualifierObject" }
override predicate isOutQualifier() { any() }
override predicate isQualifierObject() { any() }
}
class OutReturnValue extends FunctionOutput, TOutReturnValue {
override string toString() { result = "OutReturnValue" }
override predicate isOutReturnValue() { any() }
override predicate isReturnValue() { any() }
}
class OutReturnPointer extends FunctionOutput, TOutReturnPointer {
override string toString() { result = "OutReturnPointer" }
class OutReturnValueDeref extends FunctionOutput, TOutReturnValueDeref {
override string toString() { result = "OutReturnValueDeref" }
override predicate isOutReturnPointer() { any() }
override predicate isReturnValueDeref() { any() }
}

View File

@@ -9,6 +9,7 @@
import semmle.code.cpp.Function
import semmle.code.cpp.models.Models
import semmle.code.cpp.models.interfaces.FunctionInputsAndOutputs
/**
* Models the side effects of a library function.
@@ -19,12 +20,33 @@ abstract class SideEffectFunction extends Function {
* This memory could be from global variables, or from other memory that was reachable from a
* pointer that was passed into the function.
*/
abstract predicate neverReadsMemory();
abstract predicate hasOnlySpecificReadSideEffects();
/**
* Holds if the function never writes to memory that remains allocated after the function
* returns. This memory could be from global variables, or from other memory that was reachable
* from a pointer that was passed into the function.
*/
abstract predicate neverWritesMemory();
abstract predicate hasOnlySpecificWriteSideEffects();
/**
* Holds if the value pointed to by the parameter at index `i` is written to. `buffer` is true
* if the write may be at an offset. `mustWrite` is true if the write is unconditional.
*/
predicate hasSpecificWriteSideEffect(ParameterIndex i, boolean buffer, boolean mustWrite) {
none()
}
/**
* Holds if the value pointed to by the parameter at index `i` is read from. `buffer` is true
* if the read may be at an offset.
*/
predicate hasSpecificReadSideEffect(ParameterIndex i, boolean buffer) { none() }
// TODO: name?
/**
* Gets the index of the parameter that indicates the size of the buffer pointed to by the
* parameter at index `i`.
*/
ParameterIndex getParameterSizeIndex(ParameterIndex i) { none() }
}

View File

@@ -2,8 +2,8 @@ import cpp
/**
* Align the specified offset up to the specified alignment boundary.
* The result is the smallest integer i such that (i % alignment) = 0
* and (i >= offset)
* The result is the smallest integer `i` such that `(i % alignment) = 0`
* and `(i >= offset)`.
*/
bindingset[offset, alignment]
private int alignUp(int offset, int alignment) {
@@ -30,16 +30,16 @@ abstract class Architecture extends string {
/** Gets the size of a pointer, in bits. */
abstract int pointerSize();
/** Gets the size of a 'long int', in bits. */
/** Gets the size of a `long int`, in bits. */
abstract int longSize();
/** Gets the size of a 'long double', in bits. */
/** Gets the size of a `long double`, in bits. */
abstract int longDoubleSize();
/** Gets the size of a 'long long', in bits. */
/** Gets the size of a `long long`, in bits. */
abstract int longLongSize();
/** Gets the size of a 'wchar_t', in bits. */
/** Gets the size of a `wchar_t`, in bits. */
abstract int wideCharSize();
/** Gets the alignment boundary for doubles, in bits. */
@@ -479,8 +479,10 @@ class PaddedType extends Class {
int typeBitSize(Architecture arch) {
if this instanceof Union
then
// A correct implementation for unions would be
// A correct implementation for unions would be:
// ```
// result = max(fieldSize(_, arch))
// ```
// but that uses a recursive aggregate, which isn't supported in
// QL. We therefore use this slightly more complex implementation
// instead.

View File

@@ -2,7 +2,7 @@
* This library is a clone of semmle.code.cpp.controlflow.SSA, with
* only one difference: extra phi definitions are added after
* guards. For example:
*
* ```
* x = f();
* if (x < 10) {
* // Block 1
@@ -11,12 +11,12 @@
* // Block 2
* ...
* }
*
* ```
* In standard SSA, basic blocks 1 and 2 do not need phi definitions
* for x, because they are dominated by the definition of x on the
* first line. In RangeSSA, however, we add phi definitions for x at
* for `x`, because they are dominated by the definition of `x` on the
* first line. In RangeSSA, however, we add phi definitions for `x` at
* the beginning of blocks 1 and 2. This is useful for range analysis
* because it enables us to deduce a more accurate range for x in the
* because it enables us to deduce a more accurate range for `x` in the
* two branches of the if-statement.
*/
@@ -74,19 +74,19 @@ class RangeSsaDefinition extends ControlFlowNodeBase {
/**
* A string representation of the SSA variable represented by the pair
* (this, v).
* `(this, v)`.
*/
string toString(LocalScopeVariable v) { exists(RangeSSA x | result = x.toString(this, v)) }
/** Gets a use of the SSA variable represented by the pair (this, v) */
/** Gets a use of the SSA variable represented by the pair `(this, v)`. */
VariableAccess getAUse(LocalScopeVariable v) { exists(RangeSSA x | result = x.getAUse(this, v)) }
/** Gets the control flow node for this definition */
/** Gets the control flow node for this definition. */
ControlFlowNode getDefinition() { result = this }
BasicBlock getBasicBlock() { result.contains(getDefinition()) }
/** Whether this definition is a phi node for variable v */
/** Whether this definition is a phi node for variable `v`. */
predicate isPhiNode(LocalScopeVariable v) {
exists(RangeSSA x | x.phi_node(v, this.(BasicBlock)))
}
@@ -136,7 +136,7 @@ class RangeSsaDefinition extends ControlFlowNodeBase {
)
}
/** Gets the expression assigned to this SsaDefinition */
/** Gets the expression assigned to this SsaDefinition. */
Expr getDefiningValue(LocalScopeVariable v) {
exists(ControlFlowNode def | def = this.getDefinition() |
def = v.getInitializer().getExpr() and def = result

View File

@@ -0,0 +1,487 @@
import cpp
import semmle.code.cpp.dataflow.DataFlow
module BoostorgAsio {
/**
* Represents boost::asio::ssl::context enum
*/
class SslContextMethod extends Enum {
SslContextMethod() {
this.getName().toString() = "method" and
this.getQualifiedName().toString().matches("boost::asio::ssl::context%")
}
/**
* returns the value for a banned protocol
*/
EnumConstant getABannedProtocolConstant() {
result = this.getAnEnumConstant() and
(
/// Generic SSL version 2.
result.getName() = "sslv2"
or
/// SSL version 2 client.
result.getName() = "sslv2_client"
or
/// SSL version 2 server.
result.getName() = "sslv2_server"
or
/// Generic SSL version 3.
result.getName() = "sslv3"
or
/// SSL version 3 client.
result.getName() = "sslv3_client"
or
/// SSL version 3 server.
result.getName() = "sslv3_server"
or
/// Generic TLS version 1.
result.getName() = "tlsv1"
or
/// TLS version 1 client.
result.getName() = "tlsv1_client"
or
/// TLS version 1 server.
result.getName() = "tlsv1_server"
or
/// Generic TLS version 1.1.
result.getName() = "tlsv11"
or
/// TLS version 1.1 client.
result.getName() = "tlsv11_client"
or
/// TLS version 1.1 server.
result.getName() = "tlsv11_server"
)
}
/**
* returns the value for a approved protocols, but that are hard-coded (i.e. no protocol negotiation)
*/
EnumConstant getAnApprovedButHardcodedProtocolConstant() {
result = this.getATls12ProtocolConstant()
}
/**
* returns the value for a TLS v1.2 protocol
*/
EnumConstant getATls12ProtocolConstant() {
result = this.getAnEnumConstant() and
(
/// Generic TLS version 1.2.
result.getName() = "tlsv12"
or
/// TLS version 1.2 client.
result.getName() = "tlsv12_client"
or
/// TLS version 1.2 server.
result.getName() = "tlsv12_server"
)
}
/**
* returns the value for a TLS v1.3 protocol
*/
EnumConstant getATls13ProtocolConstant() {
result = this.getAnEnumConstant() and
(
/// Generic TLS version 1.3.
result.getName() = "tlsv13"
or
/// TLS version 1.3 client.
result.getName() = "tlsv13_client"
or
/// TLS version 1.3 server.
result.getName() = "tlsv13_server"
)
}
/**
* returns the value of a generic TLS or SSL/TLS protocol
*/
EnumConstant getAGenericTlsProtocolConstant() {
result = this.getAnEnumConstant() and
(
/// Generic TLS
result.getName() = "tls"
or
/// TLS client.
result.getName() = "tls_client"
or
/// TLS server.
result.getName() = "tls_server"
)
or
result = getASslv23ProtocolConstant()
}
/**
* returns the value of a generic SSL/TLS protocol
*/
EnumConstant getASslv23ProtocolConstant() {
result = this.getAnEnumConstant() and
(
/// OpenSSL - SSLv23 == A TLS/SSL connection established with these methods may understand the SSLv2, SSLv3, TLSv1, TLSv1.1 and TLSv1.2 protocols.
/// Generic SSL/TLS.
result.getName() = "sslv23"
or
/// SSL/TLS client.
result.getName() = "sslv23_client"
or
/// SSL/TLS server.
result.getName() = "sslv23_server"
)
}
}
/**
* NOTE: ignore - Modern versions of OpenSSL do not support SSL v2 anymore, so this option is for backwards compatibility only
*/
int getShiftedSslOptionsNoSsl2() {
// SSL_OP_NO_SSLv2 was removed from modern OpenSSL versions
result = 0
}
/**
* RightShift(16) value for no_sslv3 constant
*/
int getShiftedSslOptionsNoSsl3() {
// SSL_OP_NO_SSLv3 == 0x02000000U
result = 512
}
/**
* RightShift(16) value for no_tlsv1 constant
*/
int getShiftedSslOptionsNoTls1() {
// SSL_OP_NO_TLSv1 == 0x04000000U
result = 1024
}
/**
* RightShift(16) value for no_tlsv1_1 constant
*/
int getShiftedSslOptionsNoTls1_1() {
// SSL_OP_NO_TLSv1_1 == 0x10000000U
result = 4096
}
/**
* RightShift(16) value for no_tlsv1_2 constant
*/
int getShiftedSslOptionsNoTls1_2() {
// SSL_OP_NO_TLSv1_2 == 0x08000000U
result = 2048
}
/**
* RightShift(16) value for no_tlsv1_3 constant
*/
int getShiftedSslOptionsNoTls1_3() {
// SSL_OP_NO_TLSv1_2 == 0x20000000U
result = 8192
}
/**
* Represents boost::asio::ssl::context class
*/
class SslContextClass extends Class {
SslContextClass() { this.getQualifiedName() = "boost::asio::ssl::context" }
ConstructorCall getAContructorCall() {
this.getAConstructor().getACallToThisFunction() = result and
not result.getLocation().getFile().toString().matches("%/boost/asio/%") and
result.fromSource()
}
}
/**
* Represents boost::asio::ssl::context::set_options member function
*/
class SslSetOptionsFunction extends Function {
SslSetOptionsFunction() {
this.getQualifiedName().matches("boost::asio::ssl::context::set_options")
}
}
/**
* holds if the expression represents a banned protocol
*/
predicate isExprBannedBoostProtocol(Expr e) {
exists(Literal va | va = e |
va.getValue().toInt() = 0 or
va.getValue().toInt() = 1 or
va.getValue().toInt() = 2 or
va.getValue().toInt() = 3 or
va.getValue().toInt() = 4 or
va.getValue().toInt() = 5 or
va.getValue().toInt() = 6 or
va.getValue().toInt() = 7 or
va.getValue().toInt() = 8 or
va.getValue().toInt() = 12 or
va.getValue().toInt() = 13 or
va.getValue().toInt() = 14
)
or
exists(VariableAccess va | va = e |
va.getValue().toInt() = 0 or
va.getValue().toInt() = 1 or
va.getValue().toInt() = 2 or
va.getValue().toInt() = 3 or
va.getValue().toInt() = 4 or
va.getValue().toInt() = 5 or
va.getValue().toInt() = 6 or
va.getValue().toInt() = 7 or
va.getValue().toInt() = 8 or
va.getValue().toInt() = 12 or
va.getValue().toInt() = 13 or
va.getValue().toInt() = 14
)
or
exists(EnumConstantAccess eca, SslContextMethod enum | e = eca |
enum.getABannedProtocolConstant().getAnAccess() = eca
)
}
/**
* holds if the expression represents a TLS v1.2 protocol
*/
predicate isExprTls12BoostProtocol(Expr e) {
exists(Literal va | va = e |
(
va.getValue().toInt() = 15 or /// Generic TLS version 1.2.
va.getValue().toInt() = 16 or /// TLS version 1.2 client.
va.getValue().toInt() = 17 /// TLS version 1.2 server.
)
)
or
exists(VariableAccess va | va = e |
(
va.getValue().toInt() = 15 or /// Generic TLS version 1.2.
va.getValue().toInt() = 16 or /// TLS version 1.2 client.
va.getValue().toInt() = 17 /// TLS version 1.2 server.
)
)
or
exists(EnumConstantAccess eca, SslContextMethod enum | e = eca |
enum.getATls12ProtocolConstant().getAnAccess() = eca
)
}
/**
* holds if the expression represents a protocol that requires Crypto Board approval
*/
predicate isExprTls13BoostProtocol(Expr e) {
exists(Literal va | va = e |
(
va.getValue().toInt() = 18 or
va.getValue().toInt() = 19 or
va.getValue().toInt() = 20
)
)
or
exists(VariableAccess va | va = e |
(
va.getValue().toInt() = 18 or
va.getValue().toInt() = 19 or
va.getValue().toInt() = 20
)
)
or
exists(EnumConstantAccess eca, SslContextMethod enum | e = eca |
enum.getATls13ProtocolConstant().getAnAccess() = eca
)
}
/**
* holds if the expression represents a generic TLS or SSL/TLS protocol
*/
predicate isExprTlsBoostProtocol(Expr e) {
exists(Literal va | va = e |
(
va.getValue().toInt() = 9 or /// Generic SSL/TLS.
va.getValue().toInt() = 10 or /// SSL/TLS client.
va.getValue().toInt() = 11 or /// SSL/TLS server.
va.getValue().toInt() = 21 or /// Generic TLS.
va.getValue().toInt() = 22 or /// TLS client.
va.getValue().toInt() = 23 /// TLS server.
)
)
or
exists(VariableAccess va | va = e |
(
va.getValue().toInt() = 9 or /// Generic SSL/TLS.
va.getValue().toInt() = 10 or /// SSL/TLS client.
va.getValue().toInt() = 11 or /// SSL/TLS server.
va.getValue().toInt() = 21 or /// Generic TLS.
va.getValue().toInt() = 22 or /// TLS client.
va.getValue().toInt() = 23 /// TLS server.
)
)
or
exists(EnumConstantAccess eca, SslContextMethod enum | e = eca |
enum.getAGenericTlsProtocolConstant().getAnAccess() = eca
)
}
/**
* holds if the expression represents a generic SSl/TLS protocol
*/
predicate isExprSslV23BoostProtocol(Expr e) {
exists(Literal va | va = e |
(
va.getValue().toInt() = 9 or /// Generic SSL/TLS.
va.getValue().toInt() = 10 or /// SSL/TLS client.
va.getValue().toInt() = 11 /// SSL/TLS server.
)
)
or
exists(VariableAccess va | va = e |
(
va.getValue().toInt() = 9 or /// Generic SSL/TLS.
va.getValue().toInt() = 10 or /// SSL/TLS client.
va.getValue().toInt() = 11 /// SSL/TLS server.
)
)
or
exists(EnumConstantAccess eca, SslContextMethod enum | e = eca |
enum.getASslv23ProtocolConstant().getAnAccess() = eca
)
}
//////////////////////// Dataflow /////////////////////
/**
* Abstract - Protocol value Flows to the first argument of the context constructor
*/
abstract class SslContextCallAbstractConfig extends DataFlow::Configuration {
bindingset[this]
SslContextCallAbstractConfig() { any() }
override predicate isSink(DataFlow::Node sink) {
exists(ConstructorCall cc, SslContextClass c, Expr e | e = sink.asExpr() |
c.getAContructorCall() = cc and
cc.getArgument(0) = e
)
}
}
/**
* any Protocol value Flows to the first argument of the context constructor
*/
class SslContextCallConfig extends SslContextCallAbstractConfig {
SslContextCallConfig() { this = "SslContextCallConfig" }
override predicate isSource(DataFlow::Node source) {
exists(Expr e | e = source.asExpr() |
e.fromSource() and
not e.getLocation().getFile().toString().matches("%/boost/asio/%")
)
}
}
/**
* a banned protocol value Flows to the first argument of the context constructor
*/
class SslContextCallBannedProtocolConfig extends SslContextCallAbstractConfig {
SslContextCallBannedProtocolConfig() { this = "SslContextCallBannedProtocolConfig" }
override predicate isSource(DataFlow::Node source) {
exists(Expr e | e = source.asExpr() |
e.fromSource() and
not e.getLocation().getFile().toString().matches("%/boost/asio/%") and
isExprBannedBoostProtocol(e)
)
}
}
/**
* a TLS 1.2 protocol value Flows to the first argument of the context constructor
*/
class SslContextCallTls12ProtocolConfig extends SslContextCallAbstractConfig {
SslContextCallTls12ProtocolConfig() { this = "SslContextCallTls12ProtocolConfig" }
override predicate isSource(DataFlow::Node source) {
exists(Expr e | e = source.asExpr() |
e.fromSource() and
not e.getLocation().getFile().toString().matches("%/boost/asio/%") and
isExprTls12BoostProtocol(e)
)
}
}
/**
* a TLS 1.3 protocol value Flows to the first argument of the context constructor
*/
class SslContextCallTls13ProtocolConfig extends SslContextCallAbstractConfig {
SslContextCallTls13ProtocolConfig() { this = "SslContextCallTls12ProtocolConfig" }
override predicate isSource(DataFlow::Node source) {
exists(Expr e | e = source.asExpr() |
e.fromSource() and
not e.getLocation().getFile().toString().matches("%/boost/asio/%") and
isExprTls13BoostProtocol(e)
)
}
}
/**
* a generic TLS protocol value Flows to the first argument of the context constructor
*/
class SslContextCallTlsProtocolConfig extends SslContextCallAbstractConfig {
SslContextCallTlsProtocolConfig() { this = "SslContextCallTlsProtocolConfig" }
override predicate isSource(DataFlow::Node source) {
exists(Expr e | e = source.asExpr() |
e.fromSource() and
not e.getLocation().getFile().toString().matches("%/boost/asio/%") and
isExprTlsBoostProtocol(e)
)
}
}
/**
* a context constructor call flows to a call calling SetOptions()
*/
class SslContextFlowsToSetOptionConfig extends DataFlow::Configuration {
SslContextFlowsToSetOptionConfig() { this = "SslContextFlowsToSetOptionConfig" }
override predicate isSource(DataFlow::Node source) {
exists(SslContextClass c, ConstructorCall cc |
cc = source.asExpr() and
c.getAContructorCall() = cc
)
}
override predicate isSink(DataFlow::Node sink) {
exists(FunctionCall fc, SslSetOptionsFunction f, Variable v, VariableAccess va |
va = sink.asExpr()
|
f.getACallToThisFunction() = fc and
v.getAnAccess() = va and
va = fc.getQualifier()
)
}
}
/**
* an option value flows to the 1st parameter of SetOptions()
*/
class SslOptionConfig extends DataFlow::Configuration {
SslOptionConfig() { this = "SslOptionConfig" }
override predicate isSource(DataFlow::Node source) {
exists(Expr e | e = source.asExpr() |
e.fromSource() and
not e.getLocation().getFile().toString().matches("%/boost/asio/%")
)
}
override predicate isSink(DataFlow::Node sink) {
exists(SslSetOptionsFunction f, FunctionCall call |
sink.asExpr() = call.getArgument(0) and
f.getACallToThisFunction() = call and
not sink.getLocation().getFile().toString().matches("%/boost/asio/%")
)
}
}
}

View File

@@ -294,6 +294,8 @@ class IfStmt extends ConditionalStmt, @stmt_if {
* ```
*/
class ConstexprIfStmt extends ConditionalStmt, @stmt_constexpr_if {
override string getCanonicalQLClass() { result = "ConstexprIfStmt" }
/**
* Gets the condition expression of this 'constexpr if' statement.
*
@@ -1645,6 +1647,7 @@ class EnumSwitch extends SwitchStmt {
* } catch (std::exception &e) {
* g();
* }
* ```
* there is a handler that's associated with the `catch` block and controls
* entry to it.
*/

View File

@@ -729,6 +729,18 @@ private predicate mk_AlignofExpr(HashCons child, AlignofExprOperator e) {
child = hashCons(e.getAChild())
}
/**
* Gets the hash cons of field initializer expressions [0..i), where i > 0, for
* the class aggregate literal `cal` of type `c`, where `head` is the hash cons
* of the i'th initializer expression.
*/
HC_Fields aggInitExprsUpTo(ClassAggregateLiteral cal, Class c, int i) {
exists(Field f, HashCons head, HC_Fields tail |
result = HC_FieldCons(c, i - 1, f, head, tail) and
mk_FieldCons(c, i - 1, f, head, tail, cal)
)
}
private predicate mk_FieldCons(
Class c, int i, Field f, HashCons hc, HC_Fields hcf, ClassAggregateLiteral cal
) {
@@ -738,12 +750,8 @@ private predicate mk_FieldCons(
e = cal.getFieldExpr(f).getFullyConverted() and
f.getInitializationOrder() = i and
(
exists(HashCons head, Field f2, HC_Fields tail |
hc = hashCons(e) and
hcf = HC_FieldCons(c, i - 1, f2, head, tail) and
f2.getInitializationOrder() = i - 1 and
mk_FieldCons(c, i - 1, f2, head, tail, cal)
)
hc = hashCons(e) and
hcf = aggInitExprsUpTo(cal, c, i)
or
hc = hashCons(e) and
i = 0 and
@@ -766,14 +774,7 @@ private predicate mk_ClassAggregateLiteral(Class c, HC_Fields hcf, ClassAggregat
analyzableClassAggregateLiteral(cal) and
c = cal.getUnspecifiedType() and
(
exists(HC_Fields tail, Expr e, Field f, int numChildren, HashCons eCons |
f.getInitializationOrder() = cal.getNumChild() - 1 and
e = cal.getFieldExpr(f).getFullyConverted() and
eCons = hashCons(e) and
numChildren = cal.getNumChild() and
hcf = HC_FieldCons(c, numChildren - 1, f, eCons, tail) and
mk_FieldCons(c, numChildren - 1, f, eCons, tail, cal)
)
hcf = aggInitExprsUpTo(cal, c, cal.getNumChild())
or
cal.getNumChild() = 0 and
hcf = HC_EmptyFields(c)
@@ -785,15 +786,23 @@ private predicate analyzableArrayAggregateLiteral(ArrayAggregateLiteral aal) {
strictcount(aal.getUnspecifiedType()) = 1
}
/**
* Gets the hash cons of array elements in [0..i), where i > 0, for
* the array aggregate literal `aal` of type `t`.
*/
private HC_Array arrayElemsUpTo(ArrayAggregateLiteral aal, Type t, int i) {
exists(HC_Array tail, HashCons head |
result = HC_ArrayCons(t, i - 1, head, tail) and
mk_ArrayCons(t, i - 1, head, tail, aal)
)
}
private predicate mk_ArrayCons(Type t, int i, HashCons hc, HC_Array hca, ArrayAggregateLiteral aal) {
analyzableArrayAggregateLiteral(aal) and
t = aal.getUnspecifiedType() and
hc = hashCons(aal.getChild(i)) and
(
exists(HC_Array tail, HashCons head |
hca = HC_ArrayCons(t, i - 1, head, tail) and
mk_ArrayCons(t, i - 1, head, tail, aal)
)
hca = arrayElemsUpTo(aal, t, i)
or
i = 0 and
hca = HC_EmptyArray(t)

View File

@@ -105,7 +105,7 @@ compilation_time(
*/
#keyset[compilation, file_number, file_number_diagnostic_number]
diagnostic_for(
unique int diagnostic : @diagnostic ref,
int diagnostic : @diagnostic ref,
int compilation : @compilation ref,
int file_number : int ref,
int file_number_diagnostic_number : int ref
@@ -422,8 +422,9 @@ function_defaulted(unique int id: @function ref);
#keyset[id, type_id]
fun_decls(
unique int id: @fun_decl,
int id: @fun_decl,
int function: @function ref,
int type_id: @type ref,
string name: string ref,
@@ -460,8 +461,9 @@ param_decl_bind(
int fun_decl: @fun_decl ref
);
#keyset[id, type_id]
var_decls(
unique int id: @var_decl,
int id: @var_decl,
int variable: @variable ref,
int type_id: @type ref,
string name: string ref,
@@ -521,18 +523,21 @@ params(
overrides(int new: @function ref, int old: @function ref);
#keyset[id, type_id]
membervariables(
unique int id: @membervariable,
int id: @membervariable,
int type_id: @type ref,
string name: string ref
);
#keyset[id, type_id]
globalvariables(
unique int id: @globalvariable,
int id: @globalvariable,
int type_id: @type ref,
string name: string ref
);
#keyset[id, type_id]
localvariables(
int id: @localvariable,
int type_id: @type ref,
@@ -675,7 +680,7 @@ decltypes(
| 2 = class
| 3 = union
| 4 = enum
| 5 = typedef
| 5 = typedef // classic C: typedef typedef type name
| 6 = template
| 7 = template_parameter
| 8 = template_template_parameter
@@ -684,6 +689,7 @@ decltypes(
// ... 11 objc_protocol deprecated
// ... 12 objc_category deprecated
| 13 = scoped_enum
| 14 = using_alias // a using name = type style typedef
;
*/
usertypes(
@@ -1060,10 +1066,12 @@ compgenerated(unique int id: @element ref);
* destructed in reverse construction order, so for a given `element`
* these should be called from highest to lowest `i`.
*/
#keyset[element, destructor_call]
#keyset[element, i]
synthetic_destructor_call(
int element: @element ref,
int i: int ref,
unique int destructor_call: @routineexpr ref
int destructor_call: @routineexpr ref
);
namespaces(
@@ -1509,6 +1517,7 @@ case @expr.kind of
| 322 = @builtinaddressof
| 323 = @vec_fill
| 324 = @builtinconvertvector
| 325 = @builtincomplex
;
new_allocated_type(

File diff suppressed because it is too large Load Diff