mirror of
https://github.com/github/codeql.git
synced 2026-07-06 12:05:31 +02:00
Merge branch 'main' into rdmarsh2/cpp/gvn-functions
This commit is contained in:
@@ -0,0 +1,13 @@
|
||||
class Expr extends @expr {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
class Location extends @location_expr {
|
||||
string toString() { none() }
|
||||
}
|
||||
|
||||
from Expr expr, int kind, int kind_new, Location location
|
||||
where
|
||||
exprs(expr, kind, location) and
|
||||
if expr instanceof @blockassignexpr then kind_new = 0 else kind_new = kind
|
||||
select expr, kind_new, location
|
||||
2131
cpp/downgrades/73af5058c6899dcdb05754c27ca966aeb3a68c94/old.dbscheme
Normal file
2131
cpp/downgrades/73af5058c6899dcdb05754c27ca966aeb3a68c94/old.dbscheme
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,3 @@
|
||||
description: Support block assignment
|
||||
compatibility: partial
|
||||
exprs.rel: run exprs.qlo
|
||||
2136
cpp/downgrades/f96ad9b2da43bbc9e55a72a165febd270ae07981/old.dbscheme
Normal file
2136
cpp/downgrades/f96ad9b2da43bbc9e55a72a165febd270ae07981/old.dbscheme
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,3 @@
|
||||
description: Add relation for orphaned local variables
|
||||
compatibility: full
|
||||
orphaned_variables.rel: delete
|
||||
@@ -1,3 +1,15 @@
|
||||
## 0.3.3
|
||||
|
||||
### New Features
|
||||
|
||||
* Added a predicate `getValueConstant` to `AttributeArgument` that yields the argument value as an `Expr` when the value is a constant expression.
|
||||
* A new class predicate `MustFlowConfiguration::allowInterproceduralFlow` has been added to the `semmle.code.cpp.ir.dataflow.MustFlow` library. The new predicate can be overridden to disable interprocedural flow.
|
||||
* Added subclasses of `BuiltInOperations` for `__builtin_bit_cast`, `__builtin_shuffle`, `__has_unique_object_representations`, `__is_aggregate`, and `__is_assignable`.
|
||||
|
||||
### Major Analysis Improvements
|
||||
|
||||
* The IR dataflow library now includes flow through global variables. This enables new findings in many scenarios.
|
||||
|
||||
## 0.3.2
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: majorAnalysis
|
||||
---
|
||||
* The IR dataflow library now includes flow through global variables. This enables new findings in many scenarios.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: feature
|
||||
---
|
||||
* Added subclasses of `BuiltInOperations` for `__builtin_bit_cast`, `__builtin_shuffle`, `__has_unique_object_representations`, `__is_aggregate`, and `__is_assignable`.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: feature
|
||||
---
|
||||
* A new class predicate `MustFlowConfiguration::allowInterproceduralFlow` has been added to the `semmle.code.cpp.ir.dataflow.MustFlow` library. The new predicate can be overridden to disable interprocedural flow.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: feature
|
||||
---
|
||||
* Added a predicate `getValueConstant` to `AttributeArgument` that yields the argument value as an `Expr` when the value is a constant expression.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: feature
|
||||
---
|
||||
* Added a `BlockAssignExpr` class, which models a `memcpy`-like operation used in compiler generated copy/move constructors and assignment operations.
|
||||
@@ -0,0 +1,6 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* All deprecated predicates/classes/modules that have been deprecated for over a year have been
|
||||
deleted.
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: feature
|
||||
---
|
||||
* Added support for getting the link targets of global and namespace variables.
|
||||
5
cpp/ql/lib/change-notes/2022-08-22-xml-rename.md
Normal file
5
cpp/ql/lib/change-notes/2022-08-22-xml-rename.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
category: deprecated
|
||||
---
|
||||
* Many classes/predicates/modules with upper-case acronyms in their name have been renamed to follow our style-guide.
|
||||
The old name still exists as a deprecated alias.
|
||||
11
cpp/ql/lib/change-notes/released/0.3.3.md
Normal file
11
cpp/ql/lib/change-notes/released/0.3.3.md
Normal file
@@ -0,0 +1,11 @@
|
||||
## 0.3.3
|
||||
|
||||
### New Features
|
||||
|
||||
* Added a predicate `getValueConstant` to `AttributeArgument` that yields the argument value as an `Expr` when the value is a constant expression.
|
||||
* A new class predicate `MustFlowConfiguration::allowInterproceduralFlow` has been added to the `semmle.code.cpp.ir.dataflow.MustFlow` library. The new predicate can be overridden to disable interprocedural flow.
|
||||
* Added subclasses of `BuiltInOperations` for `__builtin_bit_cast`, `__builtin_shuffle`, `__has_unique_object_representations`, `__is_aggregate`, and `__is_assignable`.
|
||||
|
||||
### Major Analysis Improvements
|
||||
|
||||
* The IR dataflow library now includes flow through global variables. This enables new findings in many scenarios.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.3.2
|
||||
lastReleaseVersion: 0.3.3
|
||||
|
||||
@@ -119,27 +119,67 @@ module SemanticExprConfig {
|
||||
result = block.getDisplayIndex()
|
||||
}
|
||||
|
||||
class SsaVariable instanceof IR::Instruction {
|
||||
SsaVariable() { super.hasMemoryResult() }
|
||||
newtype TSsaVariable =
|
||||
TSsaInstruction(IR::Instruction instr) { instr.hasMemoryResult() } or
|
||||
TSsaOperand(IR::Operand op) { op.isDefinitionInexact() }
|
||||
|
||||
final string toString() { result = super.toString() }
|
||||
class SsaVariable extends TSsaVariable {
|
||||
string toString() { none() }
|
||||
|
||||
final Location getLocation() { result = super.getLocation() }
|
||||
Location getLocation() { none() }
|
||||
|
||||
IR::Instruction asInstruction() { none() }
|
||||
|
||||
IR::Operand asOperand() { none() }
|
||||
}
|
||||
|
||||
predicate explicitUpdate(SsaVariable v, Expr sourceExpr) { v = sourceExpr }
|
||||
class SsaInstructionVariable extends SsaVariable, TSsaInstruction {
|
||||
IR::Instruction instr;
|
||||
|
||||
predicate phi(SsaVariable v) { v instanceof IR::PhiInstruction }
|
||||
SsaInstructionVariable() { this = TSsaInstruction(instr) }
|
||||
|
||||
SsaVariable getAPhiInput(SsaVariable v) { result = v.(IR::PhiInstruction).getAnInput() }
|
||||
final override string toString() { result = instr.toString() }
|
||||
|
||||
Expr getAUse(SsaVariable v) { result.(IR::LoadInstruction).getSourceValue() = v }
|
||||
final override Location getLocation() { result = instr.getLocation() }
|
||||
|
||||
final override IR::Instruction asInstruction() { result = instr }
|
||||
}
|
||||
|
||||
class SsaOperand extends SsaVariable, TSsaOperand {
|
||||
IR::Operand op;
|
||||
|
||||
SsaOperand() { this = TSsaOperand(op) }
|
||||
|
||||
final override string toString() { result = op.toString() }
|
||||
|
||||
final override Location getLocation() { result = op.getLocation() }
|
||||
|
||||
final override IR::Operand asOperand() { result = op }
|
||||
}
|
||||
|
||||
predicate explicitUpdate(SsaVariable v, Expr sourceExpr) { v.asInstruction() = sourceExpr }
|
||||
|
||||
predicate phi(SsaVariable v) { v.asInstruction() instanceof IR::PhiInstruction }
|
||||
|
||||
SsaVariable getAPhiInput(SsaVariable v) {
|
||||
exists(IR::PhiInstruction instr |
|
||||
result.asInstruction() = instr.getAnInput()
|
||||
or
|
||||
result.asOperand() = instr.getAnInputOperand()
|
||||
)
|
||||
}
|
||||
|
||||
Expr getAUse(SsaVariable v) { result.(IR::LoadInstruction).getSourceValue() = v.asInstruction() }
|
||||
|
||||
SemType getSsaVariableType(SsaVariable v) {
|
||||
result = getSemanticType(v.(IR::Instruction).getResultIRType())
|
||||
result = getSemanticType(v.asInstruction().getResultIRType())
|
||||
}
|
||||
|
||||
BasicBlock getSsaVariableBasicBlock(SsaVariable v) { result = v.(IR::Instruction).getBlock() }
|
||||
BasicBlock getSsaVariableBasicBlock(SsaVariable v) {
|
||||
result = v.asInstruction().getBlock()
|
||||
or
|
||||
result = v.asOperand().getUse().getBlock()
|
||||
}
|
||||
|
||||
private newtype TReadPosition =
|
||||
TReadPositionBlock(IR::IRBlock block) or
|
||||
@@ -169,7 +209,9 @@ module SemanticExprConfig {
|
||||
|
||||
final override predicate hasRead(SsaVariable v) {
|
||||
exists(IR::Operand operand |
|
||||
operand.getDef() = v and not operand instanceof IR::PhiInputOperand
|
||||
operand.getDef() = v.asInstruction() and
|
||||
not operand instanceof IR::PhiInputOperand and
|
||||
operand.getUse().getBlock() = block
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -186,7 +228,7 @@ module SemanticExprConfig {
|
||||
|
||||
final override predicate hasRead(SsaVariable v) {
|
||||
exists(IR::PhiInputOperand operand |
|
||||
operand.getDef() = v and
|
||||
operand.getDef() = v.asInstruction() and
|
||||
operand.getPredecessorBlock() = pred and
|
||||
operand.getUse().getBlock() = succ
|
||||
)
|
||||
@@ -205,17 +247,16 @@ module SemanticExprConfig {
|
||||
exists(IR::PhiInputOperand operand |
|
||||
pos = TReadPositionPhiInputEdge(operand.getPredecessorBlock(), operand.getUse().getBlock())
|
||||
|
|
||||
phi = operand.getUse() and input = operand.getDef()
|
||||
phi.asInstruction() = operand.getUse() and
|
||||
(
|
||||
input.asInstruction() = operand.getDef()
|
||||
or
|
||||
input.asOperand() = operand
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
class Bound instanceof IRBound::Bound {
|
||||
Bound() {
|
||||
this instanceof IRBound::ZeroBound
|
||||
or
|
||||
this.(IRBound::ValueNumberBound).getValueNumber().getAnInstruction() instanceof SsaVariable
|
||||
}
|
||||
|
||||
string toString() { result = super.toString() }
|
||||
|
||||
final Location getLocation() { result = super.getLocation() }
|
||||
@@ -228,13 +269,13 @@ module SemanticExprConfig {
|
||||
|
||||
override string toString() {
|
||||
result =
|
||||
min(SsaVariable instr |
|
||||
instr = bound.getValueNumber().getAnInstruction()
|
||||
min(SsaVariable v |
|
||||
v.asInstruction() = bound.getValueNumber().getAnInstruction()
|
||||
|
|
||||
instr
|
||||
v
|
||||
order by
|
||||
instr.(IR::Instruction).getBlock().getDisplayIndex(),
|
||||
instr.(IR::Instruction).getDisplayIndexInBlock()
|
||||
v.asInstruction().getBlock().getDisplayIndex(),
|
||||
v.asInstruction().getDisplayIndexInBlock()
|
||||
).toString()
|
||||
}
|
||||
}
|
||||
@@ -242,7 +283,7 @@ module SemanticExprConfig {
|
||||
predicate zeroBound(Bound bound) { bound instanceof IRBound::ZeroBound }
|
||||
|
||||
predicate ssaBound(Bound bound, SsaVariable v) {
|
||||
v = bound.(IRBound::ValueNumberBound).getValueNumber().getAnInstruction()
|
||||
v.asInstruction() = bound.(IRBound::ValueNumberBound).getValueNumber().getAnInstruction()
|
||||
}
|
||||
|
||||
Expr getBoundExpr(Bound bound, int delta) {
|
||||
@@ -251,22 +292,20 @@ module SemanticExprConfig {
|
||||
|
||||
class Guard = IRGuards::IRGuardCondition;
|
||||
|
||||
predicate guard(Guard guard, BasicBlock block) {
|
||||
block = guard.(IRGuards::IRGuardCondition).getBlock()
|
||||
}
|
||||
predicate guard(Guard guard, BasicBlock block) { block = guard.getBlock() }
|
||||
|
||||
Expr getGuardAsExpr(Guard guard) { result = guard }
|
||||
|
||||
predicate equalityGuard(Guard guard, Expr e1, Expr e2, boolean polarity) {
|
||||
guard.(IRGuards::IRGuardCondition).comparesEq(e1.getAUse(), e2.getAUse(), 0, true, polarity)
|
||||
guard.comparesEq(e1.getAUse(), e2.getAUse(), 0, true, polarity)
|
||||
}
|
||||
|
||||
predicate guardDirectlyControlsBlock(Guard guard, BasicBlock controlled, boolean branch) {
|
||||
guard.(IRGuards::IRGuardCondition).controls(controlled, branch)
|
||||
guard.controls(controlled, branch)
|
||||
}
|
||||
|
||||
predicate guardHasBranchEdge(Guard guard, BasicBlock bb1, BasicBlock bb2, boolean branch) {
|
||||
guard.(IRGuards::IRGuardCondition).controlsEdge(bb1, bb2, branch)
|
||||
guard.controlsEdge(bb1, bb2, branch)
|
||||
}
|
||||
|
||||
Guard comparisonGuard(Expr e) { result = e }
|
||||
@@ -284,9 +323,13 @@ SemBasicBlock getSemanticBasicBlock(IR::IRBlock block) { result = block }
|
||||
|
||||
IR::IRBlock getCppBasicBlock(SemBasicBlock block) { block = result }
|
||||
|
||||
SemSsaVariable getSemanticSsaVariable(IR::Instruction instr) { result = instr }
|
||||
SemSsaVariable getSemanticSsaVariable(IR::Instruction instr) {
|
||||
result.(SemanticExprConfig::SsaVariable).asInstruction() = instr
|
||||
}
|
||||
|
||||
IR::Instruction getCppSsaVariableInstruction(SemSsaVariable v) { v = result }
|
||||
IR::Instruction getCppSsaVariableInstruction(SemSsaVariable var) {
|
||||
var.(SemanticExprConfig::SsaVariable).asInstruction() = result
|
||||
}
|
||||
|
||||
SemBound getSemanticBound(IRBound::Bound bound) { result = bound }
|
||||
|
||||
|
||||
@@ -160,6 +160,7 @@ private predicate phiModulusInit(SemSsaPhiNode phi, SemBound b, int val, int mod
|
||||
/**
|
||||
* Holds if all inputs to `phi` numbered `1` to `rix` are equal to `b + val` modulo `mod`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate phiModulusRankStep(SemSsaPhiNode phi, SemBound b, int val, int mod, int rix) {
|
||||
rix = 0 and
|
||||
phiModulusInit(phi, b, val, mod)
|
||||
@@ -169,7 +170,7 @@ private predicate phiModulusRankStep(SemSsaPhiNode phi, SemBound b, int val, int
|
||||
val = remainder(v1, mod)
|
||||
|
|
||||
exists(int v2, int m2 |
|
||||
rankedPhiInput(phi, inp, edge, rix) and
|
||||
rankedPhiInput(pragma[only_bind_out](phi), inp, edge, rix) and
|
||||
phiModulusRankStep(phi, b, v1, m1, rix - 1) and
|
||||
ssaModulus(inp, edge, b, v2, m2) and
|
||||
mod = m1.gcd(m2).gcd(v1 - v2)
|
||||
|
||||
@@ -342,7 +342,10 @@ private class ConvertOrBoxExpr extends SemUnaryExpr {
|
||||
* A cast that can be ignored for the purpose of range analysis.
|
||||
*/
|
||||
private class SafeCastExpr extends ConvertOrBoxExpr {
|
||||
SafeCastExpr() { conversionCannotOverflow(getTrackedType(getOperand()), getTrackedType(this)) }
|
||||
SafeCastExpr() {
|
||||
conversionCannotOverflow(getTrackedType(pragma[only_bind_into](getOperand())),
|
||||
getTrackedType(this))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -189,9 +189,12 @@ private class BinarySignExpr extends FlowSignExpr {
|
||||
BinarySignExpr() { binary = this }
|
||||
|
||||
override Sign getSignRestriction() {
|
||||
result =
|
||||
semExprSign(binary.getLeftOperand())
|
||||
.applyBinaryOp(semExprSign(binary.getRightOperand()), binary.getOpcode())
|
||||
exists(SemExpr left, SemExpr right |
|
||||
binaryExprOperands(binary, left, right) and
|
||||
result =
|
||||
semExprSign(pragma[only_bind_out](left))
|
||||
.applyBinaryOp(semExprSign(pragma[only_bind_out](right)), binary.getOpcode())
|
||||
)
|
||||
or
|
||||
exists(SemDivExpr div | div = binary |
|
||||
result = semExprSign(div.getLeftOperand()) and
|
||||
@@ -201,6 +204,10 @@ private class BinarySignExpr extends FlowSignExpr {
|
||||
}
|
||||
}
|
||||
|
||||
private predicate binaryExprOperands(SemBinaryExpr binary, SemExpr left, SemExpr right) {
|
||||
binary.getLeftOperand() = left and binary.getRightOperand() = right
|
||||
}
|
||||
|
||||
/**
|
||||
* A `Convert`, `Box`, or `Unbox` expression.
|
||||
*/
|
||||
@@ -221,7 +228,7 @@ private class UnarySignExpr extends FlowSignExpr {
|
||||
UnarySignExpr() { unary = this and not this instanceof SemCastExpr }
|
||||
|
||||
override Sign getSignRestriction() {
|
||||
result = semExprSign(unary.getOperand()).applyUnaryOp(unary.getOpcode())
|
||||
result = semExprSign(pragma[only_bind_out](unary.getOperand())).applyUnaryOp(unary.getOpcode())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-all
|
||||
version: 0.3.3-dev
|
||||
version: 0.3.4-dev
|
||||
groups: cpp
|
||||
dbscheme: semmlecode.cpp.dbscheme
|
||||
extractor: cpp
|
||||
|
||||
@@ -218,8 +218,6 @@ class Folder extends Container, @folder {
|
||||
class File extends Container, @file {
|
||||
override string getAbsolutePath() { files(underlyingElement(this), result) }
|
||||
|
||||
override string toString() { result = Container.super.toString() }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "File" }
|
||||
|
||||
override Location getLocation() {
|
||||
|
||||
@@ -41,6 +41,15 @@ class LinkTarget extends @link_target {
|
||||
* translation units which contributed to this link target.
|
||||
*/
|
||||
Class getAClass() { link_parent(unresolveElement(result), this) }
|
||||
|
||||
/**
|
||||
* Gets a global or namespace variable which was compiled into this
|
||||
* link target, or had its declaration included by one of the translation
|
||||
* units which contributed to this link target.
|
||||
*/
|
||||
GlobalOrNamespaceVariable getAGlobalOrNamespaceVariable() {
|
||||
link_parent(unresolveElement(result), this)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -398,6 +398,8 @@ class LocalVariable extends LocalScopeVariable, @localvariable {
|
||||
exists(DeclStmt s | s.getADeclaration() = this and s.getEnclosingFunction() = result)
|
||||
or
|
||||
exists(ConditionDeclExpr e | e.getVariable() = this and e.getEnclosingFunction() = result)
|
||||
or
|
||||
orphaned_variables(underlyingElement(this), unresolveElement(result))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -471,6 +473,9 @@ class GlobalOrNamespaceVariable extends Variable, @globalvariable {
|
||||
override Type getType() { globalvariables(underlyingElement(this), unresolveElement(result), _) }
|
||||
|
||||
override Element getEnclosingElement() { none() }
|
||||
|
||||
/** Gets a link target which compiled or referenced this global or namespace variable. */
|
||||
LinkTarget getALinkTarget() { this = result.getAGlobalOrNamespaceVariable() }
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
107
cpp/ql/lib/semmle/code/cpp/XML.qll
Executable file → Normal file
107
cpp/ql/lib/semmle/code/cpp/XML.qll
Executable file → Normal file
@@ -8,7 +8,7 @@ private class TXmlLocatable =
|
||||
@xmldtd or @xmlelement or @xmlattribute or @xmlnamespace or @xmlcomment or @xmlcharacters;
|
||||
|
||||
/** An XML element that has a location. */
|
||||
class XMLLocatable extends @xmllocatable, TXmlLocatable {
|
||||
class XmlLocatable extends @xmllocatable, TXmlLocatable {
|
||||
/** Gets the source location for this element. */
|
||||
Location getLocation() { xmllocations(this, result) }
|
||||
|
||||
@@ -32,13 +32,16 @@ class XMLLocatable extends @xmllocatable, TXmlLocatable {
|
||||
string toString() { none() } // overridden in subclasses
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for XmlLocatable */
|
||||
deprecated class XMLLocatable = XmlLocatable;
|
||||
|
||||
/**
|
||||
* An `XMLParent` is either an `XMLElement` or an `XMLFile`,
|
||||
* An `XmlParent` is either an `XmlElement` or an `XmlFile`,
|
||||
* both of which can contain other elements.
|
||||
*/
|
||||
class XMLParent extends @xmlparent {
|
||||
XMLParent() {
|
||||
// explicitly restrict `this` to be either an `XMLElement` or an `XMLFile`;
|
||||
class XmlParent extends @xmlparent {
|
||||
XmlParent() {
|
||||
// explicitly restrict `this` to be either an `XmlElement` or an `XmlFile`;
|
||||
// the type `@xmlparent` currently also includes non-XML files
|
||||
this instanceof @xmlelement or xmlEncoding(this, _)
|
||||
}
|
||||
@@ -50,28 +53,28 @@ class XMLParent extends @xmlparent {
|
||||
string getName() { none() } // overridden in subclasses
|
||||
|
||||
/** Gets the file to which this XML parent belongs. */
|
||||
XMLFile getFile() { result = this or xmlElements(this, _, _, _, result) }
|
||||
XmlFile getFile() { result = this or xmlElements(this, _, _, _, result) }
|
||||
|
||||
/** Gets the child element at a specified index of this XML parent. */
|
||||
XMLElement getChild(int index) { xmlElements(result, _, this, index, _) }
|
||||
XmlElement getChild(int index) { xmlElements(result, _, this, index, _) }
|
||||
|
||||
/** Gets a child element of this XML parent. */
|
||||
XMLElement getAChild() { xmlElements(result, _, this, _, _) }
|
||||
XmlElement getAChild() { xmlElements(result, _, this, _, _) }
|
||||
|
||||
/** Gets a child element of this XML parent with the given `name`. */
|
||||
XMLElement getAChild(string name) { xmlElements(result, _, this, _, _) and result.hasName(name) }
|
||||
XmlElement getAChild(string name) { xmlElements(result, _, this, _, _) and result.hasName(name) }
|
||||
|
||||
/** Gets a comment that is a child of this XML parent. */
|
||||
XMLComment getAComment() { xmlComments(result, _, this, _) }
|
||||
XmlComment getAComment() { xmlComments(result, _, this, _) }
|
||||
|
||||
/** Gets a character sequence that is a child of this XML parent. */
|
||||
XMLCharacters getACharactersSet() { xmlChars(result, _, this, _, _, _) }
|
||||
XmlCharacters getACharactersSet() { xmlChars(result, _, this, _, _, _) }
|
||||
|
||||
/** Gets the depth in the tree. (Overridden in XMLElement.) */
|
||||
/** Gets the depth in the tree. (Overridden in XmlElement.) */
|
||||
int getDepth() { result = 0 }
|
||||
|
||||
/** Gets the number of child XML elements of this XML parent. */
|
||||
int getNumberOfChildren() { result = count(XMLElement e | xmlElements(e, _, this, _, _)) }
|
||||
int getNumberOfChildren() { result = count(XmlElement e | xmlElements(e, _, this, _, _)) }
|
||||
|
||||
/** Gets the number of places in the body of this XML parent where text occurs. */
|
||||
int getNumberOfCharacterSets() { result = count(int pos | xmlChars(_, _, this, pos, _, _)) }
|
||||
@@ -92,9 +95,12 @@ class XMLParent extends @xmlparent {
|
||||
string toString() { result = this.getName() }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for XmlParent */
|
||||
deprecated class XMLParent = XmlParent;
|
||||
|
||||
/** An XML file. */
|
||||
class XMLFile extends XMLParent, File {
|
||||
XMLFile() { xmlEncoding(this, _) }
|
||||
class XmlFile extends XmlParent, File {
|
||||
XmlFile() { xmlEncoding(this, _) }
|
||||
|
||||
/** Gets a printable representation of this XML file. */
|
||||
override string toString() { result = this.getName() }
|
||||
@@ -120,15 +126,21 @@ class XMLFile extends XMLParent, File {
|
||||
string getEncoding() { xmlEncoding(this, result) }
|
||||
|
||||
/** Gets the XML file itself. */
|
||||
override XMLFile getFile() { result = this }
|
||||
override XmlFile getFile() { result = this }
|
||||
|
||||
/** Gets a top-most element in an XML file. */
|
||||
XMLElement getARootElement() { result = this.getAChild() }
|
||||
XmlElement getARootElement() { result = this.getAChild() }
|
||||
|
||||
/** Gets a DTD associated with this XML file. */
|
||||
XMLDTD getADTD() { xmlDTDs(result, _, _, _, this) }
|
||||
XmlDtd getADtd() { xmlDTDs(result, _, _, _, this) }
|
||||
|
||||
/** DEPRECATED: Alias for getADtd */
|
||||
deprecated XmlDtd getADTD() { result = this.getADtd() }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for XmlFile */
|
||||
deprecated class XMLFile = XmlFile;
|
||||
|
||||
/**
|
||||
* An XML document type definition (DTD).
|
||||
*
|
||||
@@ -140,7 +152,7 @@ class XMLFile extends XMLParent, File {
|
||||
* <!ELEMENT lastName (#PCDATA)>
|
||||
* ```
|
||||
*/
|
||||
class XMLDTD extends XMLLocatable, @xmldtd {
|
||||
class XmlDtd extends XmlLocatable, @xmldtd {
|
||||
/** Gets the name of the root element of this DTD. */
|
||||
string getRoot() { xmlDTDs(this, result, _, _, _) }
|
||||
|
||||
@@ -154,7 +166,7 @@ class XMLDTD extends XMLLocatable, @xmldtd {
|
||||
predicate isPublic() { not xmlDTDs(this, _, "", _, _) }
|
||||
|
||||
/** Gets the parent of this DTD. */
|
||||
XMLParent getParent() { xmlDTDs(this, _, _, _, result) }
|
||||
XmlParent getParent() { xmlDTDs(this, _, _, _, result) }
|
||||
|
||||
override string toString() {
|
||||
this.isPublic() and
|
||||
@@ -165,6 +177,9 @@ class XMLDTD extends XMLLocatable, @xmldtd {
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for XmlDtd */
|
||||
deprecated class XMLDTD = XmlDtd;
|
||||
|
||||
/**
|
||||
* An XML element in an XML file.
|
||||
*
|
||||
@@ -176,7 +191,7 @@ class XMLDTD extends XMLLocatable, @xmldtd {
|
||||
* </manifest>
|
||||
* ```
|
||||
*/
|
||||
class XMLElement extends @xmlelement, XMLParent, XMLLocatable {
|
||||
class XmlElement extends @xmlelement, XmlParent, XmlLocatable {
|
||||
/** Holds if this XML element has the given `name`. */
|
||||
predicate hasName(string name) { name = this.getName() }
|
||||
|
||||
@@ -184,10 +199,10 @@ class XMLElement extends @xmlelement, XMLParent, XMLLocatable {
|
||||
override string getName() { xmlElements(this, result, _, _, _) }
|
||||
|
||||
/** Gets the XML file in which this XML element occurs. */
|
||||
override XMLFile getFile() { xmlElements(this, _, _, _, result) }
|
||||
override XmlFile getFile() { xmlElements(this, _, _, _, result) }
|
||||
|
||||
/** Gets the parent of this XML element. */
|
||||
XMLParent getParent() { xmlElements(this, _, result, _, _) }
|
||||
XmlParent getParent() { xmlElements(this, _, result, _, _) }
|
||||
|
||||
/** Gets the index of this XML element among its parent's children. */
|
||||
int getIndex() { xmlElements(this, _, _, result, _) }
|
||||
@@ -196,7 +211,7 @@ class XMLElement extends @xmlelement, XMLParent, XMLLocatable {
|
||||
predicate hasNamespace() { xmlHasNs(this, _, _) }
|
||||
|
||||
/** Gets the namespace of this XML element, if any. */
|
||||
XMLNamespace getNamespace() { xmlHasNs(this, result, _) }
|
||||
XmlNamespace getNamespace() { xmlHasNs(this, result, _) }
|
||||
|
||||
/** Gets the index of this XML element among its parent's children. */
|
||||
int getElementPositionIndex() { xmlElements(this, _, _, result, _) }
|
||||
@@ -205,10 +220,10 @@ class XMLElement extends @xmlelement, XMLParent, XMLLocatable {
|
||||
override int getDepth() { result = this.getParent().getDepth() + 1 }
|
||||
|
||||
/** Gets an XML attribute of this XML element. */
|
||||
XMLAttribute getAnAttribute() { result.getElement() = this }
|
||||
XmlAttribute getAnAttribute() { result.getElement() = this }
|
||||
|
||||
/** Gets the attribute with the specified `name`, if any. */
|
||||
XMLAttribute getAttribute(string name) { result.getElement() = this and result.getName() = name }
|
||||
XmlAttribute getAttribute(string name) { result.getElement() = this and result.getName() = name }
|
||||
|
||||
/** Holds if this XML element has an attribute with the specified `name`. */
|
||||
predicate hasAttribute(string name) { exists(this.getAttribute(name)) }
|
||||
@@ -220,6 +235,9 @@ class XMLElement extends @xmlelement, XMLParent, XMLLocatable {
|
||||
override string toString() { result = this.getName() }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for XmlElement */
|
||||
deprecated class XMLElement = XmlElement;
|
||||
|
||||
/**
|
||||
* An attribute that occurs inside an XML element.
|
||||
*
|
||||
@@ -230,18 +248,18 @@ class XMLElement extends @xmlelement, XMLParent, XMLLocatable {
|
||||
* android:versionCode="1"
|
||||
* ```
|
||||
*/
|
||||
class XMLAttribute extends @xmlattribute, XMLLocatable {
|
||||
class XmlAttribute extends @xmlattribute, XmlLocatable {
|
||||
/** Gets the name of this attribute. */
|
||||
string getName() { xmlAttrs(this, _, result, _, _, _) }
|
||||
|
||||
/** Gets the XML element to which this attribute belongs. */
|
||||
XMLElement getElement() { xmlAttrs(this, result, _, _, _, _) }
|
||||
XmlElement getElement() { xmlAttrs(this, result, _, _, _, _) }
|
||||
|
||||
/** Holds if this attribute has a namespace. */
|
||||
predicate hasNamespace() { xmlHasNs(this, _, _) }
|
||||
|
||||
/** Gets the namespace of this attribute, if any. */
|
||||
XMLNamespace getNamespace() { xmlHasNs(this, result, _) }
|
||||
XmlNamespace getNamespace() { xmlHasNs(this, result, _) }
|
||||
|
||||
/** Gets the value of this attribute. */
|
||||
string getValue() { xmlAttrs(this, _, _, result, _, _) }
|
||||
@@ -250,6 +268,9 @@ class XMLAttribute extends @xmlattribute, XMLLocatable {
|
||||
override string toString() { result = this.getName() + "=" + this.getValue() }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for XmlAttribute */
|
||||
deprecated class XMLAttribute = XmlAttribute;
|
||||
|
||||
/**
|
||||
* A namespace used in an XML file.
|
||||
*
|
||||
@@ -259,23 +280,29 @@ class XMLAttribute extends @xmlattribute, XMLLocatable {
|
||||
* xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
* ```
|
||||
*/
|
||||
class XMLNamespace extends XMLLocatable, @xmlnamespace {
|
||||
class XmlNamespace extends XmlLocatable, @xmlnamespace {
|
||||
/** Gets the prefix of this namespace. */
|
||||
string getPrefix() { xmlNs(this, result, _, _) }
|
||||
|
||||
/** Gets the URI of this namespace. */
|
||||
string getURI() { xmlNs(this, _, result, _) }
|
||||
string getUri() { xmlNs(this, _, result, _) }
|
||||
|
||||
/** DEPRECATED: Alias for getUri */
|
||||
deprecated string getURI() { result = this.getUri() }
|
||||
|
||||
/** Holds if this namespace has no prefix. */
|
||||
predicate isDefault() { this.getPrefix() = "" }
|
||||
|
||||
override string toString() {
|
||||
this.isDefault() and result = this.getURI()
|
||||
this.isDefault() and result = this.getUri()
|
||||
or
|
||||
not this.isDefault() and result = this.getPrefix() + ":" + this.getURI()
|
||||
not this.isDefault() and result = this.getPrefix() + ":" + this.getUri()
|
||||
}
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for XmlNamespace */
|
||||
deprecated class XMLNamespace = XmlNamespace;
|
||||
|
||||
/**
|
||||
* A comment in an XML file.
|
||||
*
|
||||
@@ -285,17 +312,20 @@ class XMLNamespace extends XMLLocatable, @xmlnamespace {
|
||||
* <!-- This is a comment. -->
|
||||
* ```
|
||||
*/
|
||||
class XMLComment extends @xmlcomment, XMLLocatable {
|
||||
class XmlComment extends @xmlcomment, XmlLocatable {
|
||||
/** Gets the text content of this XML comment. */
|
||||
string getText() { xmlComments(this, result, _, _) }
|
||||
|
||||
/** Gets the parent of this XML comment. */
|
||||
XMLParent getParent() { xmlComments(this, _, result, _) }
|
||||
XmlParent getParent() { xmlComments(this, _, result, _) }
|
||||
|
||||
/** Gets a printable representation of this XML comment. */
|
||||
override string toString() { result = this.getText() }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for XmlComment */
|
||||
deprecated class XMLComment = XmlComment;
|
||||
|
||||
/**
|
||||
* A sequence of characters that occurs between opening and
|
||||
* closing tags of an XML element, excluding other elements.
|
||||
@@ -306,12 +336,12 @@ class XMLComment extends @xmlcomment, XMLLocatable {
|
||||
* <content>This is a sequence of characters.</content>
|
||||
* ```
|
||||
*/
|
||||
class XMLCharacters extends @xmlcharacters, XMLLocatable {
|
||||
class XmlCharacters extends @xmlcharacters, XmlLocatable {
|
||||
/** Gets the content of this character sequence. */
|
||||
string getCharacters() { xmlChars(this, result, _, _, _, _) }
|
||||
|
||||
/** Gets the parent of this character sequence. */
|
||||
XMLParent getParent() { xmlChars(this, _, result, _, _, _) }
|
||||
XmlParent getParent() { xmlChars(this, _, result, _, _, _) }
|
||||
|
||||
/** Holds if this character sequence is CDATA. */
|
||||
predicate isCDATA() { xmlChars(this, _, _, _, 1, _) }
|
||||
@@ -319,3 +349,6 @@ class XMLCharacters extends @xmlcharacters, XMLLocatable {
|
||||
/** Gets a printable representation of this XML character sequence. */
|
||||
override string toString() { result = this.getCharacters() }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for XmlCharacters */
|
||||
deprecated class XMLCharacters = XmlCharacters;
|
||||
|
||||
@@ -3061,7 +3061,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
|
||||
else cc instanceof CallContextAny
|
||||
) and
|
||||
sc instanceof SummaryCtxNone and
|
||||
ap instanceof AccessPathNil
|
||||
ap = TAccessPathNil(node.getDataFlowType())
|
||||
}
|
||||
|
||||
predicate isAtSink() {
|
||||
|
||||
@@ -3061,7 +3061,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
|
||||
else cc instanceof CallContextAny
|
||||
) and
|
||||
sc instanceof SummaryCtxNone and
|
||||
ap instanceof AccessPathNil
|
||||
ap = TAccessPathNil(node.getDataFlowType())
|
||||
}
|
||||
|
||||
predicate isAtSink() {
|
||||
|
||||
@@ -3061,7 +3061,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
|
||||
else cc instanceof CallContextAny
|
||||
) and
|
||||
sc instanceof SummaryCtxNone and
|
||||
ap instanceof AccessPathNil
|
||||
ap = TAccessPathNil(node.getDataFlowType())
|
||||
}
|
||||
|
||||
predicate isAtSink() {
|
||||
|
||||
@@ -3061,7 +3061,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
|
||||
else cc instanceof CallContextAny
|
||||
) and
|
||||
sc instanceof SummaryCtxNone and
|
||||
ap instanceof AccessPathNil
|
||||
ap = TAccessPathNil(node.getDataFlowType())
|
||||
}
|
||||
|
||||
predicate isAtSink() {
|
||||
|
||||
@@ -3061,7 +3061,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
|
||||
else cc instanceof CallContextAny
|
||||
) and
|
||||
sc instanceof SummaryCtxNone and
|
||||
ap instanceof AccessPathNil
|
||||
ap = TAccessPathNil(node.getDataFlowType())
|
||||
}
|
||||
|
||||
predicate isAtSink() {
|
||||
|
||||
@@ -47,6 +47,20 @@ class AssignExpr extends Assignment, @assignexpr {
|
||||
override string toString() { result = "... = ..." }
|
||||
}
|
||||
|
||||
/**
|
||||
* A compiler generated assignment operation that may occur in a compiler generated
|
||||
* copy/move constructor or assignment operator, and which functions like `memcpy`
|
||||
* where the size argument is based on the type of the rvalue of the assignment.
|
||||
*/
|
||||
class BlockAssignExpr extends Assignment, @blockassignexpr {
|
||||
override string getOperator() { result = "=" }
|
||||
|
||||
override string getAPrimaryQlClass() { result = "BlockAssignExpr" }
|
||||
|
||||
/** Gets a textual representation of this assignment. */
|
||||
override string toString() { result = "... = ..." }
|
||||
}
|
||||
|
||||
/**
|
||||
* A non-overloaded binary assignment operation other than `=`.
|
||||
*
|
||||
|
||||
@@ -3061,7 +3061,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
|
||||
else cc instanceof CallContextAny
|
||||
) and
|
||||
sc instanceof SummaryCtxNone and
|
||||
ap instanceof AccessPathNil
|
||||
ap = TAccessPathNil(node.getDataFlowType())
|
||||
}
|
||||
|
||||
predicate isAtSink() {
|
||||
|
||||
@@ -3061,7 +3061,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
|
||||
else cc instanceof CallContextAny
|
||||
) and
|
||||
sc instanceof SummaryCtxNone and
|
||||
ap instanceof AccessPathNil
|
||||
ap = TAccessPathNil(node.getDataFlowType())
|
||||
}
|
||||
|
||||
predicate isAtSink() {
|
||||
|
||||
@@ -3061,7 +3061,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
|
||||
else cc instanceof CallContextAny
|
||||
) and
|
||||
sc instanceof SummaryCtxNone and
|
||||
ap instanceof AccessPathNil
|
||||
ap = TAccessPathNil(node.getDataFlowType())
|
||||
}
|
||||
|
||||
predicate isAtSink() {
|
||||
|
||||
@@ -3061,7 +3061,7 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
|
||||
else cc instanceof CallContextAny
|
||||
) and
|
||||
sc instanceof SummaryCtxNone and
|
||||
ap instanceof AccessPathNil
|
||||
ap = TAccessPathNil(node.getDataFlowType())
|
||||
}
|
||||
|
||||
predicate isAtSink() {
|
||||
|
||||
@@ -39,7 +39,7 @@ private module Liveness {
|
||||
/**
|
||||
* Holds if the `i`th node of basic block `bb` is a reference to `v` of kind `k`.
|
||||
*/
|
||||
private predicate ref(BasicBlock bb, int i, SourceVariable v, RefKind k) {
|
||||
predicate ref(BasicBlock bb, int i, SourceVariable v, RefKind k) {
|
||||
exists(boolean certain | variableRead(bb, i, v, certain) | k = Read(certain))
|
||||
or
|
||||
exists(boolean certain | variableWrite(bb, i, v, certain) | k = Write(certain))
|
||||
@@ -76,6 +76,10 @@ private module Liveness {
|
||||
not result + 1 = refRank(bb, _, v, _)
|
||||
}
|
||||
|
||||
predicate lastRefIsRead(BasicBlock bb, SourceVariable v) {
|
||||
maxRefRank(bb, v) = refRank(bb, _, v, Read(_))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the (1-based) rank of the first reference to `v` inside basic block `bb`
|
||||
* that is either a read or a certain write.
|
||||
@@ -185,23 +189,29 @@ newtype TDefinition =
|
||||
|
||||
private module SsaDefReaches {
|
||||
newtype TSsaRefKind =
|
||||
SsaRead() or
|
||||
SsaActualRead() or
|
||||
SsaPhiRead() or
|
||||
SsaDef()
|
||||
|
||||
class SsaRead = SsaActualRead or SsaPhiRead;
|
||||
|
||||
/**
|
||||
* A classification of SSA variable references into reads and definitions.
|
||||
*/
|
||||
class SsaRefKind extends TSsaRefKind {
|
||||
string toString() {
|
||||
this = SsaRead() and
|
||||
result = "SsaRead"
|
||||
this = SsaActualRead() and
|
||||
result = "SsaActualRead"
|
||||
or
|
||||
this = SsaPhiRead() and
|
||||
result = "SsaPhiRead"
|
||||
or
|
||||
this = SsaDef() and
|
||||
result = "SsaDef"
|
||||
}
|
||||
|
||||
int getOrder() {
|
||||
this = SsaRead() and
|
||||
this instanceof SsaRead and
|
||||
result = 0
|
||||
or
|
||||
this = SsaDef() and
|
||||
@@ -209,6 +219,80 @@ private module SsaDefReaches {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `bb` is in the dominance frontier of a block containing a
|
||||
* read of `v`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate inReadDominanceFrontier(BasicBlock bb, SourceVariable v) {
|
||||
exists(BasicBlock readbb | inDominanceFrontier(readbb, bb) |
|
||||
lastRefIsRead(readbb, v)
|
||||
or
|
||||
phiRead(readbb, v)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if a phi-read node should be inserted for variable `v` at the beginning
|
||||
* of basic block `bb`.
|
||||
*
|
||||
* Phi-read nodes are like normal phi nodes, but they are inserted based on reads
|
||||
* instead of writes, and only if the dominance-frontier block does not already
|
||||
* contain a reference (read or write) to `v`. Unlike normal phi nodes, this is
|
||||
* an internal implementation detail that is not exposed.
|
||||
*
|
||||
* The motivation for adding phi-reads is to improve performance of the use-use
|
||||
* calculation in cases where there is a large number of reads that can reach the
|
||||
* same join-point, and from there reach a large number of basic blocks. Example:
|
||||
*
|
||||
* ```cs
|
||||
* if (a)
|
||||
* use(x);
|
||||
* else if (b)
|
||||
* use(x);
|
||||
* else if (c)
|
||||
* use(x);
|
||||
* else if (d)
|
||||
* use(x);
|
||||
* // many more ifs ...
|
||||
*
|
||||
* // phi-read for `x` inserted here
|
||||
*
|
||||
* // program not mentioning `x`, with large basic block graph
|
||||
*
|
||||
* use(x);
|
||||
* ```
|
||||
*
|
||||
* Without phi-reads, the analysis has to replicate reachability for each of
|
||||
* the guarded uses of `x`. However, with phi-reads, the analysis will limit
|
||||
* each conditional use of `x` to reach the basic block containing the phi-read
|
||||
* node for `x`, and only that basic block will have to compute reachability
|
||||
* through the remainder of the large program.
|
||||
*
|
||||
* Like normal reads, each phi-read node `phi-read` can be reached from exactly
|
||||
* one SSA definition (without passing through another definition): Assume, for
|
||||
* the sake of contradiction, that there are two reaching definitions `def1` and
|
||||
* `def2`. Now, if both `def1` and `def2` dominate `phi-read`, then the nearest
|
||||
* dominating definition will prevent the other from reaching `phi-read`. So, at
|
||||
* least one of `def1` and `def2` cannot dominate `phi-read`; assume it is `def1`.
|
||||
* Then `def1` must go through one of its dominance-frontier blocks in order to
|
||||
* reach `phi-read`. However, such a block will always start with a (normal) phi
|
||||
* node, which contradicts reachability.
|
||||
*
|
||||
* Also, like normal reads, the unique SSA definition `def` that reaches `phi-read`,
|
||||
* will dominate `phi-read`. Assuming it doesn't means that the path from `def`
|
||||
* to `phi-read` goes through a dominance-frontier block, and hence a phi node,
|
||||
* which contradicts reachability.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate phiRead(BasicBlock bb, SourceVariable v) {
|
||||
inReadDominanceFrontier(bb, v) and
|
||||
liveAtEntry(bb, v) and
|
||||
// only if there are no other references to `v` inside `bb`
|
||||
not ref(bb, _, v, _) and
|
||||
not exists(Definition def | def.definesAt(v, bb, _))
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the `i`th node of basic block `bb` is a reference to `v`,
|
||||
* either a read (when `k` is `SsaRead()`) or an SSA definition (when `k`
|
||||
@@ -216,11 +300,16 @@ private module SsaDefReaches {
|
||||
*
|
||||
* Unlike `Liveness::ref`, this includes `phi` nodes.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate ssaRef(BasicBlock bb, int i, SourceVariable v, SsaRefKind k) {
|
||||
variableRead(bb, i, v, _) and
|
||||
k = SsaRead()
|
||||
k = SsaActualRead()
|
||||
or
|
||||
exists(Definition def | def.definesAt(v, bb, i)) and
|
||||
phiRead(bb, v) and
|
||||
i = -1 and
|
||||
k = SsaPhiRead()
|
||||
or
|
||||
any(Definition def).definesAt(v, bb, i) and
|
||||
k = SsaDef()
|
||||
}
|
||||
|
||||
@@ -273,7 +362,7 @@ private module SsaDefReaches {
|
||||
)
|
||||
or
|
||||
ssaDefReachesRank(bb, def, rnk - 1, v) and
|
||||
rnk = ssaRefRank(bb, _, v, SsaRead())
|
||||
rnk = ssaRefRank(bb, _, v, any(SsaRead k))
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -283,7 +372,7 @@ private module SsaDefReaches {
|
||||
predicate ssaDefReachesReadWithinBlock(SourceVariable v, Definition def, BasicBlock bb, int i) {
|
||||
exists(int rnk |
|
||||
ssaDefReachesRank(bb, def, rnk, v) and
|
||||
rnk = ssaRefRank(bb, i, v, SsaRead())
|
||||
rnk = ssaRefRank(bb, i, v, any(SsaRead k))
|
||||
)
|
||||
}
|
||||
|
||||
@@ -309,45 +398,94 @@ private module SsaDefReaches {
|
||||
ssaDefRank(def, v, bb, i, _) = maxSsaRefRank(bb, v)
|
||||
}
|
||||
|
||||
predicate defOccursInBlock(Definition def, BasicBlock bb, SourceVariable v) {
|
||||
exists(ssaDefRank(def, v, bb, _, _))
|
||||
predicate defOccursInBlock(Definition def, BasicBlock bb, SourceVariable v, SsaRefKind k) {
|
||||
exists(ssaDefRank(def, v, bb, _, k))
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate ssaDefReachesThroughBlock(Definition def, BasicBlock bb) {
|
||||
ssaDefReachesEndOfBlock(bb, def, _) and
|
||||
not defOccursInBlock(_, bb, def.getSourceVariable())
|
||||
not defOccursInBlock(_, bb, def.getSourceVariable(), _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `def` is accessed in basic block `bb1` (either a read or a write),
|
||||
* `bb2` is a transitive successor of `bb1`, `def` is live at the end of `bb1`,
|
||||
* and the underlying variable for `def` is neither read nor written in any block
|
||||
* on the path between `bb1` and `bb2`.
|
||||
* `bb2` is a transitive successor of `bb1`, `def` is live at the end of _some_
|
||||
* predecessor of `bb2`, and the underlying variable for `def` is neither read
|
||||
* nor written in any block on the path between `bb1` and `bb2`.
|
||||
*
|
||||
* Phi reads are considered as normal reads for this predicate.
|
||||
*/
|
||||
predicate varBlockReaches(Definition def, BasicBlock bb1, BasicBlock bb2) {
|
||||
defOccursInBlock(def, bb1, _) and
|
||||
pragma[nomagic]
|
||||
private predicate varBlockReachesInclPhiRead(Definition def, BasicBlock bb1, BasicBlock bb2) {
|
||||
defOccursInBlock(def, bb1, _, _) and
|
||||
bb2 = getABasicBlockSuccessor(bb1)
|
||||
or
|
||||
exists(BasicBlock mid |
|
||||
varBlockReaches(def, bb1, mid) and
|
||||
varBlockReachesInclPhiRead(def, bb1, mid) and
|
||||
ssaDefReachesThroughBlock(def, mid) and
|
||||
bb2 = getABasicBlockSuccessor(mid)
|
||||
)
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate phiReadStep(Definition def, SourceVariable v, BasicBlock bb1, BasicBlock bb2) {
|
||||
varBlockReachesInclPhiRead(def, bb1, bb2) and
|
||||
defOccursInBlock(def, bb2, v, SsaPhiRead())
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
private predicate varBlockReachesExclPhiRead(Definition def, BasicBlock bb1, BasicBlock bb2) {
|
||||
varBlockReachesInclPhiRead(pragma[only_bind_into](def), bb1, pragma[only_bind_into](bb2)) and
|
||||
ssaRef(bb2, _, def.getSourceVariable(), [SsaActualRead().(TSsaRefKind), SsaDef()])
|
||||
or
|
||||
exists(BasicBlock mid |
|
||||
varBlockReachesExclPhiRead(def, mid, bb2) and
|
||||
phiReadStep(def, _, bb1, mid)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `def` is accessed in basic block `bb1` (either a read or a write),
|
||||
* `def` is read at index `i2` in basic block `bb2`, `bb2` is in a transitive
|
||||
* successor block of `bb1`, and `def` is neither read nor written in any block
|
||||
* on a path between `bb1` and `bb2`.
|
||||
* the underlying variable `v` of `def` is accessed in basic block `bb2`
|
||||
* (either a read or a write), `bb2` is a transitive successor of `bb1`, and
|
||||
* `v` is neither read nor written in any block on the path between `bb1`
|
||||
* and `bb2`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate varBlockReaches(Definition def, BasicBlock bb1, BasicBlock bb2) {
|
||||
varBlockReachesExclPhiRead(def, bb1, bb2) and
|
||||
not defOccursInBlock(def, bb1, _, SsaPhiRead())
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate defAdjacentRead(Definition def, BasicBlock bb1, BasicBlock bb2, int i2) {
|
||||
varBlockReaches(def, bb1, bb2) and
|
||||
ssaRefRank(bb2, i2, def.getSourceVariable(), SsaRead()) = 1
|
||||
ssaRefRank(bb2, i2, def.getSourceVariable(), SsaActualRead()) = 1
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `def` is accessed in basic block `bb` (either a read or a write),
|
||||
* `bb1` can reach a transitive successor `bb2` where `def` is no longer live,
|
||||
* and `v` is neither read nor written in any block on the path between `bb`
|
||||
* and `bb2`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate varBlockReachesExit(Definition def, BasicBlock bb) {
|
||||
exists(BasicBlock bb2 | varBlockReachesInclPhiRead(def, bb, bb2) |
|
||||
not defOccursInBlock(def, bb2, _, _) and
|
||||
not ssaDefReachesEndOfBlock(bb2, def, _)
|
||||
)
|
||||
or
|
||||
exists(BasicBlock mid |
|
||||
varBlockReachesExit(def, mid) and
|
||||
phiReadStep(def, _, bb, mid)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
predicate phiReadExposedForTesting = phiRead/2;
|
||||
|
||||
private import SsaDefReaches
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -365,7 +503,8 @@ predicate liveThrough(BasicBlock bb, SourceVariable v) {
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate ssaDefReachesEndOfBlock(BasicBlock bb, Definition def, SourceVariable v) {
|
||||
exists(int last | last = maxSsaRefRank(bb, v) |
|
||||
exists(int last |
|
||||
last = maxSsaRefRank(pragma[only_bind_into](bb), pragma[only_bind_into](v)) and
|
||||
ssaDefReachesRank(bb, def, last, v) and
|
||||
liveAtExit(bb, v)
|
||||
)
|
||||
@@ -405,7 +544,7 @@ pragma[nomagic]
|
||||
predicate ssaDefReachesRead(SourceVariable v, Definition def, BasicBlock bb, int i) {
|
||||
ssaDefReachesReadWithinBlock(v, def, bb, i)
|
||||
or
|
||||
variableRead(bb, i, v, _) and
|
||||
ssaRef(bb, i, v, any(SsaRead k)) and
|
||||
ssaDefReachesEndOfBlock(getABasicBlockPredecessor(bb), def, v) and
|
||||
not ssaDefReachesReadWithinBlock(v, _, bb, i)
|
||||
}
|
||||
@@ -421,7 +560,7 @@ pragma[nomagic]
|
||||
predicate adjacentDefRead(Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2) {
|
||||
exists(int rnk |
|
||||
rnk = ssaDefRank(def, _, bb1, i1, _) and
|
||||
rnk + 1 = ssaDefRank(def, _, bb1, i2, SsaRead()) and
|
||||
rnk + 1 = ssaDefRank(def, _, bb1, i2, SsaActualRead()) and
|
||||
variableRead(bb1, i2, _, _) and
|
||||
bb2 = bb1
|
||||
)
|
||||
@@ -538,18 +677,15 @@ predicate lastRefRedefNoUncertainReads(Definition def, BasicBlock bb, int i, Def
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate lastRef(Definition def, BasicBlock bb, int i) {
|
||||
// Can reach another definition
|
||||
lastRefRedef(def, bb, i, _)
|
||||
or
|
||||
lastSsaRef(def, _, bb, i) and
|
||||
(
|
||||
exists(SourceVariable v | lastSsaRef(def, v, bb, i) |
|
||||
// Can reach exit directly
|
||||
bb instanceof ExitBasicBlock
|
||||
or
|
||||
// Can reach a block using one or more steps, where `def` is no longer live
|
||||
exists(BasicBlock bb2 | varBlockReaches(def, bb, bb2) |
|
||||
not defOccursInBlock(def, bb2, _) and
|
||||
not ssaDefReachesEndOfBlock(bb2, def, _)
|
||||
)
|
||||
varBlockReachesExit(def, bb)
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ module InstructionConsistency {
|
||||
abstract Language::Location getLocation();
|
||||
}
|
||||
|
||||
private class PresentIRFunction extends OptionalIRFunction, TPresentIRFunction {
|
||||
class PresentIRFunction extends OptionalIRFunction, TPresentIRFunction {
|
||||
private IRFunction irFunc;
|
||||
|
||||
PresentIRFunction() { this = TPresentIRFunction(irFunc) }
|
||||
@@ -37,6 +37,8 @@ module InstructionConsistency {
|
||||
result =
|
||||
min(Language::Location loc | loc = irFunc.getLocation() | loc order by loc.toString())
|
||||
}
|
||||
|
||||
IRFunction getIRFunction() { result = irFunc }
|
||||
}
|
||||
|
||||
private class MissingIRFunction extends OptionalIRFunction, TMissingIRFunction {
|
||||
|
||||
@@ -3,7 +3,7 @@ import semmle.code.cpp.ir.internal.Overlap
|
||||
private import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
||||
private import semmle.code.cpp.Print
|
||||
private import semmle.code.cpp.ir.implementation.unaliased_ssa.IR
|
||||
private import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.SSAConstruction as OldSSA
|
||||
private import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.SSAConstruction as OldSsa
|
||||
private import semmle.code.cpp.ir.internal.IntegerConstant as Ints
|
||||
private import semmle.code.cpp.ir.internal.IntegerInterval as Interval
|
||||
private import semmle.code.cpp.ir.implementation.internal.OperandTag
|
||||
@@ -572,7 +572,7 @@ private Overlap getVariableMemoryLocationOverlap(
|
||||
* Holds if the def/use information for the result of `instr` can be reused from the previous
|
||||
* iteration of the IR.
|
||||
*/
|
||||
predicate canReuseSsaForOldResult(Instruction instr) { OldSSA::canReuseSsaForMemoryResult(instr) }
|
||||
predicate canReuseSsaForOldResult(Instruction instr) { OldSsa::canReuseSsaForMemoryResult(instr) }
|
||||
|
||||
/** DEPRECATED: Alias for canReuseSsaForOldResult */
|
||||
deprecated predicate canReuseSSAForOldResult = canReuseSsaForOldResult/1;
|
||||
|
||||
@@ -5,10 +5,9 @@ private import Imports::OperandTag
|
||||
private import Imports::Overlap
|
||||
private import Imports::TInstruction
|
||||
private import Imports::RawIR as RawIR
|
||||
private import SSAInstructions
|
||||
private import SSAOperands
|
||||
private import SsaInstructions
|
||||
private import SsaOperands
|
||||
private import NewIR
|
||||
|
||||
import Cached
|
||||
|
||||
cached
|
||||
|
||||
@@ -2,10 +2,18 @@ import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as OldIR
|
||||
import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.reachability.ReachableBlock as Reachability
|
||||
import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.reachability.Dominance as Dominance
|
||||
import semmle.code.cpp.ir.implementation.aliased_ssa.IR as NewIR
|
||||
import semmle.code.cpp.ir.implementation.internal.TInstruction::AliasedSsaInstructions as SSAInstructions
|
||||
import semmle.code.cpp.ir.implementation.internal.TInstruction::AliasedSsaInstructions as SsaInstructions
|
||||
|
||||
/** DEPRECATED: Alias for SsaInstructions */
|
||||
deprecated module SSAInstructions = SsaInstructions;
|
||||
|
||||
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
||||
import AliasedSSA as Alias
|
||||
import semmle.code.cpp.ir.implementation.internal.TOperand::AliasedSsaOperands as SSAOperands
|
||||
import semmle.code.cpp.ir.implementation.internal.TOperand::AliasedSsaOperands as SsaOperands
|
||||
|
||||
/** DEPRECATED: Alias for SsaOperands */
|
||||
deprecated module SSAOperands = SsaOperands;
|
||||
|
||||
private import SideEffectElimination as Elim
|
||||
|
||||
predicate removedInstruction(Reachability::ReachableInstruction instr) {
|
||||
|
||||
@@ -29,16 +29,16 @@ newtype TInstruction =
|
||||
UnaliasedSsa::SSA::hasUnreachedInstruction(irFunc)
|
||||
} or
|
||||
TAliasedSsaPhiInstruction(
|
||||
TRawInstruction blockStartInstr, AliasedSSA::SSA::MemoryLocation memoryLocation
|
||||
TRawInstruction blockStartInstr, AliasedSsa::SSA::MemoryLocation memoryLocation
|
||||
) {
|
||||
AliasedSSA::SSA::hasPhiInstruction(blockStartInstr, memoryLocation)
|
||||
AliasedSsa::SSA::hasPhiInstruction(blockStartInstr, memoryLocation)
|
||||
} or
|
||||
TAliasedSsaChiInstruction(TRawInstruction primaryInstruction) {
|
||||
not AliasedSSA::removedInstruction(primaryInstruction) and
|
||||
AliasedSSA::SSA::hasChiInstruction(primaryInstruction)
|
||||
not AliasedSsa::removedInstruction(primaryInstruction) and
|
||||
AliasedSsa::SSA::hasChiInstruction(primaryInstruction)
|
||||
} or
|
||||
TAliasedSsaUnreachedInstruction(IRFunctionBase irFunc) {
|
||||
AliasedSSA::SSA::hasUnreachedInstruction(irFunc)
|
||||
AliasedSsa::SSA::hasUnreachedInstruction(irFunc)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -84,7 +84,7 @@ module AliasedSsaInstructions {
|
||||
class TPhiInstruction = TAliasedSsaPhiInstruction or TUnaliasedSsaPhiInstruction;
|
||||
|
||||
TPhiInstruction phiInstruction(
|
||||
TRawInstruction blockStartInstr, AliasedSSA::SSA::MemoryLocation memoryLocation
|
||||
TRawInstruction blockStartInstr, AliasedSsa::SSA::MemoryLocation memoryLocation
|
||||
) {
|
||||
result = TAliasedSsaPhiInstruction(blockStartInstr, memoryLocation)
|
||||
}
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
||||
import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as IRConstruction
|
||||
import semmle.code.cpp.ir.implementation.unaliased_ssa.internal.SSAConstruction as UnaliasedSsa
|
||||
import semmle.code.cpp.ir.implementation.aliased_ssa.internal.SSAConstruction as AliasedSSA
|
||||
import semmle.code.cpp.ir.implementation.aliased_ssa.internal.SSAConstruction as AliasedSsa
|
||||
|
||||
/** DEPRECATED: Alias for AliasedSsa */
|
||||
deprecated module AliasedSSA = AliasedSsa;
|
||||
|
||||
import semmle.code.cpp.ir.implementation.aliased_ssa.internal.SideEffectElimination as Elim
|
||||
|
||||
@@ -22,7 +22,7 @@ module InstructionConsistency {
|
||||
abstract Language::Location getLocation();
|
||||
}
|
||||
|
||||
private class PresentIRFunction extends OptionalIRFunction, TPresentIRFunction {
|
||||
class PresentIRFunction extends OptionalIRFunction, TPresentIRFunction {
|
||||
private IRFunction irFunc;
|
||||
|
||||
PresentIRFunction() { this = TPresentIRFunction(irFunc) }
|
||||
@@ -37,6 +37,8 @@ module InstructionConsistency {
|
||||
result =
|
||||
min(Language::Location loc | loc = irFunc.getLocation() | loc order by loc.toString())
|
||||
}
|
||||
|
||||
IRFunction getIRFunction() { result = irFunc }
|
||||
}
|
||||
|
||||
private class MissingIRFunction extends OptionalIRFunction, TMissingIRFunction {
|
||||
|
||||
@@ -1450,8 +1450,6 @@ class TranslatedAssignExpr extends TranslatedNonConstantExpr {
|
||||
result = this.getLeftOperand().getResult()
|
||||
}
|
||||
|
||||
abstract Instruction getStoredValue();
|
||||
|
||||
final TranslatedExpr getLeftOperand() {
|
||||
result = getTranslatedExpr(expr.getLValue().getFullyConverted())
|
||||
}
|
||||
@@ -1493,6 +1491,75 @@ class TranslatedAssignExpr extends TranslatedNonConstantExpr {
|
||||
}
|
||||
}
|
||||
|
||||
class TranslatedBlockAssignExpr extends TranslatedNonConstantExpr {
|
||||
override BlockAssignExpr expr;
|
||||
|
||||
final override TranslatedElement getChild(int id) {
|
||||
id = 0 and result = this.getLeftOperand()
|
||||
or
|
||||
id = 1 and result = this.getRightOperand()
|
||||
}
|
||||
|
||||
final override Instruction getFirstInstruction() {
|
||||
// The operand evaluation order should not matter since block assignments behave like memcpy.
|
||||
result = this.getLeftOperand().getFirstInstruction()
|
||||
}
|
||||
|
||||
final override Instruction getResult() { result = this.getInstruction(AssignmentStoreTag()) }
|
||||
|
||||
final TranslatedExpr getLeftOperand() {
|
||||
result = getTranslatedExpr(expr.getLValue().getFullyConverted())
|
||||
}
|
||||
|
||||
final TranslatedExpr getRightOperand() {
|
||||
result = getTranslatedExpr(expr.getRValue().getFullyConverted())
|
||||
}
|
||||
|
||||
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
|
||||
tag = LoadTag() and
|
||||
result = this.getInstruction(AssignmentStoreTag()) and
|
||||
kind instanceof GotoEdge
|
||||
or
|
||||
tag = AssignmentStoreTag() and
|
||||
result = this.getParent().getChildSuccessor(this) and
|
||||
kind instanceof GotoEdge
|
||||
}
|
||||
|
||||
override Instruction getChildSuccessor(TranslatedElement child) {
|
||||
child = this.getLeftOperand() and
|
||||
result = this.getRightOperand().getFirstInstruction()
|
||||
or
|
||||
child = this.getRightOperand() and
|
||||
result = this.getInstruction(LoadTag())
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
tag = LoadTag() and
|
||||
opcode instanceof Opcode::Load and
|
||||
resultType = getTypeForPRValue(expr.getRValue().getType())
|
||||
or
|
||||
tag = AssignmentStoreTag() and
|
||||
opcode instanceof Opcode::Store and
|
||||
// The frontend specifies that the relevant type is the one of the source.
|
||||
resultType = getTypeForPRValue(expr.getRValue().getType())
|
||||
}
|
||||
|
||||
override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
|
||||
tag = LoadTag() and
|
||||
operandTag instanceof AddressOperandTag and
|
||||
result = this.getRightOperand().getResult()
|
||||
or
|
||||
tag = AssignmentStoreTag() and
|
||||
(
|
||||
operandTag instanceof AddressOperandTag and
|
||||
result = this.getLeftOperand().getResult()
|
||||
or
|
||||
operandTag instanceof StoreValueOperandTag and
|
||||
result = this.getInstruction(LoadTag())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
class TranslatedAssignOperation extends TranslatedNonConstantExpr {
|
||||
override AssignOperation expr;
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ module InstructionConsistency {
|
||||
abstract Language::Location getLocation();
|
||||
}
|
||||
|
||||
private class PresentIRFunction extends OptionalIRFunction, TPresentIRFunction {
|
||||
class PresentIRFunction extends OptionalIRFunction, TPresentIRFunction {
|
||||
private IRFunction irFunc;
|
||||
|
||||
PresentIRFunction() { this = TPresentIRFunction(irFunc) }
|
||||
@@ -37,6 +37,8 @@ module InstructionConsistency {
|
||||
result =
|
||||
min(Language::Location loc | loc = irFunc.getLocation() | loc order by loc.toString())
|
||||
}
|
||||
|
||||
IRFunction getIRFunction() { result = irFunc }
|
||||
}
|
||||
|
||||
private class MissingIRFunction extends OptionalIRFunction, TMissingIRFunction {
|
||||
|
||||
@@ -5,10 +5,9 @@ private import Imports::OperandTag
|
||||
private import Imports::Overlap
|
||||
private import Imports::TInstruction
|
||||
private import Imports::RawIR as RawIR
|
||||
private import SSAInstructions
|
||||
private import SSAOperands
|
||||
private import SsaInstructions
|
||||
private import SsaOperands
|
||||
private import NewIR
|
||||
|
||||
import Cached
|
||||
|
||||
cached
|
||||
|
||||
@@ -3,13 +3,20 @@ import semmle.code.cpp.ir.implementation.raw.internal.reachability.ReachableBloc
|
||||
import semmle.code.cpp.ir.implementation.raw.internal.reachability.Dominance as Dominance
|
||||
import semmle.code.cpp.ir.implementation.unaliased_ssa.IR as NewIR
|
||||
import semmle.code.cpp.ir.implementation.raw.internal.IRConstruction as RawStage
|
||||
import semmle.code.cpp.ir.implementation.internal.TInstruction::UnaliasedSsaInstructions as SSAInstructions
|
||||
import semmle.code.cpp.ir.implementation.internal.TInstruction::UnaliasedSsaInstructions as SsaInstructions
|
||||
|
||||
/** DEPRECATED: Alias for SsaInstructions */
|
||||
deprecated module SSAInstructions = SsaInstructions;
|
||||
|
||||
import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
||||
import SimpleSSA as Alias
|
||||
import semmle.code.cpp.ir.implementation.internal.TOperand::UnaliasedSsaOperands as SSAOperands
|
||||
import semmle.code.cpp.ir.implementation.internal.TOperand::UnaliasedSsaOperands as SsaOperands
|
||||
|
||||
/** DEPRECATED: Alias for SsaOperands */
|
||||
deprecated module SSAOperands = SsaOperands;
|
||||
|
||||
predicate removedInstruction(Reachability::ReachableInstruction instr) { none() }
|
||||
|
||||
class OldBlock = Reachability::ReachableBlock;
|
||||
|
||||
class OldInstruction = Reachability::ReachableInstruction;
|
||||
class OldInstruction = Reachability::ReachableInstruction;
|
||||
|
||||
@@ -11,12 +11,6 @@ private class StdPair extends ClassTemplateInstantiation {
|
||||
StdPair() { this.hasQualifiedName(["std", "bsl"], "pair") }
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: This is now called `StdPair` and is a private part of the
|
||||
* library implementation.
|
||||
*/
|
||||
deprecated class StdPairClass = StdPair;
|
||||
|
||||
/**
|
||||
* Any of the single-parameter constructors of `std::pair` that takes a reference to an
|
||||
* instantiation of `std::pair`. These constructors allow conversion between pair types when the
|
||||
|
||||
@@ -27,13 +27,6 @@ abstract class RemoteFlowSourceFunction extends Function {
|
||||
predicate hasSocketInput(FunctionInput input) { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `RemoteFlowSourceFunction` instead.
|
||||
*
|
||||
* A library function that returns data that may be read from a network connection.
|
||||
*/
|
||||
deprecated class RemoteFlowFunction = RemoteFlowSourceFunction;
|
||||
|
||||
/**
|
||||
* A library function that returns data that is directly controlled by a user.
|
||||
*/
|
||||
@@ -44,13 +37,6 @@ abstract class LocalFlowSourceFunction extends Function {
|
||||
abstract predicate hasLocalFlowSource(FunctionOutput output, string description);
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED: Use `LocalFlowSourceFunction` instead.
|
||||
*
|
||||
* A library function that returns data that is directly controlled by a user.
|
||||
*/
|
||||
deprecated class LocalFlowFunction = LocalFlowSourceFunction;
|
||||
|
||||
/** A library function that sends data over a network connection. */
|
||||
abstract class RemoteFlowSinkFunction extends Function {
|
||||
/**
|
||||
|
||||
@@ -523,6 +523,11 @@ autoderivation(
|
||||
int derivation_type: @type ref
|
||||
);
|
||||
|
||||
orphaned_variables(
|
||||
int var: @localvariable ref,
|
||||
int function: @function ref
|
||||
)
|
||||
|
||||
enumconstants(
|
||||
unique int id: @enumconstant,
|
||||
int parent: @usertype ref,
|
||||
@@ -1302,7 +1307,7 @@ funbind(
|
||||
|
||||
@assign_op_expr = @assign_arith_expr | @assign_bitwise_expr
|
||||
|
||||
@assign_expr = @assignexpr | @assign_op_expr
|
||||
@assign_expr = @assignexpr | @assign_op_expr | @blockassignexpr
|
||||
|
||||
/*
|
||||
case @allocator.form of
|
||||
@@ -1660,6 +1665,7 @@ case @expr.kind of
|
||||
| 332 = @hasuniqueobjectrepresentations
|
||||
| 333 = @builtinbitcast
|
||||
| 334 = @builtinshuffle
|
||||
| 335 = @blockassignexpr
|
||||
;
|
||||
|
||||
@var_args_expr = @vastartexpr
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
||||
description: Support block assignment
|
||||
compatibility: backwards
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,2 @@
|
||||
description: Add relation for orphaned local variables
|
||||
compatibility: partial
|
||||
@@ -29,7 +29,4 @@ where
|
||||
n = strictcount(ComplexStmt s | s = b.getAStmt()) and
|
||||
n > 3 and
|
||||
complexStmt = b.getAStmt()
|
||||
select b,
|
||||
"Block with too many statements (" + n.toString() +
|
||||
" complex statements in the block). Complex statements at: $@", complexStmt,
|
||||
complexStmt.toString()
|
||||
select b, "Block with too many statements (" + n.toString() + " complex statements in the block)."
|
||||
|
||||
@@ -110,4 +110,4 @@ where
|
||||
emptyBlock(s, eb) and
|
||||
not emptyBlockContainsNonchild(eb) and
|
||||
not lineComment(eb)
|
||||
select eb, "Empty block without comment"
|
||||
select eb, "Empty block without comment."
|
||||
|
||||
@@ -1,3 +1,9 @@
|
||||
## 0.3.2
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The query `cpp/bad-strncpy-size` now covers more `strncpy`-like functions than before, including `strxfrm`(`_l`), `wcsxfrm`(`_l`), and `stpncpy`. Users of this query may see an increase in results.
|
||||
|
||||
## 0.3.1
|
||||
|
||||
## 0.3.0
|
||||
|
||||
@@ -12,4 +12,4 @@
|
||||
import CommentedOutCode
|
||||
|
||||
from CommentedOutCode comment
|
||||
select comment, "This comment appears to contain commented-out code"
|
||||
select comment, "This comment appears to contain commented-out code."
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
* @name Sign check of bitwise operation
|
||||
* @description Checking the sign of a bitwise operation often has surprising
|
||||
* edge cases.
|
||||
* @description Checking the sign of the result of a bitwise operation may yield unexpected results.
|
||||
* @kind problem
|
||||
* @problem.severity warning
|
||||
* @precision high
|
||||
@@ -26,4 +25,4 @@ where
|
||||
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."
|
||||
select e, "Potentially unsafe sign check of a bitwise operation."
|
||||
|
||||
@@ -21,4 +21,4 @@ where
|
||||
FloatingPointType and
|
||||
not ro.getAnOperand().isConstant() and // comparisons to constants generate too many false positives
|
||||
not left.(VariableAccess).getTarget() = right.(VariableAccess).getTarget() // skip self comparison
|
||||
select ro, "Equality test on floating point values may not behave as expected."
|
||||
select ro, "Equality checks on floating point values can yield unexpected results."
|
||||
|
||||
@@ -13,10 +13,11 @@
|
||||
|
||||
import cpp
|
||||
|
||||
from EnumSwitch es, float missing, float total
|
||||
from EnumSwitch es, float missing, float total, EnumConstant case
|
||||
where
|
||||
not es.hasDefaultCase() and
|
||||
missing = count(es.getAMissingCase()) and
|
||||
total = missing + count(es.getASwitchCase()) and
|
||||
missing / total < 0.3
|
||||
select es, "Switch statement is missing case for " + es.getAMissingCase().getName()
|
||||
missing / total < 0.3 and
|
||||
case = es.getAMissingCase()
|
||||
select es, "Switch statement does not have a case for $@.", case, case.getName()
|
||||
|
||||
@@ -106,6 +106,26 @@ predicate inheritanceConversionTypes(
|
||||
toType = convert.getResultType()
|
||||
}
|
||||
|
||||
private signature class ConversionInstruction extends UnaryInstruction;
|
||||
|
||||
module Conversion<ConversionInstruction I> {
|
||||
signature predicate hasTypes(I instr, Type fromType, Type toType);
|
||||
|
||||
module Using<hasTypes/3 project> {
|
||||
pragma[nomagic]
|
||||
predicate hasOperandAndTypes(I convert, Instruction unary, Type fromType, Type toType) {
|
||||
project(convert, fromType, toType) and
|
||||
unary = convert.getUnary()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
predicate hasObjectAndField(FieldAddressInstruction fai, Instruction object, Field f) {
|
||||
fai.getObjectAddress() = object and
|
||||
fai.getField() = f
|
||||
}
|
||||
|
||||
/** Gets the HashCons value of an address computed by `instr`, if any. */
|
||||
TGlobalAddress globalAddress(Instruction instr) {
|
||||
result = TGlobalVariable(instr.(VariableAddressInstruction).getAstVariable())
|
||||
@@ -117,25 +137,27 @@ TGlobalAddress globalAddress(Instruction instr) {
|
||||
result = TLoad(globalAddress(load.getSourceAddress()))
|
||||
)
|
||||
or
|
||||
exists(ConvertInstruction convert, Type fromType, Type toType | instr = convert |
|
||||
uncheckedConversionTypes(convert, fromType, toType) and
|
||||
result = TConversion("unchecked", globalAddress(convert.getUnary()), fromType, toType)
|
||||
exists(Type fromType, Type toType, Instruction unary |
|
||||
Conversion<ConvertInstruction>::Using<uncheckedConversionTypes/3>::hasOperandAndTypes(instr,
|
||||
unary, fromType, toType) and
|
||||
result = TConversion("unchecked", globalAddress(unary), fromType, toType)
|
||||
)
|
||||
or
|
||||
exists(CheckedConvertOrNullInstruction convert, Type fromType, Type toType | instr = convert |
|
||||
checkedConversionTypes(convert, fromType, toType) and
|
||||
result = TConversion("checked", globalAddress(convert.getUnary()), fromType, toType)
|
||||
exists(Type fromType, Type toType, Instruction unary |
|
||||
Conversion<CheckedConvertOrNullInstruction>::Using<checkedConversionTypes/3>::hasOperandAndTypes(instr,
|
||||
unary, fromType, toType) and
|
||||
result = TConversion("checked", globalAddress(unary), fromType, toType)
|
||||
)
|
||||
or
|
||||
exists(InheritanceConversionInstruction convert, Type fromType, Type toType | instr = convert |
|
||||
inheritanceConversionTypes(convert, fromType, toType) and
|
||||
result = TConversion("inheritance", globalAddress(convert.getUnary()), fromType, toType)
|
||||
exists(Type fromType, Type toType, Instruction unary |
|
||||
Conversion<InheritanceConversionInstruction>::Using<inheritanceConversionTypes/3>::hasOperandAndTypes(instr,
|
||||
unary, fromType, toType) and
|
||||
result = TConversion("inheritance", globalAddress(unary), fromType, toType)
|
||||
)
|
||||
or
|
||||
exists(FieldAddressInstruction fai | instr = fai |
|
||||
result =
|
||||
TFieldAddress(globalAddress(pragma[only_bind_into](fai.getObjectAddress())),
|
||||
pragma[only_bind_out](fai.getField()))
|
||||
exists(FieldAddressInstruction fai, Instruction object, Field f | instr = fai |
|
||||
hasObjectAndField(fai, object, f) and
|
||||
result = TFieldAddress(globalAddress(object), f)
|
||||
)
|
||||
or
|
||||
result = globalAddress(instr.(PointerOffsetInstruction).getLeft())
|
||||
@@ -268,7 +290,11 @@ class PathElement extends TPathElement {
|
||||
predicate isSink(IRBlock block) { exists(this.asSink(block)) }
|
||||
|
||||
string toString() {
|
||||
result = [asStore().toString(), asCall(_).toString(), asMid().toString(), asSink(_).toString()]
|
||||
result =
|
||||
[
|
||||
this.asStore().toString(), this.asCall(_).toString(), this.asMid().toString(),
|
||||
this.asSink(_).toString()
|
||||
]
|
||||
}
|
||||
|
||||
predicate hasLocationInfo(
|
||||
|
||||
@@ -30,7 +30,7 @@ Make sure that all classes with virtual functions also have a virtual destructor
|
||||
S. Meyers. <em>Effective C++ 3d ed.</em> pp 40-44. Addison-Wesley Professional, 2005.
|
||||
</li>
|
||||
<li>
|
||||
<a href="http://blogs.msdn.com/b/oldnewthing/archive/2004/05/07/127826.aspx">When should your destructor be virtual?</a>
|
||||
<a href="https://devblogs.microsoft.com/oldnewthing/20040507-00/?p=39443">When should your destructor be virtual?</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
@@ -10,6 +10,12 @@ import cpp
|
||||
import semmle.code.cpp.ir.implementation.aliased_ssa.IR
|
||||
import semmle.code.cpp.ir.implementation.aliased_ssa.IRConsistency as IRConsistency
|
||||
|
||||
class PresentIRFunction extends IRConsistency::PresentIRFunction {
|
||||
override string toString() {
|
||||
result = min(string name | name = this.getIRFunction().getFunction().getQualifiedName() | name)
|
||||
}
|
||||
}
|
||||
|
||||
select count(Instruction i | IRConsistency::missingOperand(i, _, _, _) | i) as missingOperand,
|
||||
count(Instruction i | IRConsistency::unexpectedOperand(i, _, _, _) | i) as unexpectedOperand,
|
||||
count(Instruction i | IRConsistency::duplicateOperand(i, _, _, _) | i) as duplicateOperand,
|
||||
|
||||
@@ -21,7 +21,9 @@ class UntrustedExternalApiDataNode extends ExternalApiDataNode {
|
||||
/** DEPRECATED: Alias for UntrustedExternalApiDataNode */
|
||||
deprecated class UntrustedExternalAPIDataNode = UntrustedExternalApiDataNode;
|
||||
|
||||
/** An external API which is used with untrusted data. */
|
||||
private newtype TExternalApi =
|
||||
/** An untrusted API method `m` where untrusted data is passed at `index`. */
|
||||
TExternalApiParameter(Function f, int index) {
|
||||
exists(UntrustedExternalApiDataNode n |
|
||||
f = n.getExternalFunction() and
|
||||
|
||||
@@ -21,7 +21,9 @@ class UntrustedExternalApiDataNode extends ExternalApiDataNode {
|
||||
/** DEPRECATED: Alias for UntrustedExternalApiDataNode */
|
||||
deprecated class UntrustedExternalAPIDataNode = UntrustedExternalApiDataNode;
|
||||
|
||||
/** An external API which is used with untrusted data. */
|
||||
private newtype TExternalApi =
|
||||
/** An untrusted API method `m` where untrusted data is passed at `index`. */
|
||||
TExternalApiParameter(Function f, int index) {
|
||||
exists(UntrustedExternalApiDataNode n |
|
||||
f = n.getExternalFunction() and
|
||||
|
||||
@@ -19,6 +19,7 @@ import semmle.code.cpp.security.Security
|
||||
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
|
||||
import semmle.code.cpp.ir.IR
|
||||
import semmle.code.cpp.ir.dataflow.TaintTracking
|
||||
import semmle.code.cpp.ir.dataflow.TaintTracking2
|
||||
import semmle.code.cpp.security.FlowSources
|
||||
import semmle.code.cpp.models.implementations.Strcat
|
||||
import DataFlow::PathGraph
|
||||
@@ -83,6 +84,32 @@ class ExecState extends DataFlow::FlowState {
|
||||
DataFlow::Node getFstNode() { result = fst }
|
||||
|
||||
DataFlow::Node getSndNode() { result = snd }
|
||||
|
||||
/** Holds if this is a possible `ExecState` for `sink`. */
|
||||
predicate isFeasibleForSink(DataFlow::Node sink) {
|
||||
any(ExecStateConfiguration conf).hasFlow(snd, sink)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A `TaintTracking` configuration that's used to find the relevant `ExecState`s for a
|
||||
* given sink. This avoids a cartesian product between all sinks and all `ExecState`s in
|
||||
* `ExecTaintConfiguration::isSink`.
|
||||
*/
|
||||
class ExecStateConfiguration extends TaintTracking2::Configuration {
|
||||
ExecStateConfiguration() { this = "ExecStateConfiguration" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
exists(ExecState state | state.getSndNode() = source)
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
shellCommand(sinkAsArgumentIndirection(sink), _)
|
||||
}
|
||||
|
||||
override predicate isSanitizerOut(DataFlow::Node node) {
|
||||
isSink(node, _) // Prevent duplicates along a call chain, since `shellCommand` will include wrappers
|
||||
}
|
||||
}
|
||||
|
||||
class ExecTaintConfiguration extends TaintTracking::Configuration {
|
||||
@@ -94,8 +121,8 @@ class ExecTaintConfiguration extends TaintTracking::Configuration {
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) {
|
||||
shellCommand(sinkAsArgumentIndirection(sink), _) and
|
||||
state instanceof ExecState
|
||||
any(ExecStateConfiguration conf).isSink(sink) and
|
||||
state.(ExecState).isFeasibleForSink(sink)
|
||||
}
|
||||
|
||||
override predicate isAdditionalTaintStep(
|
||||
|
||||
@@ -17,8 +17,8 @@ import semmle.code.cpp.dataflow.DataFlow
|
||||
/**
|
||||
* A call to `SSL_get_verify_result`.
|
||||
*/
|
||||
class SSLGetVerifyResultCall extends FunctionCall {
|
||||
SSLGetVerifyResultCall() { getTarget().getName() = "SSL_get_verify_result" }
|
||||
class SslGetVerifyResultCall extends FunctionCall {
|
||||
SslGetVerifyResultCall() { getTarget().getName() = "SSL_get_verify_result" }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -29,7 +29,7 @@ class VerifyResultConfig extends DataFlow::Configuration {
|
||||
VerifyResultConfig() { this = "VerifyResultConfig" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
source.asExpr() instanceof SSLGetVerifyResultCall
|
||||
source.asExpr() instanceof SslGetVerifyResultCall
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
|
||||
@@ -17,33 +17,33 @@ import semmle.code.cpp.controlflow.IRGuards
|
||||
/**
|
||||
* A call to `SSL_get_peer_certificate`.
|
||||
*/
|
||||
class SSLGetPeerCertificateCall extends FunctionCall {
|
||||
SSLGetPeerCertificateCall() {
|
||||
class SslGetPeerCertificateCall extends FunctionCall {
|
||||
SslGetPeerCertificateCall() {
|
||||
getTarget().getName() = "SSL_get_peer_certificate" // SSL_get_peer_certificate(ssl)
|
||||
}
|
||||
|
||||
Expr getSSLArgument() { result = getArgument(0) }
|
||||
Expr getSslArgument() { result = getArgument(0) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A call to `SSL_get_verify_result`.
|
||||
*/
|
||||
class SSLGetVerifyResultCall extends FunctionCall {
|
||||
SSLGetVerifyResultCall() {
|
||||
class SslGetVerifyResultCall extends FunctionCall {
|
||||
SslGetVerifyResultCall() {
|
||||
getTarget().getName() = "SSL_get_verify_result" // SSL_get_peer_certificate(ssl)
|
||||
}
|
||||
|
||||
Expr getSSLArgument() { result = getArgument(0) }
|
||||
Expr getSslArgument() { result = getArgument(0) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the SSL object passed into `SSL_get_peer_certificate` is checked with
|
||||
* `SSL_get_verify_result` entering `node`.
|
||||
*/
|
||||
predicate resultIsChecked(SSLGetPeerCertificateCall getCertCall, ControlFlowNode node) {
|
||||
exists(Expr ssl, SSLGetVerifyResultCall check |
|
||||
ssl = globalValueNumber(getCertCall.getSSLArgument()).getAnExpr() and
|
||||
ssl = check.getSSLArgument() and
|
||||
predicate resultIsChecked(SslGetPeerCertificateCall getCertCall, ControlFlowNode node) {
|
||||
exists(Expr ssl, SslGetVerifyResultCall check |
|
||||
ssl = globalValueNumber(getCertCall.getSslArgument()).getAnExpr() and
|
||||
ssl = check.getSslArgument() and
|
||||
node = check
|
||||
)
|
||||
}
|
||||
@@ -53,7 +53,7 @@ predicate resultIsChecked(SSLGetPeerCertificateCall getCertCall, ControlFlowNode
|
||||
* `0` on the edge `node1` to `node2`.
|
||||
*/
|
||||
predicate certIsZero(
|
||||
SSLGetPeerCertificateCall getCertCall, ControlFlowNode node1, ControlFlowNode node2
|
||||
SslGetPeerCertificateCall getCertCall, ControlFlowNode node1, ControlFlowNode node2
|
||||
) {
|
||||
exists(Expr cert | cert = globalValueNumber(getCertCall).getAnExpr() |
|
||||
exists(GuardCondition guard, Expr zero |
|
||||
@@ -87,7 +87,7 @@ predicate certIsZero(
|
||||
* `SSL_get_verify_result` at `node`. Note that this is only computed at the call to
|
||||
* `SSL_get_peer_certificate` and at the start and end of `BasicBlock`s.
|
||||
*/
|
||||
predicate certNotChecked(SSLGetPeerCertificateCall getCertCall, ControlFlowNode node) {
|
||||
predicate certNotChecked(SslGetPeerCertificateCall getCertCall, ControlFlowNode node) {
|
||||
// cert is not checked at the call to `SSL_get_peer_certificate`
|
||||
node = getCertCall
|
||||
or
|
||||
@@ -112,7 +112,7 @@ predicate certNotChecked(SSLGetPeerCertificateCall getCertCall, ControlFlowNode
|
||||
)
|
||||
}
|
||||
|
||||
from SSLGetPeerCertificateCall getCertCall, ControlFlowNode node
|
||||
from SslGetPeerCertificateCall getCertCall, ControlFlowNode node
|
||||
where
|
||||
certNotChecked(getCertCall, node) and
|
||||
node instanceof Function // (function exit)
|
||||
|
||||
@@ -26,6 +26,10 @@ class ToBufferConfiguration extends TaintTracking::Configuration {
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof FlowSource }
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
node.asExpr().getUnspecifiedType() instanceof IntegralType
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
exists(BufferWrite::BufferWrite w | w.getASource() = sink.asExpr())
|
||||
}
|
||||
|
||||
@@ -47,14 +47,17 @@ class EnvData extends SystemData {
|
||||
/**
|
||||
* Data originating from a call to `mysql_get_client_info()`.
|
||||
*/
|
||||
class SQLClientInfo extends SystemData {
|
||||
SQLClientInfo() { this.(FunctionCall).getTarget().hasName("mysql_get_client_info") }
|
||||
class SqlClientInfo extends SystemData {
|
||||
SqlClientInfo() { this.(FunctionCall).getTarget().hasName("mysql_get_client_info") }
|
||||
|
||||
override DataFlow::Node getAnExpr() { result.asConvertedExpr() = this }
|
||||
|
||||
override predicate isSensitive() { any() }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for SqlClientInfo */
|
||||
deprecated class SQLClientInfo = SqlClientInfo;
|
||||
|
||||
private predicate sqlConnectInfo(FunctionCall source, Expr use) {
|
||||
(
|
||||
source.getTarget().hasName("mysql_connect") or
|
||||
@@ -66,14 +69,17 @@ private predicate sqlConnectInfo(FunctionCall source, Expr use) {
|
||||
/**
|
||||
* Data passed into an SQL connect function.
|
||||
*/
|
||||
class SQLConnectInfo extends SystemData {
|
||||
SQLConnectInfo() { sqlConnectInfo(this, _) }
|
||||
class SqlConnectInfo extends SystemData {
|
||||
SqlConnectInfo() { sqlConnectInfo(this, _) }
|
||||
|
||||
override DataFlow::Node getAnExpr() { sqlConnectInfo(this, result.asConvertedExpr()) }
|
||||
|
||||
override predicate isSensitive() { any() }
|
||||
}
|
||||
|
||||
/** DEPRECATED: Alias for SqlConnectInfo */
|
||||
deprecated class SQLConnectInfo = SqlConnectInfo;
|
||||
|
||||
private predicate posixSystemInfo(FunctionCall source, DataFlow::Node use) {
|
||||
// size_t confstr(int name, char *buf, size_t len)
|
||||
// - various OS / system strings, such as the libc version
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The "Cleartext storage of sensitive information in buffer" (`cpp/cleartext-storage-buffer`) query has been improved to produce fewer false positives.
|
||||
4
cpp/ql/src/change-notes/2022-08-23-alert-messages.md
Normal file
4
cpp/ql/src/change-notes/2022-08-23-alert-messages.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The alert message of many queries have been changed to make the message consistent with other languages.
|
||||
@@ -1,4 +1,5 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
## 0.3.2
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The query `cpp/bad-strncpy-size` now covers more `strncpy`-like functions than before, including `strxfrm`(`_l`), `wcsxfrm`(`_l`), and `stpncpy`. Users of this query may see an increase in results.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.3.1
|
||||
lastReleaseVersion: 0.3.2
|
||||
|
||||
@@ -67,7 +67,7 @@ predicate findUseCharacterConversion(Expr exp, string msg) {
|
||||
exists(FunctionCall fc |
|
||||
fc = exp and
|
||||
(
|
||||
exists(Loop lptmp | lptmp = fc.getEnclosingStmt().getParentStmt*()) and
|
||||
fc.getEnclosingStmt().getParentStmt*() instanceof Loop and
|
||||
fc.getTarget().hasName(["mbtowc", "mbrtowc", "_mbtowc_l"]) and
|
||||
not fc.getArgument(0).isConstant() and
|
||||
not fc.getArgument(1).isConstant() and
|
||||
|
||||
@@ -44,11 +44,8 @@ predicate conversionDoneLate(MulExpr mexp) {
|
||||
mexp.getEnclosingElement().(ComparisonOperation).hasOperands(mexp, e0) and
|
||||
e0.getType().getSize() = mexp.getConversion().getConversion().getType().getSize()
|
||||
or
|
||||
e0.(FunctionCall)
|
||||
.getTarget()
|
||||
.getParameter(argumentPosition(e0.(FunctionCall), mexp, _))
|
||||
.getType()
|
||||
.getSize() = mexp.getConversion().getConversion().getType().getSize()
|
||||
e0.(FunctionCall).getTarget().getParameter(argumentPosition(e0, mexp, _)).getType().getSize() =
|
||||
mexp.getConversion().getConversion().getType().getSize()
|
||||
)
|
||||
)
|
||||
}
|
||||
@@ -75,7 +72,7 @@ predicate signSmallerWithEqualSizes(MulExpr mexp) {
|
||||
ae.getRValue().getUnderlyingType().(IntegralType).isUnsigned() and
|
||||
ae.getLValue().getUnderlyingType().(IntegralType).isSigned() and
|
||||
(
|
||||
not exists(DivExpr de | mexp.getParent*() = de)
|
||||
not mexp.getParent*() instanceof DivExpr
|
||||
or
|
||||
exists(DivExpr de, Expr ec |
|
||||
e2.isConstant() and
|
||||
|
||||
@@ -33,7 +33,7 @@ Make sure that all classes with virtual functions also have a virtual destructor
|
||||
S. Meyers. <em>Effective C++ 3d ed.</em> pp 40-44. Addison-Wesley Professional, 2005.
|
||||
</li>
|
||||
<li>
|
||||
<a href="http://blogs.msdn.com/b/oldnewthing/archive/2004/05/07/127826.aspx">When should your destructor be virtual?</a>
|
||||
<a href="https://devblogs.microsoft.com/oldnewthing/20040507-00/?p=39443">When should your destructor be virtual?</a>
|
||||
</li>
|
||||
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-queries
|
||||
version: 0.3.2-dev
|
||||
version: 0.3.3-dev
|
||||
groups:
|
||||
- cpp
|
||||
- queries
|
||||
|
||||
@@ -330,6 +330,19 @@ abstract private class Expectation extends FailureLocatable {
|
||||
override Location getLocation() { result = comment.getLocation() }
|
||||
}
|
||||
|
||||
private predicate onSameLine(ValidExpectation a, ActualResult b) {
|
||||
exists(string fname, int line, Location la, Location lb |
|
||||
// Join order intent:
|
||||
// Take the locations of ActualResults,
|
||||
// join with locations in the same file / on the same line,
|
||||
// then match those against ValidExpectations.
|
||||
la = a.getLocation() and
|
||||
pragma[only_bind_into](lb) = b.getLocation() and
|
||||
pragma[only_bind_into](la).hasLocationInfo(fname, line, _, _, _) and
|
||||
lb.hasLocationInfo(fname, line, _, _, _)
|
||||
)
|
||||
}
|
||||
|
||||
private class ValidExpectation extends Expectation, TValidExpectation {
|
||||
string tag;
|
||||
string value;
|
||||
@@ -344,8 +357,7 @@ private class ValidExpectation extends Expectation, TValidExpectation {
|
||||
string getKnownFailure() { result = knownFailure }
|
||||
|
||||
predicate matchesActualResult(ActualResult actualResult) {
|
||||
getLocation().getStartLine() = actualResult.getLocation().getStartLine() and
|
||||
getLocation().getFile() = actualResult.getLocation().getFile() and
|
||||
onSameLine(pragma[only_bind_into](this), actualResult) and
|
||||
getTag() = actualResult.getTag() and
|
||||
getValue() = actualResult.getValue()
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
|
||||
import cpp
|
||||
private import semmle.code.cpp.ir.dataflow.DataFlow::DataFlow as IRDataFlow
|
||||
private import semmle.code.cpp.dataflow.DataFlow::DataFlow as ASTDataFlow
|
||||
private import semmle.code.cpp.dataflow.DataFlow::DataFlow as AstDataFlow
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
|
||||
class IRFlowTest extends InlineExpectationsTest {
|
||||
@@ -49,11 +49,11 @@ class AstFlowTest extends InlineExpectationsTest {
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(
|
||||
ASTDataFlow::Node source, ASTDataFlow::Node sink, ASTDataFlow::Configuration conf, int n
|
||||
AstDataFlow::Node source, AstDataFlow::Node sink, AstDataFlow::Configuration conf, int n
|
||||
|
|
||||
tag = "ast" and
|
||||
conf.hasFlow(source, sink) and
|
||||
n = strictcount(ASTDataFlow::Node otherSource | conf.hasFlow(otherSource, sink)) and
|
||||
n = strictcount(AstDataFlow::Node otherSource | conf.hasFlow(otherSource, sink)) and
|
||||
(
|
||||
n = 1 and value = ""
|
||||
or
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.security.TaintTrackingImpl as ASTTaintTracking
|
||||
import semmle.code.cpp.security.TaintTrackingImpl as AstTaintTracking
|
||||
import semmle.code.cpp.ir.dataflow.DefaultTaintTracking as IRDefaultTaintTracking
|
||||
import IRDefaultTaintTracking::TaintedWithPath as TaintedWithPath
|
||||
import TaintedWithPath::Private
|
||||
@@ -17,7 +17,7 @@ predicate isSinkArgument(Element sink) {
|
||||
)
|
||||
}
|
||||
|
||||
predicate astTaint(Expr source, Element sink) { ASTTaintTracking::tainted(source, sink) }
|
||||
predicate astTaint(Expr source, Element sink) { AstTaintTracking::tainted(source, sink) }
|
||||
|
||||
class SourceConfiguration extends TaintedWithPath::TaintTrackingConfiguration {
|
||||
override predicate isSink(Element e) { isSinkArgument(e) }
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.security.TaintTrackingImpl as ASTTaintTracking
|
||||
import semmle.code.cpp.security.TaintTrackingImpl as AstTaintTracking
|
||||
import semmle.code.cpp.ir.dataflow.DefaultTaintTracking as IRDefaultTaintTracking
|
||||
import IRDefaultTaintTracking::TaintedWithPath as TaintedWithPath
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
@@ -18,7 +18,7 @@ predicate argToSinkCall(Element sink) {
|
||||
}
|
||||
|
||||
predicate astTaint(Expr source, Element sink) {
|
||||
ASTTaintTracking::tainted(source, sink) and argToSinkCall(sink)
|
||||
AstTaintTracking::tainted(source, sink) and argToSinkCall(sink)
|
||||
}
|
||||
|
||||
class SourceConfiguration extends TaintedWithPath::TaintTrackingConfiguration {
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.security.Security
|
||||
import semmle.code.cpp.security.TaintTrackingImpl as ASTTaintTracking
|
||||
import semmle.code.cpp.security.TaintTrackingImpl as AstTaintTracking
|
||||
import semmle.code.cpp.ir.dataflow.DefaultTaintTracking as IRDefaultTaintTracking
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
|
||||
predicate astTaint(Expr source, Element sink, string globalVar) {
|
||||
ASTTaintTracking::taintedIncludingGlobalVars(source, sink, globalVar) and globalVar != ""
|
||||
AstTaintTracking::taintedIncludingGlobalVars(source, sink, globalVar) and globalVar != ""
|
||||
}
|
||||
|
||||
predicate irTaint(Expr source, Element sink, string globalVar) {
|
||||
|
||||
@@ -7,7 +7,7 @@ string describe(File f) {
|
||||
f.compiledAsCpp() and
|
||||
result = "C++"
|
||||
or
|
||||
f instanceof XMLParent and
|
||||
f instanceof XmlParent and
|
||||
result = "XMLParent" // regression tests a bug in the characteristic predicate of XMLParent
|
||||
}
|
||||
|
||||
|
||||
@@ -13975,6 +13975,192 @@ ir.cpp:
|
||||
# 1815| Type = [IntType] int
|
||||
# 1815| ValueCategory = prvalue(load)
|
||||
# 1817| getStmt(8): [ReturnStmt] return ...
|
||||
# 1834| [CopyAssignmentOperator] block_assignment::A& block_assignment::A::operator=(block_assignment::A const&)
|
||||
# 1834| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [LValueReferenceType] const A &
|
||||
# 1834| [MoveAssignmentOperator] block_assignment::A& block_assignment::A::operator=(block_assignment::A&&)
|
||||
# 1834| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [RValueReferenceType] A &&
|
||||
#-----| getEntryPoint(): [BlockStmt] { ... }
|
||||
#-----| getStmt(0): [ExprStmt] ExprStmt
|
||||
#-----| getExpr(): [BlockAssignExpr] ... = ...
|
||||
#-----| Type = [VoidType] void
|
||||
#-----| ValueCategory = prvalue
|
||||
#-----| getLValue(): [PointerFieldAccess] e
|
||||
#-----| Type = [ArrayType] enum <unnamed>[1]
|
||||
#-----| ValueCategory = lvalue
|
||||
#-----| getQualifier(): [ThisExpr] this
|
||||
#-----| Type = [PointerType] A *
|
||||
#-----| ValueCategory = prvalue(load)
|
||||
#-----| getRValue(): [ReferenceFieldAccess] e
|
||||
#-----| Type = [ArrayType] enum <unnamed>[1]
|
||||
#-----| ValueCategory = lvalue
|
||||
#-----| getQualifier(): [VariableAccess] (unnamed parameter 0)
|
||||
#-----| Type = [RValueReferenceType] A &&
|
||||
#-----| ValueCategory = prvalue(load)
|
||||
#-----| getQualifier().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
|
||||
#-----| Type = [Class] A
|
||||
#-----| ValueCategory = lvalue
|
||||
#-----| getStmt(1): [ReturnStmt] return ...
|
||||
#-----| getExpr(): [PointerDereferenceExpr] * ...
|
||||
#-----| Type = [Class] A
|
||||
#-----| ValueCategory = lvalue
|
||||
#-----| getOperand(): [ThisExpr] this
|
||||
#-----| Type = [PointerType] A *
|
||||
#-----| ValueCategory = prvalue(load)
|
||||
#-----| getExpr().getFullyConverted(): [ReferenceToExpr] (reference to)
|
||||
#-----| Type = [LValueReferenceType] A &
|
||||
#-----| ValueCategory = prvalue
|
||||
# 1834| [Constructor] void block_assignment::A::A()
|
||||
# 1834| <params>:
|
||||
# 1834| [CopyConstructor] void block_assignment::A::A(block_assignment::A const&)
|
||||
# 1834| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [LValueReferenceType] const A &
|
||||
# 1834| [MoveConstructor] void block_assignment::A::A(block_assignment::A&&)
|
||||
# 1834| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [RValueReferenceType] A &&
|
||||
# 1836| [VirtualFunction] void block_assignment::A::f()
|
||||
# 1836| <params>:
|
||||
# 1839| [CopyAssignmentOperator] block_assignment::B& block_assignment::B::operator=(block_assignment::B const&)
|
||||
# 1839| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [LValueReferenceType] const B &
|
||||
# 1839| [MoveAssignmentOperator] block_assignment::B& block_assignment::B::operator=(block_assignment::B&&)
|
||||
# 1839| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [RValueReferenceType] B &&
|
||||
#-----| getEntryPoint(): [BlockStmt] { ... }
|
||||
#-----| getStmt(0): [ExprStmt] ExprStmt
|
||||
# 1839| getExpr(): [FunctionCall] call to operator=
|
||||
# 1839| Type = [LValueReferenceType] A &
|
||||
# 1839| ValueCategory = prvalue
|
||||
# 1839| getQualifier(): [ThisExpr] this
|
||||
# 1839| Type = [PointerType] B *
|
||||
# 1839| ValueCategory = prvalue(load)
|
||||
# 1839| getArgument(0): [PointerDereferenceExpr] * ...
|
||||
# 1839| Type = [Class] A
|
||||
# 1839| ValueCategory = xvalue
|
||||
# 1839| getOperand(): [AddressOfExpr] & ...
|
||||
# 1839| Type = [PointerType] B *
|
||||
# 1839| ValueCategory = prvalue
|
||||
# 1839| getOperand(): [VariableAccess] (unnamed parameter 0)
|
||||
# 1839| Type = [RValueReferenceType] B &&
|
||||
# 1839| ValueCategory = prvalue(load)
|
||||
#-----| getOperand().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
|
||||
#-----| Type = [Struct] B
|
||||
#-----| ValueCategory = lvalue
|
||||
#-----| getOperand().getFullyConverted(): [CStyleCast] (A *)...
|
||||
#-----| Conversion = [BaseClassConversion] base class conversion
|
||||
#-----| Type = [PointerType] A *
|
||||
#-----| ValueCategory = prvalue
|
||||
#-----| getQualifier().getFullyConverted(): [CStyleCast] (A *)...
|
||||
#-----| Conversion = [BaseClassConversion] base class conversion
|
||||
#-----| Type = [PointerType] A *
|
||||
#-----| ValueCategory = prvalue
|
||||
#-----| getArgument(0).getFullyConverted(): [ReferenceToExpr] (reference to)
|
||||
#-----| Type = [LValueReferenceType] A &
|
||||
#-----| ValueCategory = prvalue
|
||||
#-----| getExpr().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
|
||||
#-----| Type = [Class] A
|
||||
#-----| ValueCategory = lvalue
|
||||
#-----| getStmt(1): [ReturnStmt] return ...
|
||||
#-----| getExpr(): [PointerDereferenceExpr] * ...
|
||||
#-----| Type = [Struct] B
|
||||
#-----| ValueCategory = lvalue
|
||||
#-----| getOperand(): [ThisExpr] this
|
||||
#-----| Type = [PointerType] B *
|
||||
#-----| ValueCategory = prvalue(load)
|
||||
#-----| getExpr().getFullyConverted(): [ReferenceToExpr] (reference to)
|
||||
#-----| Type = [LValueReferenceType] B &
|
||||
#-----| ValueCategory = prvalue
|
||||
# 1839| [CopyConstructor] void block_assignment::B::B(block_assignment::B const&)
|
||||
# 1839| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [LValueReferenceType] const B &
|
||||
# 1839| [MoveConstructor] void block_assignment::B::B(block_assignment::B&&)
|
||||
# 1839| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [RValueReferenceType] B &&
|
||||
# 1840| [Constructor] void block_assignment::B::B(block_assignment::A*)
|
||||
# 1840| <params>:
|
||||
# 1840| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
# 1840| Type = [PointerType] A *
|
||||
# 1843| [TopLevelFunction] void block_assignment::foo()
|
||||
# 1843| <params>:
|
||||
# 1843| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 1844| getStmt(0): [DeclStmt] declaration
|
||||
# 1844| getDeclarationEntry(0): [VariableDeclarationEntry] definition of v
|
||||
# 1844| Type = [Struct] B
|
||||
# 1844| getVariable().getInitializer(): [Initializer] initializer for v
|
||||
# 1844| getExpr(): [ConstructorCall] call to B
|
||||
# 1844| Type = [VoidType] void
|
||||
# 1844| ValueCategory = prvalue
|
||||
# 1844| getArgument(0): [Literal] 0
|
||||
# 1844| Type = [IntType] int
|
||||
# 1844| Value = [Literal] 0
|
||||
# 1844| ValueCategory = prvalue
|
||||
# 1844| getArgument(0).getFullyConverted(): [CStyleCast] (A *)...
|
||||
# 1844| Conversion = [IntegralToPointerConversion] integral to pointer conversion
|
||||
# 1844| Type = [PointerType] A *
|
||||
# 1844| Value = [CStyleCast] 0
|
||||
# 1844| ValueCategory = prvalue
|
||||
# 1845| getStmt(1): [ExprStmt] ExprStmt
|
||||
# 1845| getExpr(): [FunctionCall] call to operator=
|
||||
# 1845| Type = [LValueReferenceType] B &
|
||||
# 1845| ValueCategory = prvalue
|
||||
# 1845| getQualifier(): [VariableAccess] v
|
||||
# 1845| Type = [Struct] B
|
||||
# 1845| ValueCategory = lvalue
|
||||
# 1845| getArgument(0): [ConstructorCall] call to B
|
||||
# 1845| Type = [VoidType] void
|
||||
# 1845| ValueCategory = prvalue
|
||||
# 1845| getArgument(0): [Literal] 0
|
||||
# 1845| Type = [IntType] int
|
||||
# 1845| Value = [Literal] 0
|
||||
# 1845| ValueCategory = prvalue
|
||||
# 1845| getArgument(0).getFullyConverted(): [CStyleCast] (A *)...
|
||||
# 1845| Conversion = [IntegralToPointerConversion] integral to pointer conversion
|
||||
# 1845| Type = [PointerType] A *
|
||||
# 1845| Value = [CStyleCast] 0
|
||||
# 1845| ValueCategory = prvalue
|
||||
# 1845| getArgument(0).getFullyConverted(): [ReferenceToExpr] (reference to)
|
||||
# 1845| Type = [LValueReferenceType] B &
|
||||
# 1845| ValueCategory = prvalue
|
||||
# 1845| getExpr(): [TemporaryObjectExpr] temporary object
|
||||
# 1845| Type = [Struct] B
|
||||
# 1845| ValueCategory = lvalue
|
||||
# 1845| getExpr().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
|
||||
# 1845| Type = [Struct] B
|
||||
# 1845| ValueCategory = lvalue
|
||||
# 1846| getStmt(2): [ReturnStmt] return ...
|
||||
# 1849| [TopLevelFunction] void magicvars()
|
||||
# 1849| <params>:
|
||||
# 1849| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 1850| getStmt(0): [DeclStmt] declaration
|
||||
# 1850| getDeclarationEntry(0): [VariableDeclarationEntry] definition of pf
|
||||
# 1850| Type = [PointerType] const char *
|
||||
# 1850| getVariable().getInitializer(): [Initializer] initializer for pf
|
||||
# 1850| getExpr(): [VariableAccess] __PRETTY_FUNCTION__
|
||||
# 1850| Type = [ArrayType] const char[17]
|
||||
# 1850| ValueCategory = lvalue
|
||||
# 1850| getExpr().getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion
|
||||
# 1850| Type = [PointerType] const char *
|
||||
# 1850| ValueCategory = prvalue
|
||||
# 1851| getStmt(1): [DeclStmt] declaration
|
||||
# 1851| getDeclarationEntry(0): [VariableDeclarationEntry] definition of strfunc
|
||||
# 1851| Type = [PointerType] const char *
|
||||
# 1851| getVariable().getInitializer(): [Initializer] initializer for strfunc
|
||||
# 1851| getExpr(): [VariableAccess] __func__
|
||||
# 1851| Type = [ArrayType] const char[10]
|
||||
# 1851| ValueCategory = lvalue
|
||||
# 1851| getExpr().getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion
|
||||
# 1851| Type = [PointerType] const char *
|
||||
# 1851| ValueCategory = prvalue
|
||||
# 1852| getStmt(2): [ReturnStmt] return ...
|
||||
perf-regression.cpp:
|
||||
# 4| [CopyAssignmentOperator] Big& Big::operator=(Big const&)
|
||||
# 4| <params>:
|
||||
|
||||
@@ -1830,4 +1830,25 @@ char *global_string = "global string";
|
||||
|
||||
int global_6 = global_2;
|
||||
|
||||
namespace block_assignment {
|
||||
class A {
|
||||
enum {} e[1];
|
||||
virtual void f();
|
||||
};
|
||||
|
||||
struct B : A {
|
||||
B(A *);
|
||||
};
|
||||
|
||||
void foo() {
|
||||
B v(0);
|
||||
v = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void magicvars() {
|
||||
const char *pf = __PRETTY_FUNCTION__;
|
||||
const char *strfunc = __func__;
|
||||
}
|
||||
|
||||
// semmle-extractor-options: -std=c++17 --clang
|
||||
|
||||
@@ -671,6 +671,10 @@
|
||||
| file://:0:0:0:0 | Address | &:r0_1 |
|
||||
| file://:0:0:0:0 | Address | &:r0_1 |
|
||||
| file://:0:0:0:0 | Address | &:r0_1 |
|
||||
| file://:0:0:0:0 | Address | &:r0_1 |
|
||||
| file://:0:0:0:0 | Address | &:r0_1 |
|
||||
| file://:0:0:0:0 | Address | &:r0_1 |
|
||||
| file://:0:0:0:0 | Address | &:r0_1 |
|
||||
| file://:0:0:0:0 | Address | &:r0_2 |
|
||||
| file://:0:0:0:0 | Address | &:r0_3 |
|
||||
| file://:0:0:0:0 | Address | &:r0_3 |
|
||||
@@ -691,6 +695,13 @@
|
||||
| file://:0:0:0:0 | Address | &:r0_3 |
|
||||
| file://:0:0:0:0 | Address | &:r0_3 |
|
||||
| file://:0:0:0:0 | Address | &:r0_3 |
|
||||
| file://:0:0:0:0 | Address | &:r0_3 |
|
||||
| file://:0:0:0:0 | Address | &:r0_3 |
|
||||
| file://:0:0:0:0 | Address | &:r0_3 |
|
||||
| file://:0:0:0:0 | Address | &:r0_3 |
|
||||
| file://:0:0:0:0 | Address | &:r0_5 |
|
||||
| file://:0:0:0:0 | Address | &:r0_5 |
|
||||
| file://:0:0:0:0 | Address | &:r0_5 |
|
||||
| file://:0:0:0:0 | Address | &:r0_5 |
|
||||
| file://:0:0:0:0 | Address | &:r0_5 |
|
||||
| file://:0:0:0:0 | Address | &:r0_5 |
|
||||
@@ -699,6 +710,10 @@
|
||||
| file://:0:0:0:0 | Address | &:r0_5 |
|
||||
| file://:0:0:0:0 | Address | &:r0_6 |
|
||||
| file://:0:0:0:0 | Address | &:r0_7 |
|
||||
| file://:0:0:0:0 | Address | &:r0_7 |
|
||||
| file://:0:0:0:0 | Address | &:r0_8 |
|
||||
| file://:0:0:0:0 | Address | &:r0_8 |
|
||||
| file://:0:0:0:0 | Address | &:r0_8 |
|
||||
| file://:0:0:0:0 | Address | &:r0_8 |
|
||||
| file://:0:0:0:0 | Address | &:r0_8 |
|
||||
| file://:0:0:0:0 | Address | &:r0_8 |
|
||||
@@ -708,10 +723,15 @@
|
||||
| file://:0:0:0:0 | Address | &:r0_10 |
|
||||
| file://:0:0:0:0 | Address | &:r0_11 |
|
||||
| file://:0:0:0:0 | Address | &:r0_11 |
|
||||
| file://:0:0:0:0 | Address | &:r0_11 |
|
||||
| file://:0:0:0:0 | Address | &:r0_13 |
|
||||
| file://:0:0:0:0 | Address | &:r0_15 |
|
||||
| file://:0:0:0:0 | Address | &:r0_15 |
|
||||
| file://:0:0:0:0 | Address | &:r0_15 |
|
||||
| file://:0:0:0:0 | Address | &:r0_15 |
|
||||
| file://:0:0:0:0 | Address | &:r0_16 |
|
||||
| file://:0:0:0:0 | Address | &:r0_16 |
|
||||
| file://:0:0:0:0 | Address | &:r0_17 |
|
||||
| file://:0:0:0:0 | Address | &:r0_18 |
|
||||
| file://:0:0:0:0 | Address | &:r0_18 |
|
||||
| file://:0:0:0:0 | Address | &:r0_19 |
|
||||
@@ -719,6 +739,7 @@
|
||||
| file://:0:0:0:0 | Arg(0) | 0:r0_6 |
|
||||
| file://:0:0:0:0 | Arg(0) | 0:r0_8 |
|
||||
| file://:0:0:0:0 | Arg(0) | 0:r0_8 |
|
||||
| file://:0:0:0:0 | Arg(0) | 0:r0_8 |
|
||||
| file://:0:0:0:0 | Arg(0) | 0:r0_15 |
|
||||
| file://:0:0:0:0 | Arg(0) | 0:r0_15 |
|
||||
| file://:0:0:0:0 | CallTarget | func:r0_1 |
|
||||
@@ -731,8 +752,12 @@
|
||||
| file://:0:0:0:0 | ChiPartial | partial:m0_8 |
|
||||
| file://:0:0:0:0 | ChiPartial | partial:m0_11 |
|
||||
| file://:0:0:0:0 | ChiPartial | partial:m0_11 |
|
||||
| file://:0:0:0:0 | ChiPartial | partial:m0_11 |
|
||||
| file://:0:0:0:0 | ChiPartial | partial:m0_13 |
|
||||
| file://:0:0:0:0 | ChiPartial | partial:m0_13 |
|
||||
| file://:0:0:0:0 | ChiTotal | total:m0_3 |
|
||||
| file://:0:0:0:0 | ChiTotal | total:m0_4 |
|
||||
| file://:0:0:0:0 | ChiTotal | total:m0_4 |
|
||||
| file://:0:0:0:0 | ChiTotal | total:m754_8 |
|
||||
| file://:0:0:0:0 | ChiTotal | total:m763_8 |
|
||||
| file://:0:0:0:0 | ChiTotal | total:m1043_10 |
|
||||
@@ -740,6 +765,8 @@
|
||||
| file://:0:0:0:0 | ChiTotal | total:m1688_3 |
|
||||
| file://:0:0:0:0 | ChiTotal | total:m1716_8 |
|
||||
| file://:0:0:0:0 | ChiTotal | total:m1716_19 |
|
||||
| file://:0:0:0:0 | ChiTotal | total:m1834_8 |
|
||||
| file://:0:0:0:0 | ChiTotal | total:m1839_8 |
|
||||
| file://:0:0:0:0 | Left | r0_2 |
|
||||
| file://:0:0:0:0 | Left | r0_4 |
|
||||
| file://:0:0:0:0 | Left | r0_7 |
|
||||
@@ -753,6 +780,9 @@
|
||||
| file://:0:0:0:0 | Load | m0_2 |
|
||||
| file://:0:0:0:0 | Load | m0_2 |
|
||||
| file://:0:0:0:0 | Load | m0_2 |
|
||||
| file://:0:0:0:0 | Load | m0_2 |
|
||||
| file://:0:0:0:0 | Load | m0_2 |
|
||||
| file://:0:0:0:0 | Load | m0_2 |
|
||||
| file://:0:0:0:0 | Load | m745_6 |
|
||||
| file://:0:0:0:0 | Load | m754_6 |
|
||||
| file://:0:0:0:0 | Load | m763_6 |
|
||||
@@ -760,6 +790,10 @@
|
||||
| file://:0:0:0:0 | Load | m1466_4 |
|
||||
| file://:0:0:0:0 | Load | m1685_7 |
|
||||
| file://:0:0:0:0 | Load | m1714_7 |
|
||||
| file://:0:0:0:0 | Load | m1834_6 |
|
||||
| file://:0:0:0:0 | Load | m1834_6 |
|
||||
| file://:0:0:0:0 | Load | m1839_6 |
|
||||
| file://:0:0:0:0 | Load | ~m0_4 |
|
||||
| file://:0:0:0:0 | Load | ~m1444_6 |
|
||||
| file://:0:0:0:0 | Load | ~m1712_10 |
|
||||
| file://:0:0:0:0 | Load | ~m1712_14 |
|
||||
@@ -776,6 +810,8 @@
|
||||
| file://:0:0:0:0 | SideEffect | m0_4 |
|
||||
| file://:0:0:0:0 | SideEffect | m0_4 |
|
||||
| file://:0:0:0:0 | SideEffect | m0_4 |
|
||||
| file://:0:0:0:0 | SideEffect | m0_4 |
|
||||
| file://:0:0:0:0 | SideEffect | m0_14 |
|
||||
| file://:0:0:0:0 | SideEffect | m1078_23 |
|
||||
| file://:0:0:0:0 | SideEffect | m1078_23 |
|
||||
| file://:0:0:0:0 | SideEffect | m1084_23 |
|
||||
@@ -785,6 +821,7 @@
|
||||
| file://:0:0:0:0 | SideEffect | ~m0_4 |
|
||||
| file://:0:0:0:0 | SideEffect | ~m0_4 |
|
||||
| file://:0:0:0:0 | SideEffect | ~m0_4 |
|
||||
| file://:0:0:0:0 | SideEffect | ~m0_4 |
|
||||
| file://:0:0:0:0 | SideEffect | ~m96_8 |
|
||||
| file://:0:0:0:0 | SideEffect | ~m754_8 |
|
||||
| file://:0:0:0:0 | SideEffect | ~m763_8 |
|
||||
@@ -794,6 +831,7 @@
|
||||
| file://:0:0:0:0 | SideEffect | ~m1077_8 |
|
||||
| file://:0:0:0:0 | SideEffect | ~m1240_4 |
|
||||
| file://:0:0:0:0 | SideEffect | ~m1447_6 |
|
||||
| file://:0:0:0:0 | SideEffect | ~m1839_8 |
|
||||
| file://:0:0:0:0 | StoreValue | r0_1 |
|
||||
| file://:0:0:0:0 | StoreValue | r0_1 |
|
||||
| file://:0:0:0:0 | StoreValue | r0_1 |
|
||||
@@ -807,8 +845,11 @@
|
||||
| file://:0:0:0:0 | StoreValue | r0_6 |
|
||||
| file://:0:0:0:0 | StoreValue | r0_7 |
|
||||
| file://:0:0:0:0 | StoreValue | r0_9 |
|
||||
| file://:0:0:0:0 | StoreValue | r0_12 |
|
||||
| file://:0:0:0:0 | StoreValue | r0_13 |
|
||||
| file://:0:0:0:0 | StoreValue | r0_13 |
|
||||
| file://:0:0:0:0 | StoreValue | r0_19 |
|
||||
| file://:0:0:0:0 | StoreValue | r0_20 |
|
||||
| file://:0:0:0:0 | StoreValue | r0_22 |
|
||||
| file://:0:0:0:0 | StoreValue | r0_22 |
|
||||
| file://:0:0:0:0 | Unary | r0_1 |
|
||||
@@ -821,18 +862,27 @@
|
||||
| file://:0:0:0:0 | Unary | r0_6 |
|
||||
| file://:0:0:0:0 | Unary | r0_6 |
|
||||
| file://:0:0:0:0 | Unary | r0_6 |
|
||||
| file://:0:0:0:0 | Unary | r0_6 |
|
||||
| file://:0:0:0:0 | Unary | r0_6 |
|
||||
| file://:0:0:0:0 | Unary | r0_7 |
|
||||
| file://:0:0:0:0 | Unary | r0_7 |
|
||||
| file://:0:0:0:0 | Unary | r0_7 |
|
||||
| file://:0:0:0:0 | Unary | r0_7 |
|
||||
| file://:0:0:0:0 | Unary | r0_8 |
|
||||
| file://:0:0:0:0 | Unary | r0_9 |
|
||||
| file://:0:0:0:0 | Unary | r0_9 |
|
||||
| file://:0:0:0:0 | Unary | r0_9 |
|
||||
| file://:0:0:0:0 | Unary | r0_10 |
|
||||
| file://:0:0:0:0 | Unary | r0_10 |
|
||||
| file://:0:0:0:0 | Unary | r0_10 |
|
||||
| file://:0:0:0:0 | Unary | r0_11 |
|
||||
| file://:0:0:0:0 | Unary | r0_12 |
|
||||
| file://:0:0:0:0 | Unary | r0_14 |
|
||||
| file://:0:0:0:0 | Unary | r0_14 |
|
||||
| file://:0:0:0:0 | Unary | r0_17 |
|
||||
| file://:0:0:0:0 | Unary | r0_18 |
|
||||
| file://:0:0:0:0 | Unary | r0_18 |
|
||||
| file://:0:0:0:0 | Unary | r0_19 |
|
||||
| file://:0:0:0:0 | Unary | r0_20 |
|
||||
| file://:0:0:0:0 | Unary | r0_20 |
|
||||
| file://:0:0:0:0 | Unary | r0_21 |
|
||||
@@ -8363,6 +8413,102 @@
|
||||
| ir.cpp:1831:16:1831:23 | ChiTotal | total:m1831_2 |
|
||||
| ir.cpp:1831:16:1831:23 | Load | ~m1831_2 |
|
||||
| ir.cpp:1831:16:1831:23 | StoreValue | r1831_5 |
|
||||
| ir.cpp:1834:11:1834:11 | Address | &:r1834_5 |
|
||||
| ir.cpp:1834:11:1834:11 | Address | &:r1834_5 |
|
||||
| ir.cpp:1834:11:1834:11 | Address | &:r1834_7 |
|
||||
| ir.cpp:1834:11:1834:11 | Address | &:r1834_7 |
|
||||
| ir.cpp:1834:11:1834:11 | Address | &:r1834_10 |
|
||||
| ir.cpp:1834:11:1834:11 | ChiPartial | partial:m1834_3 |
|
||||
| ir.cpp:1834:11:1834:11 | ChiTotal | total:m1834_2 |
|
||||
| ir.cpp:1834:11:1834:11 | Load | m0_20 |
|
||||
| ir.cpp:1834:11:1834:11 | Load | m1834_6 |
|
||||
| ir.cpp:1834:11:1834:11 | SideEffect | m0_14 |
|
||||
| ir.cpp:1834:11:1834:11 | SideEffect | m1834_3 |
|
||||
| ir.cpp:1839:12:1839:12 | Address | &:r1839_5 |
|
||||
| ir.cpp:1839:12:1839:12 | Address | &:r1839_5 |
|
||||
| ir.cpp:1839:12:1839:12 | Address | &:r1839_7 |
|
||||
| ir.cpp:1839:12:1839:12 | Address | &:r1839_7 |
|
||||
| ir.cpp:1839:12:1839:12 | Address | &:r1839_9 |
|
||||
| ir.cpp:1839:12:1839:12 | Address | &:r1839_12 |
|
||||
| ir.cpp:1839:12:1839:12 | Address | &:r1839_20 |
|
||||
| ir.cpp:1839:12:1839:12 | Arg(this) | this:r0_5 |
|
||||
| ir.cpp:1839:12:1839:12 | CallTarget | func:r1839_11 |
|
||||
| ir.cpp:1839:12:1839:12 | ChiPartial | partial:m1839_3 |
|
||||
| ir.cpp:1839:12:1839:12 | ChiPartial | partial:m1839_17 |
|
||||
| ir.cpp:1839:12:1839:12 | ChiTotal | total:m1839_2 |
|
||||
| ir.cpp:1839:12:1839:12 | ChiTotal | total:m1839_4 |
|
||||
| ir.cpp:1839:12:1839:12 | Load | m0_2 |
|
||||
| ir.cpp:1839:12:1839:12 | Load | m0_21 |
|
||||
| ir.cpp:1839:12:1839:12 | Load | m1839_6 |
|
||||
| ir.cpp:1839:12:1839:12 | Load | m1839_6 |
|
||||
| ir.cpp:1839:12:1839:12 | SideEffect | m0_12 |
|
||||
| ir.cpp:1839:12:1839:12 | SideEffect | ~m1839_4 |
|
||||
| ir.cpp:1839:12:1839:12 | SideEffect | ~m1839_18 |
|
||||
| ir.cpp:1839:12:1839:12 | Unary | r1839_10 |
|
||||
| ir.cpp:1839:12:1839:12 | Unary | r1839_13 |
|
||||
| ir.cpp:1839:12:1839:12 | Unary | r1839_14 |
|
||||
| ir.cpp:1839:12:1839:12 | Unary | r1839_15 |
|
||||
| ir.cpp:1839:12:1839:12 | Unary | r1839_16 |
|
||||
| ir.cpp:1843:10:1843:12 | ChiPartial | partial:m1843_3 |
|
||||
| ir.cpp:1843:10:1843:12 | ChiTotal | total:m1843_2 |
|
||||
| ir.cpp:1843:10:1843:12 | SideEffect | ~m1845_18 |
|
||||
| ir.cpp:1844:11:1844:11 | Address | &:r1844_1 |
|
||||
| ir.cpp:1844:11:1844:11 | Address | &:r1844_1 |
|
||||
| ir.cpp:1844:11:1844:11 | Arg(this) | this:r1844_1 |
|
||||
| ir.cpp:1844:13:1844:13 | Address | &:r1844_4 |
|
||||
| ir.cpp:1844:13:1844:13 | Address | &:r1844_4 |
|
||||
| ir.cpp:1844:13:1844:13 | Arg(0) | 0:r1844_4 |
|
||||
| ir.cpp:1844:13:1844:13 | ChiPartial | partial:m1844_11 |
|
||||
| ir.cpp:1844:13:1844:13 | ChiTotal | total:m1844_7 |
|
||||
| ir.cpp:1844:13:1844:13 | SideEffect | ~m1844_7 |
|
||||
| ir.cpp:1844:13:1844:14 | CallTarget | func:r1844_3 |
|
||||
| ir.cpp:1844:13:1844:14 | ChiPartial | partial:m1844_6 |
|
||||
| ir.cpp:1844:13:1844:14 | ChiPartial | partial:m1844_9 |
|
||||
| ir.cpp:1844:13:1844:14 | ChiTotal | total:m1843_4 |
|
||||
| ir.cpp:1844:13:1844:14 | ChiTotal | total:m1844_2 |
|
||||
| ir.cpp:1844:13:1844:14 | SideEffect | ~m1843_4 |
|
||||
| ir.cpp:1845:9:1845:9 | Address | &:r1845_1 |
|
||||
| ir.cpp:1845:9:1845:9 | Address | &:r1845_1 |
|
||||
| ir.cpp:1845:9:1845:9 | Arg(this) | this:r1845_1 |
|
||||
| ir.cpp:1845:9:1845:9 | ChiPartial | partial:m1845_21 |
|
||||
| ir.cpp:1845:9:1845:9 | ChiTotal | total:m1844_10 |
|
||||
| ir.cpp:1845:9:1845:9 | SideEffect | m1844_10 |
|
||||
| ir.cpp:1845:11:1845:11 | CallTarget | func:r1845_2 |
|
||||
| ir.cpp:1845:11:1845:11 | ChiPartial | partial:m1845_17 |
|
||||
| ir.cpp:1845:11:1845:11 | ChiTotal | total:m1845_14 |
|
||||
| ir.cpp:1845:11:1845:11 | SideEffect | ~m1845_14 |
|
||||
| ir.cpp:1845:11:1845:11 | Unary | r1845_16 |
|
||||
| ir.cpp:1845:13:1845:13 | Address | &:r1845_3 |
|
||||
| ir.cpp:1845:13:1845:13 | Address | &:r1845_3 |
|
||||
| ir.cpp:1845:13:1845:13 | Address | &:r1845_6 |
|
||||
| ir.cpp:1845:13:1845:13 | Address | &:r1845_6 |
|
||||
| ir.cpp:1845:13:1845:13 | Address | &:r1845_15 |
|
||||
| ir.cpp:1845:13:1845:13 | Address | &:r1845_15 |
|
||||
| ir.cpp:1845:13:1845:13 | Arg(0) | 0:r1845_6 |
|
||||
| ir.cpp:1845:13:1845:13 | Arg(0) | 0:r1845_15 |
|
||||
| ir.cpp:1845:13:1845:13 | Arg(this) | this:r1845_3 |
|
||||
| ir.cpp:1845:13:1845:13 | CallTarget | func:r1845_5 |
|
||||
| ir.cpp:1845:13:1845:13 | ChiPartial | partial:m1845_8 |
|
||||
| ir.cpp:1845:13:1845:13 | ChiPartial | partial:m1845_11 |
|
||||
| ir.cpp:1845:13:1845:13 | ChiPartial | partial:m1845_13 |
|
||||
| ir.cpp:1845:13:1845:13 | ChiPartial | partial:m1845_23 |
|
||||
| ir.cpp:1845:13:1845:13 | ChiTotal | total:m1844_12 |
|
||||
| ir.cpp:1845:13:1845:13 | ChiTotal | total:m1845_4 |
|
||||
| ir.cpp:1845:13:1845:13 | ChiTotal | total:m1845_9 |
|
||||
| ir.cpp:1845:13:1845:13 | ChiTotal | total:m1845_12 |
|
||||
| ir.cpp:1845:13:1845:13 | SideEffect | ~m1844_12 |
|
||||
| ir.cpp:1845:13:1845:13 | SideEffect | ~m1845_9 |
|
||||
| ir.cpp:1845:13:1845:13 | SideEffect | ~m1845_12 |
|
||||
| ir.cpp:1845:13:1845:13 | Unary | r1845_3 |
|
||||
| ir.cpp:1849:6:1849:14 | ChiPartial | partial:m1849_3 |
|
||||
| ir.cpp:1849:6:1849:14 | ChiTotal | total:m1849_2 |
|
||||
| ir.cpp:1849:6:1849:14 | SideEffect | m1849_3 |
|
||||
| ir.cpp:1850:17:1850:18 | Address | &:r1850_1 |
|
||||
| ir.cpp:1850:22:1850:40 | StoreValue | r1850_3 |
|
||||
| ir.cpp:1850:22:1850:40 | Unary | r1850_2 |
|
||||
| ir.cpp:1851:17:1851:23 | Address | &:r1851_1 |
|
||||
| ir.cpp:1851:27:1851:34 | StoreValue | r1851_3 |
|
||||
| ir.cpp:1851:27:1851:34 | Unary | r1851_2 |
|
||||
| perf-regression.cpp:6:3:6:5 | Address | &:r6_5 |
|
||||
| perf-regression.cpp:6:3:6:5 | Address | &:r6_5 |
|
||||
| perf-regression.cpp:6:3:6:5 | Address | &:r6_7 |
|
||||
|
||||
@@ -9797,6 +9797,141 @@ ir.cpp:
|
||||
# 1831| v1831_8(void) = AliasedUse : ~m?
|
||||
# 1831| v1831_9(void) = ExitFunction :
|
||||
|
||||
# 1834| block_assignment::A& block_assignment::A::operator=(block_assignment::A&&)
|
||||
# 1834| Block 0
|
||||
# 1834| v1834_1(void) = EnterFunction :
|
||||
# 1834| mu1834_2(unknown) = AliasedDefinition :
|
||||
# 1834| mu1834_3(unknown) = InitializeNonLocal :
|
||||
# 1834| r1834_4(glval<unknown>) = VariableAddress[#this] :
|
||||
# 1834| mu1834_5(glval<A>) = InitializeParameter[#this] : &:r1834_4
|
||||
# 1834| r1834_6(glval<A>) = Load[#this] : &:r1834_4, ~m?
|
||||
# 1834| mu1834_7(A) = InitializeIndirection[#this] : &:r1834_6
|
||||
#-----| r0_1(glval<A &&>) = VariableAddress[(unnamed parameter 0)] :
|
||||
#-----| mu0_2(A &&) = InitializeParameter[(unnamed parameter 0)] : &:r0_1
|
||||
#-----| r0_3(A &&) = Load[(unnamed parameter 0)] : &:r0_1, ~m?
|
||||
#-----| mu0_4(unknown) = InitializeIndirection[(unnamed parameter 0)] : &:r0_3
|
||||
#-----| r0_5(glval<unknown>) = VariableAddress[#this] :
|
||||
#-----| r0_6(A *) = Load[#this] : &:r0_5, ~m?
|
||||
#-----| r0_7(glval<enum <unnamed>[1]>) = FieldAddress[e] : r0_6
|
||||
#-----| r0_8(glval<A &&>) = VariableAddress[(unnamed parameter 0)] :
|
||||
#-----| r0_9(A &&) = Load[(unnamed parameter 0)] : &:r0_8, ~m?
|
||||
#-----| r0_10(glval<A>) = CopyValue : r0_9
|
||||
#-----| r0_11(glval<enum <unnamed>[1]>) = FieldAddress[e] : r0_10
|
||||
#-----| r0_12(enum <unnamed>[1]) = Load[?] : &:r0_11, ~m?
|
||||
#-----| mu0_13(enum <unnamed>[1]) = Store[?] : &:r0_7, r0_12
|
||||
#-----| r0_14(glval<A &>) = VariableAddress[#return] :
|
||||
#-----| r0_15(glval<unknown>) = VariableAddress[#this] :
|
||||
#-----| r0_16(A *) = Load[#this] : &:r0_15, ~m?
|
||||
#-----| r0_17(glval<A>) = CopyValue : r0_16
|
||||
#-----| r0_18(A &) = CopyValue : r0_17
|
||||
#-----| mu0_19(A &) = Store[#return] : &:r0_14, r0_18
|
||||
# 1834| v1834_8(void) = ReturnIndirection[#this] : &:r1834_6, ~m?
|
||||
#-----| v0_20(void) = ReturnIndirection[(unnamed parameter 0)] : &:r0_3, ~m?
|
||||
# 1834| r1834_9(glval<A &>) = VariableAddress[#return] :
|
||||
# 1834| v1834_10(void) = ReturnValue : &:r1834_9, ~m?
|
||||
# 1834| v1834_11(void) = AliasedUse : ~m?
|
||||
# 1834| v1834_12(void) = ExitFunction :
|
||||
|
||||
# 1839| block_assignment::B& block_assignment::B::operator=(block_assignment::B&&)
|
||||
# 1839| Block 0
|
||||
# 1839| v1839_1(void) = EnterFunction :
|
||||
# 1839| mu1839_2(unknown) = AliasedDefinition :
|
||||
# 1839| mu1839_3(unknown) = InitializeNonLocal :
|
||||
# 1839| r1839_4(glval<unknown>) = VariableAddress[#this] :
|
||||
# 1839| mu1839_5(glval<B>) = InitializeParameter[#this] : &:r1839_4
|
||||
# 1839| r1839_6(glval<B>) = Load[#this] : &:r1839_4, ~m?
|
||||
# 1839| mu1839_7(B) = InitializeIndirection[#this] : &:r1839_6
|
||||
#-----| r0_1(glval<B &&>) = VariableAddress[(unnamed parameter 0)] :
|
||||
#-----| mu0_2(B &&) = InitializeParameter[(unnamed parameter 0)] : &:r0_1
|
||||
#-----| r0_3(B &&) = Load[(unnamed parameter 0)] : &:r0_1, ~m?
|
||||
#-----| mu0_4(unknown) = InitializeIndirection[(unnamed parameter 0)] : &:r0_3
|
||||
# 1839| r1839_8(glval<unknown>) = VariableAddress[#this] :
|
||||
# 1839| r1839_9(B *) = Load[#this] : &:r1839_8, ~m?
|
||||
#-----| r0_5(A *) = ConvertToNonVirtualBase[B : A] : r1839_9
|
||||
# 1839| r1839_10(glval<unknown>) = FunctionAddress[operator=] :
|
||||
# 1839| r1839_11(glval<B &&>) = VariableAddress[(unnamed parameter 0)] :
|
||||
# 1839| r1839_12(B &&) = Load[(unnamed parameter 0)] : &:r1839_11, ~m?
|
||||
#-----| r0_6(glval<B>) = CopyValue : r1839_12
|
||||
# 1839| r1839_13(B *) = CopyValue : r0_6
|
||||
#-----| r0_7(A *) = ConvertToNonVirtualBase[B : A] : r1839_13
|
||||
# 1839| r1839_14(glval<A>) = CopyValue : r0_7
|
||||
#-----| r0_8(A &) = CopyValue : r1839_14
|
||||
# 1839| r1839_15(A &) = Call[operator=] : func:r1839_10, this:r0_5, 0:r0_8
|
||||
# 1839| mu1839_16(unknown) = ^CallSideEffect : ~m?
|
||||
#-----| v0_9(void) = ^IndirectReadSideEffect[-1] : &:r0_5, ~m?
|
||||
#-----| v0_10(void) = ^BufferReadSideEffect[0] : &:r0_8, ~m?
|
||||
#-----| mu0_11(A) = ^IndirectMayWriteSideEffect[-1] : &:r0_5
|
||||
#-----| mu0_12(unknown) = ^BufferMayWriteSideEffect[0] : &:r0_8
|
||||
#-----| r0_13(glval<A>) = CopyValue : r1839_15
|
||||
#-----| r0_14(glval<B &>) = VariableAddress[#return] :
|
||||
#-----| r0_15(glval<unknown>) = VariableAddress[#this] :
|
||||
#-----| r0_16(B *) = Load[#this] : &:r0_15, ~m?
|
||||
#-----| r0_17(glval<B>) = CopyValue : r0_16
|
||||
#-----| r0_18(B &) = CopyValue : r0_17
|
||||
#-----| mu0_19(B &) = Store[#return] : &:r0_14, r0_18
|
||||
# 1839| v1839_17(void) = ReturnIndirection[#this] : &:r1839_6, ~m?
|
||||
#-----| v0_20(void) = ReturnIndirection[(unnamed parameter 0)] : &:r0_3, ~m?
|
||||
# 1839| r1839_18(glval<B &>) = VariableAddress[#return] :
|
||||
# 1839| v1839_19(void) = ReturnValue : &:r1839_18, ~m?
|
||||
# 1839| v1839_20(void) = AliasedUse : ~m?
|
||||
# 1839| v1839_21(void) = ExitFunction :
|
||||
|
||||
# 1843| void block_assignment::foo()
|
||||
# 1843| Block 0
|
||||
# 1843| v1843_1(void) = EnterFunction :
|
||||
# 1843| mu1843_2(unknown) = AliasedDefinition :
|
||||
# 1843| mu1843_3(unknown) = InitializeNonLocal :
|
||||
# 1844| r1844_1(glval<B>) = VariableAddress[v] :
|
||||
# 1844| mu1844_2(B) = Uninitialized[v] : &:r1844_1
|
||||
# 1844| r1844_3(glval<unknown>) = FunctionAddress[B] :
|
||||
# 1844| r1844_4(A *) = Constant[0] :
|
||||
# 1844| v1844_5(void) = Call[B] : func:r1844_3, this:r1844_1, 0:r1844_4
|
||||
# 1844| mu1844_6(unknown) = ^CallSideEffect : ~m?
|
||||
# 1844| v1844_7(void) = ^BufferReadSideEffect[0] : &:r1844_4, ~m?
|
||||
# 1844| mu1844_8(B) = ^IndirectMayWriteSideEffect[-1] : &:r1844_1
|
||||
# 1844| mu1844_9(unknown) = ^BufferMayWriteSideEffect[0] : &:r1844_4
|
||||
# 1845| r1845_1(glval<B>) = VariableAddress[v] :
|
||||
# 1845| r1845_2(glval<unknown>) = FunctionAddress[operator=] :
|
||||
# 1845| r1845_3(glval<B>) = VariableAddress[#temp1845:13] :
|
||||
# 1845| mu1845_4(B) = Uninitialized[#temp1845:13] : &:r1845_3
|
||||
# 1845| r1845_5(glval<unknown>) = FunctionAddress[B] :
|
||||
# 1845| r1845_6(A *) = Constant[0] :
|
||||
# 1845| v1845_7(void) = Call[B] : func:r1845_5, this:r1845_3, 0:r1845_6
|
||||
# 1845| mu1845_8(unknown) = ^CallSideEffect : ~m?
|
||||
# 1845| v1845_9(void) = ^BufferReadSideEffect[0] : &:r1845_6, ~m?
|
||||
# 1845| mu1845_10(B) = ^IndirectMayWriteSideEffect[-1] : &:r1845_3
|
||||
# 1845| mu1845_11(unknown) = ^BufferMayWriteSideEffect[0] : &:r1845_6
|
||||
# 1845| r1845_12(B &) = CopyValue : r1845_3
|
||||
# 1845| r1845_13(B &) = Call[operator=] : func:r1845_2, this:r1845_1, 0:r1845_12
|
||||
# 1845| mu1845_14(unknown) = ^CallSideEffect : ~m?
|
||||
# 1845| v1845_15(void) = ^IndirectReadSideEffect[-1] : &:r1845_1, ~m?
|
||||
# 1845| v1845_16(void) = ^BufferReadSideEffect[0] : &:r1845_12, ~m?
|
||||
# 1845| mu1845_17(B) = ^IndirectMayWriteSideEffect[-1] : &:r1845_1
|
||||
# 1845| mu1845_18(unknown) = ^BufferMayWriteSideEffect[0] : &:r1845_12
|
||||
# 1845| r1845_19(glval<B>) = CopyValue : r1845_13
|
||||
# 1846| v1846_1(void) = NoOp :
|
||||
# 1843| v1843_4(void) = ReturnVoid :
|
||||
# 1843| v1843_5(void) = AliasedUse : ~m?
|
||||
# 1843| v1843_6(void) = ExitFunction :
|
||||
|
||||
# 1849| void magicvars()
|
||||
# 1849| Block 0
|
||||
# 1849| v1849_1(void) = EnterFunction :
|
||||
# 1849| mu1849_2(unknown) = AliasedDefinition :
|
||||
# 1849| mu1849_3(unknown) = InitializeNonLocal :
|
||||
# 1850| r1850_1(glval<char *>) = VariableAddress[pf] :
|
||||
# 1850| r1850_2(glval<char[17]>) = VariableAddress[__PRETTY_FUNCTION__] :
|
||||
# 1850| r1850_3(char *) = Convert : r1850_2
|
||||
# 1850| mu1850_4(char *) = Store[pf] : &:r1850_1, r1850_3
|
||||
# 1851| r1851_1(glval<char *>) = VariableAddress[strfunc] :
|
||||
# 1851| r1851_2(glval<char[10]>) = VariableAddress[__func__] :
|
||||
# 1851| r1851_3(char *) = Convert : r1851_2
|
||||
# 1851| mu1851_4(char *) = Store[strfunc] : &:r1851_1, r1851_3
|
||||
# 1852| v1852_1(void) = NoOp :
|
||||
# 1849| v1849_4(void) = ReturnVoid :
|
||||
# 1849| v1849_5(void) = AliasedUse : ~m?
|
||||
# 1849| v1849_6(void) = ExitFunction :
|
||||
|
||||
perf-regression.cpp:
|
||||
# 6| void Big::Big()
|
||||
# 6| Block 0
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import cpp
|
||||
import experimental.semmle.code.cpp.semantic.analysis.RangeAnalysis
|
||||
import experimental.semmle.code.cpp.semantic.Semantic
|
||||
import experimental.semmle.code.cpp.semantic.SemanticExprSpecific
|
||||
import semmle.code.cpp.ir.IR as IR
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
|
||||
@@ -37,8 +38,13 @@ private string getBoundString(SemBound b, int delta) {
|
||||
b instanceof SemZeroBound and result = delta.toString()
|
||||
or
|
||||
result =
|
||||
strictconcat(b.(SemSsaBound).getAVariable().(IR::Instruction).getAst().toString(), ":") +
|
||||
getOffsetString(delta)
|
||||
strictconcat(b.(SemSsaBound)
|
||||
.getAVariable()
|
||||
.(SemanticExprConfig::SsaVariable)
|
||||
.asInstruction()
|
||||
.getAst()
|
||||
.toString(), ":"
|
||||
) + getOffsetString(delta)
|
||||
}
|
||||
|
||||
private string getARangeString(SemExpr e) {
|
||||
|
||||
@@ -99,8 +99,6 @@ thisArgumentIsNonPointer
|
||||
| pointer_to_member.cpp:23:5:23:54 | Call: call to expression | Call instruction 'Call: call to expression' has a `this` argument operand that is not an address, in function '$@'. | pointer_to_member.cpp:14:5:14:9 | int usePM(int PM::*) | int usePM(int PM::*) |
|
||||
| pointer_to_member.cpp:24:5:24:49 | Call: call to expression | Call instruction 'Call: call to expression' has a `this` argument operand that is not an address, in function '$@'. | pointer_to_member.cpp:14:5:14:9 | int usePM(int PM::*) | int usePM(int PM::*) |
|
||||
nonUniqueIRVariable
|
||||
| misc.c:178:22:178:40 | VariableAddress: __PRETTY_FUNCTION__ | Variable address instruction 'VariableAddress: __PRETTY_FUNCTION__' has no associated variable, in function '$@'. | misc.c:177:6:177:14 | void magicvars() | void magicvars() |
|
||||
| misc.c:179:27:179:34 | VariableAddress: __func__ | Variable address instruction 'VariableAddress: __func__' has no associated variable, in function '$@'. | misc.c:177:6:177:14 | void magicvars() | void magicvars() |
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
missingIRType
|
||||
|
||||
@@ -149,8 +149,6 @@ thisArgumentIsNonPointer
|
||||
| pointer_to_member.cpp:23:5:23:54 | Call: call to expression | Call instruction 'Call: call to expression' has a `this` argument operand that is not an address, in function '$@'. | pointer_to_member.cpp:14:5:14:9 | int usePM(int PM::*) | int usePM(int PM::*) |
|
||||
| pointer_to_member.cpp:24:5:24:49 | Call: call to expression | Call instruction 'Call: call to expression' has a `this` argument operand that is not an address, in function '$@'. | pointer_to_member.cpp:14:5:14:9 | int usePM(int PM::*) | int usePM(int PM::*) |
|
||||
nonUniqueIRVariable
|
||||
| misc.c:178:22:178:40 | VariableAddress: __PRETTY_FUNCTION__ | Variable address instruction 'VariableAddress: __PRETTY_FUNCTION__' has no associated variable, in function '$@'. | misc.c:177:6:177:14 | void magicvars() | void magicvars() |
|
||||
| misc.c:179:27:179:34 | VariableAddress: __func__ | Variable address instruction 'VariableAddress: __func__' has no associated variable, in function '$@'. | misc.c:177:6:177:14 | void magicvars() | void magicvars() |
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
missingIRType
|
||||
|
||||
@@ -99,8 +99,6 @@ thisArgumentIsNonPointer
|
||||
| pointer_to_member.cpp:23:5:23:54 | Call: call to expression | Call instruction 'Call: call to expression' has a `this` argument operand that is not an address, in function '$@'. | pointer_to_member.cpp:14:5:14:9 | int usePM(int PM::*) | int usePM(int PM::*) |
|
||||
| pointer_to_member.cpp:24:5:24:49 | Call: call to expression | Call instruction 'Call: call to expression' has a `this` argument operand that is not an address, in function '$@'. | pointer_to_member.cpp:14:5:14:9 | int usePM(int PM::*) | int usePM(int PM::*) |
|
||||
nonUniqueIRVariable
|
||||
| misc.c:178:22:178:40 | VariableAddress: __PRETTY_FUNCTION__ | Variable address instruction 'VariableAddress: __PRETTY_FUNCTION__' has no associated variable, in function '$@'. | misc.c:177:6:177:14 | void magicvars() | void magicvars() |
|
||||
| misc.c:179:27:179:34 | VariableAddress: __func__ | Variable address instruction 'VariableAddress: __func__' has no associated variable, in function '$@'. | misc.c:177:6:177:14 | void magicvars() | void magicvars() |
|
||||
missingCanonicalLanguageType
|
||||
multipleCanonicalLanguageTypes
|
||||
missingIRType
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
| empty_block.cpp:9:10:9:11 | { ... } | Empty block without comment |
|
||||
| empty_block.cpp:12:10:13:3 | { ... } | Empty block without comment |
|
||||
| empty_block.cpp:20:10:21:3 | { ... } | Empty block without comment |
|
||||
| empty_block.cpp:9:10:9:11 | { ... } | Empty block without comment. |
|
||||
| empty_block.cpp:12:10:13:3 | { ... } | Empty block without comment. |
|
||||
| empty_block.cpp:20:10:21:3 | { ... } | Empty block without comment. |
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
| test2.cpp:37:1:37:39 | // int myFunction() { return myValue; } | This comment appears to contain commented-out code |
|
||||
| test2.cpp:39:1:39:45 | // int myFunction() const { return myValue; } | This comment appears to contain commented-out code |
|
||||
| test2.cpp:41:1:41:54 | // int myFunction() const noexcept { return myValue; } | This comment appears to contain commented-out code |
|
||||
| test2.cpp:43:1:43:18 | // #define MYMACRO | This comment appears to contain commented-out code |
|
||||
| test2.cpp:45:1:45:23 | // #include "include.h" | This comment appears to contain commented-out code |
|
||||
| test2.cpp:47:1:51:2 | /*\n#ifdef\nvoid myFunction();\n#endif\n*/ | This comment appears to contain commented-out code |
|
||||
| test2.cpp:59:1:59:24 | // #if(defined(MYMACRO)) | This comment appears to contain commented-out code |
|
||||
| test2.cpp:63:1:63:15 | // #pragma once | This comment appears to contain commented-out code |
|
||||
| test2.cpp:65:1:65:17 | // # pragma once | This comment appears to contain commented-out code |
|
||||
| test2.cpp:67:1:67:19 | /*#error"myerror"*/ | This comment appears to contain commented-out code |
|
||||
| test2.cpp:91:1:95:2 | /*\n#ifdef MYMACRO\n\t// ...\n#endif // #ifdef MYMACRO\n*/ | This comment appears to contain commented-out code |
|
||||
| test2.cpp:107:21:107:43 | // #include "config2.h" | This comment appears to contain commented-out code |
|
||||
| test2.cpp:115:16:115:35 | /* #ifdef MYMACRO */ | This comment appears to contain commented-out code |
|
||||
| test2.cpp:117:1:117:24 | // commented_out_code(); | This comment appears to contain commented-out code |
|
||||
| test2.cpp:120:2:120:25 | // commented_out_code(); | This comment appears to contain commented-out code |
|
||||
| test.c:2:1:2:22 | // commented out code; | This comment appears to contain commented-out code |
|
||||
| test.c:4:1:7:8 | // some; | This comment appears to contain commented-out code |
|
||||
| test.c:9:1:13:8 | // also; | This comment appears to contain commented-out code |
|
||||
| test.c:21:1:26:2 | /*\n some;\n commented;\n out;\n code;\n*/ | This comment appears to contain commented-out code |
|
||||
| test.c:28:1:34:2 | /*\n also;\n this\n is;\n commented-out\n code;\n*/ | This comment appears to contain commented-out code |
|
||||
| test2.cpp:37:1:37:39 | // int myFunction() { return myValue; } | This comment appears to contain commented-out code. |
|
||||
| test2.cpp:39:1:39:45 | // int myFunction() const { return myValue; } | This comment appears to contain commented-out code. |
|
||||
| test2.cpp:41:1:41:54 | // int myFunction() const noexcept { return myValue; } | This comment appears to contain commented-out code. |
|
||||
| test2.cpp:43:1:43:18 | // #define MYMACRO | This comment appears to contain commented-out code. |
|
||||
| test2.cpp:45:1:45:23 | // #include "include.h" | This comment appears to contain commented-out code. |
|
||||
| test2.cpp:47:1:51:2 | /*\n#ifdef\nvoid myFunction();\n#endif\n*/ | This comment appears to contain commented-out code. |
|
||||
| test2.cpp:59:1:59:24 | // #if(defined(MYMACRO)) | This comment appears to contain commented-out code. |
|
||||
| test2.cpp:63:1:63:15 | // #pragma once | This comment appears to contain commented-out code. |
|
||||
| test2.cpp:65:1:65:17 | // # pragma once | This comment appears to contain commented-out code. |
|
||||
| test2.cpp:67:1:67:19 | /*#error"myerror"*/ | This comment appears to contain commented-out code. |
|
||||
| test2.cpp:91:1:95:2 | /*\n#ifdef MYMACRO\n\t// ...\n#endif // #ifdef MYMACRO\n*/ | This comment appears to contain commented-out code. |
|
||||
| test2.cpp:107:21:107:43 | // #include "config2.h" | This comment appears to contain commented-out code. |
|
||||
| test2.cpp:115:16:115:35 | /* #ifdef MYMACRO */ | This comment appears to contain commented-out code. |
|
||||
| test2.cpp:117:1:117:24 | // commented_out_code(); | This comment appears to contain commented-out code. |
|
||||
| test2.cpp:120:2:120:25 | // commented_out_code(); | This comment appears to contain commented-out code. |
|
||||
| test.c:2:1:2:22 | // commented out code; | This comment appears to contain commented-out code. |
|
||||
| test.c:4:1:7:8 | // some; | This comment appears to contain commented-out code. |
|
||||
| test.c:9:1:13:8 | // also; | This comment appears to contain commented-out code. |
|
||||
| test.c:21:1:26:2 | /*\n some;\n commented;\n out;\n code;\n*/ | This comment appears to contain commented-out code. |
|
||||
| test.c:28:1:34:2 | /*\n also;\n this\n is;\n commented-out\n code;\n*/ | This comment appears to contain commented-out code. |
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user