mirror of
https://github.com/github/codeql.git
synced 2026-05-05 13:45:19 +02:00
Merge branch 'main' into edoardo/3.5-mergeback
This commit is contained in:
17
cpp/BUILD.bazel
Normal file
17
cpp/BUILD.bazel
Normal file
@@ -0,0 +1,17 @@
|
||||
package(default_visibility = ["//visibility:public"])
|
||||
|
||||
load("@rules_pkg//:mappings.bzl", "pkg_filegroup")
|
||||
|
||||
alias(
|
||||
name = "dbscheme",
|
||||
actual = "//cpp/ql/lib:dbscheme",
|
||||
)
|
||||
|
||||
pkg_filegroup(
|
||||
name = "db-files",
|
||||
srcs = [
|
||||
":dbscheme",
|
||||
"//cpp/downgrades",
|
||||
"//cpp/ql/lib:dbscheme-stats",
|
||||
],
|
||||
)
|
||||
12
cpp/downgrades/BUILD.bazel
Normal file
12
cpp/downgrades/BUILD.bazel
Normal file
@@ -0,0 +1,12 @@
|
||||
load("@rules_pkg//:mappings.bzl", "pkg_files", "strip_prefix")
|
||||
|
||||
pkg_files(
|
||||
name = "downgrades",
|
||||
srcs = glob(
|
||||
["**"],
|
||||
exclude = ["BUILD.bazel"],
|
||||
),
|
||||
prefix = "cpp/downgrades",
|
||||
strip_prefix = strip_prefix.from_pkg(),
|
||||
visibility = ["//cpp:__pkg__"],
|
||||
)
|
||||
15
cpp/ql/lib/BUILD.bazel
Normal file
15
cpp/ql/lib/BUILD.bazel
Normal file
@@ -0,0 +1,15 @@
|
||||
package(default_visibility = ["//cpp:__pkg__"])
|
||||
|
||||
load("@rules_pkg//:mappings.bzl", "pkg_files")
|
||||
|
||||
pkg_files(
|
||||
name = "dbscheme",
|
||||
srcs = ["semmlecode.cpp.dbscheme"],
|
||||
prefix = "cpp",
|
||||
)
|
||||
|
||||
pkg_files(
|
||||
name = "dbscheme-stats",
|
||||
srcs = ["semmlecode.cpp.dbscheme.stats"],
|
||||
prefix = "cpp",
|
||||
)
|
||||
4
cpp/ql/lib/change-notes/2022-03-28-private-data.md
Normal file
4
cpp/ql/lib/change-notes/2022-03-28-private-data.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: feature
|
||||
---
|
||||
* A new library `semmle.code.cpp.security.PrivateData` has been added. The new library heuristically detects variables and functions dealing with sensitive private data, such as e-mail addresses and credit card numbers.
|
||||
4
cpp/ql/lib/change-notes/2022-03-31-sensitive-exprs.md
Normal file
4
cpp/ql/lib/change-notes/2022-03-31-sensitive-exprs.md
Normal file
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The `semmle.code.cpp.security.SensitiveExprs` library has been enhanced with some additional rules for detecting credentials.
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.dataflow.TaintTracking
|
||||
import experimental.semmle.code.cpp.security.PrivateData
|
||||
import semmle.code.cpp.security.PrivateData
|
||||
import semmle.code.cpp.security.FileWrite
|
||||
import semmle.code.cpp.security.BufferWrite
|
||||
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
/**
|
||||
* Provides classes and predicates for identifying private data and functions for security.
|
||||
*
|
||||
* 'Private' data in general is anything that would compromise user privacy if exposed. This
|
||||
* library tries to guess where private data may either be stored in a variable or produced by a
|
||||
* function.
|
||||
*
|
||||
* This library is not concerned with credentials. See `SensitiveActions` for expressions related
|
||||
* to credentials.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
/** A string for `match` that identifies strings that look like they represent private data. */
|
||||
private string privateNames() {
|
||||
result =
|
||||
[
|
||||
// Inspired by the list on https://cwe.mitre.org/data/definitions/359.html
|
||||
// Government identifiers, such as Social Security Numbers
|
||||
"%social%security%number%",
|
||||
// Contact information, such as home addresses and telephone numbers
|
||||
"%postcode%", "%zipcode%",
|
||||
// result = "%telephone%" or
|
||||
// Geographic location - where the user is (or was)
|
||||
"%latitude%", "%longitude%",
|
||||
// Financial data - such as credit card numbers, salary, bank accounts, and debts
|
||||
"%creditcard%", "%salary%", "%bankaccount%",
|
||||
// Communications - e-mail addresses, private e-mail messages, SMS text messages, chat logs, etc.
|
||||
// result = "%email%" or
|
||||
// result = "%mobile%" or
|
||||
"%employer%",
|
||||
// Health - medical conditions, insurance status, prescription records
|
||||
"%medical%"
|
||||
]
|
||||
}
|
||||
|
||||
/** An expression that might contain private data. */
|
||||
abstract class PrivateDataExpr extends Expr { }
|
||||
|
||||
/** A functiond call that might produce private data. */
|
||||
class PrivateFunctionCall extends PrivateDataExpr, FunctionCall {
|
||||
PrivateFunctionCall() {
|
||||
exists(string s | this.getTarget().getName().toLowerCase() = s | s.matches(privateNames()))
|
||||
}
|
||||
}
|
||||
|
||||
/** An access to a variable that might contain private data. */
|
||||
class PrivateVariableAccess extends PrivateDataExpr, VariableAccess {
|
||||
PrivateVariableAccess() {
|
||||
exists(string s | this.getTarget().getName().toLowerCase() = s | s.matches(privateNames()))
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import SemanticExpr
|
||||
import SemanticBound
|
||||
import SemanticSSA
|
||||
import SemanticGuard
|
||||
import SemanticCFG
|
||||
import SemanticType
|
||||
import SemanticOpcode
|
||||
@@ -0,0 +1,42 @@
|
||||
/**
|
||||
* Semantic wrapper around the language-specific bounds library.
|
||||
*/
|
||||
|
||||
private import SemanticExpr
|
||||
private import SemanticExprSpecific::SemanticExprConfig as Specific
|
||||
private import SemanticSSA
|
||||
|
||||
/**
|
||||
* A valid base for an expression bound.
|
||||
*
|
||||
* Can be either a variable (`SemSsaBound`) or zero (`SemZeroBound`).
|
||||
*/
|
||||
class SemBound instanceof Specific::Bound {
|
||||
final string toString() { result = super.toString() }
|
||||
|
||||
final SemExpr getExpr(int delta) { result = Specific::getBoundExpr(this, delta) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A bound that is a constant zero.
|
||||
*/
|
||||
class SemZeroBound extends SemBound {
|
||||
SemZeroBound() { Specific::zeroBound(this) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A bound that is an SSA definition.
|
||||
*/
|
||||
class SemSsaBound extends SemBound {
|
||||
/**
|
||||
* The variables whose value is used as the bound.
|
||||
*
|
||||
* Can be multi-valued in some implementations. If so, all variables will be equivalent.
|
||||
*/
|
||||
SemSsaVariable var;
|
||||
|
||||
SemSsaBound() { Specific::ssaBound(this, var) }
|
||||
|
||||
/** Gets a variable whose value is used as the bound. */
|
||||
final SemSsaVariable getAVariable() { result = var }
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/**
|
||||
* Semantic interface to the control flow graph.
|
||||
*/
|
||||
|
||||
private import Semantic
|
||||
private import SemanticExprSpecific::SemanticExprConfig as Specific
|
||||
|
||||
/**
|
||||
* A basic block in the control-flow graph.
|
||||
*/
|
||||
class SemBasicBlock extends Specific::BasicBlock {
|
||||
/** Holds if this block (transitively) dominates `otherblock`. */
|
||||
final predicate bbDominates(SemBasicBlock otherBlock) { Specific::bbDominates(this, otherBlock) }
|
||||
|
||||
/** Holds if this block has dominance information. */
|
||||
final predicate hasDominanceInformation() { Specific::hasDominanceInformation(this) }
|
||||
|
||||
/** Gets an expression that is evaluated in this basic block. */
|
||||
final SemExpr getAnExpr() { result.getBasicBlock() = this }
|
||||
|
||||
final int getUniqueId() { result = Specific::getBasicBlockUniqueId(this) }
|
||||
}
|
||||
@@ -0,0 +1,309 @@
|
||||
/**
|
||||
* Semantic interface for expressions.
|
||||
*/
|
||||
|
||||
private import Semantic
|
||||
private import SemanticExprSpecific::SemanticExprConfig as Specific
|
||||
|
||||
/**
|
||||
* An language-neutral expression.
|
||||
*
|
||||
* The expression computes a value of type `getSemType()`. The actual computation is determined by
|
||||
* the expression's opcode (`getOpcode()`).
|
||||
*/
|
||||
class SemExpr instanceof Specific::Expr {
|
||||
final string toString() { result = super.toString() }
|
||||
|
||||
final Specific::Location getLocation() { result = super.getLocation() }
|
||||
|
||||
Opcode getOpcode() { result instanceof Opcode::Unknown }
|
||||
|
||||
SemType getSemType() { result = Specific::getUnknownExprType(this) }
|
||||
|
||||
final SemBasicBlock getBasicBlock() { result = Specific::getExprBasicBlock(this) }
|
||||
}
|
||||
|
||||
/** An expression with an opcode other than `Unknown`. */
|
||||
abstract private class SemKnownExpr extends SemExpr {
|
||||
Opcode opcode;
|
||||
SemType type;
|
||||
|
||||
final override Opcode getOpcode() { result = opcode }
|
||||
|
||||
final override SemType getSemType() { result = type }
|
||||
}
|
||||
|
||||
/** An expression that returns a literal value. */
|
||||
class SemLiteralExpr extends SemKnownExpr {
|
||||
SemLiteralExpr() {
|
||||
Specific::integerLiteral(this, type, _) and opcode instanceof Opcode::Constant
|
||||
or
|
||||
Specific::largeIntegerLiteral(this, type, _) and opcode instanceof Opcode::Constant
|
||||
or
|
||||
Specific::booleanLiteral(this, type, _) and opcode instanceof Opcode::Constant
|
||||
or
|
||||
Specific::floatingPointLiteral(this, type, _) and opcode instanceof Opcode::Constant
|
||||
or
|
||||
Specific::nullLiteral(this, type) and opcode instanceof Opcode::Constant
|
||||
or
|
||||
Specific::stringLiteral(this, type, _) and opcode instanceof Opcode::StringConstant
|
||||
}
|
||||
}
|
||||
|
||||
/** An expression that returns a numeric literal value. */
|
||||
class SemNumericLiteralExpr extends SemLiteralExpr {
|
||||
SemNumericLiteralExpr() {
|
||||
Specific::integerLiteral(this, _, _)
|
||||
or
|
||||
Specific::largeIntegerLiteral(this, _, _)
|
||||
or
|
||||
Specific::floatingPointLiteral(this, _, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an approximation of the value of the literal, as a `float`.
|
||||
*
|
||||
* If the value can be precisely represented as a `float`, the result will be exact. If the actual
|
||||
* value cannot be precisely represented (for example, it is an integer with more than 53
|
||||
* significant bits), then the result is an approximation.
|
||||
*/
|
||||
float getApproximateFloatValue() { none() }
|
||||
}
|
||||
|
||||
/** An expression that returns an integer literal value. */
|
||||
class SemIntegerLiteralExpr extends SemNumericLiteralExpr {
|
||||
SemIntegerLiteralExpr() {
|
||||
Specific::integerLiteral(this, _, _)
|
||||
or
|
||||
Specific::largeIntegerLiteral(this, _, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of the literal, if it can be represented as an `int`.
|
||||
*
|
||||
* If the value is outside the range of an `int`, use `getApproximateFloatValue()` to get a value
|
||||
* that is equal to the actual integer value, within rounding error.
|
||||
*/
|
||||
final int getIntValue() { Specific::integerLiteral(this, _, result) }
|
||||
|
||||
final override float getApproximateFloatValue() {
|
||||
result = getIntValue()
|
||||
or
|
||||
Specific::largeIntegerLiteral(this, _, result)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An expression that returns a floating-point literal value.
|
||||
*/
|
||||
class SemFloatingPointLiteralExpr extends SemNumericLiteralExpr {
|
||||
float value;
|
||||
|
||||
SemFloatingPointLiteralExpr() { Specific::floatingPointLiteral(this, _, value) }
|
||||
|
||||
final override float getApproximateFloatValue() { result = value }
|
||||
|
||||
/** Gets the value of the literal. */
|
||||
final float getFloatValue() { result = value }
|
||||
}
|
||||
|
||||
/**
|
||||
* An expression that consumes two operands.
|
||||
*/
|
||||
class SemBinaryExpr extends SemKnownExpr {
|
||||
SemExpr leftOperand;
|
||||
SemExpr rightOperand;
|
||||
|
||||
SemBinaryExpr() { Specific::binaryExpr(this, opcode, type, leftOperand, rightOperand) }
|
||||
|
||||
/** Gets the left operand. */
|
||||
final SemExpr getLeftOperand() { result = leftOperand }
|
||||
|
||||
/** Gets the right operand. */
|
||||
final SemExpr getRightOperand() { result = rightOperand }
|
||||
|
||||
/** Holds if `a` and `b` are the two operands, in either order. */
|
||||
final predicate hasOperands(SemExpr a, SemExpr b) {
|
||||
a = getLeftOperand() and b = getRightOperand()
|
||||
or
|
||||
a = getRightOperand() and b = getLeftOperand()
|
||||
}
|
||||
|
||||
/** Gets the two operands. */
|
||||
final SemExpr getAnOperand() { result = getLeftOperand() or result = getRightOperand() }
|
||||
}
|
||||
|
||||
/** An expression that performs and ordered comparison of two operands. */
|
||||
class SemRelationalExpr extends SemBinaryExpr {
|
||||
SemRelationalExpr() {
|
||||
opcode instanceof Opcode::CompareLT
|
||||
or
|
||||
opcode instanceof Opcode::CompareLE
|
||||
or
|
||||
opcode instanceof Opcode::CompareGT
|
||||
or
|
||||
opcode instanceof Opcode::CompareGE
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the operand that will be less than the other operand if the result of the comparison is
|
||||
* `true`.
|
||||
*
|
||||
* For `x < y` or `x <= y`, this will return `x`.
|
||||
* For `x > y` or `x >= y`, this will return `y`.`
|
||||
*/
|
||||
final SemExpr getLesserOperand() {
|
||||
if opcode instanceof Opcode::CompareLT or opcode instanceof Opcode::CompareLE
|
||||
then result = getLeftOperand()
|
||||
else result = getRightOperand()
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the operand that will be greater than the other operand if the result of the comparison is
|
||||
* `true`.
|
||||
*
|
||||
* For `x < y` or `x <= y`, this will return `y`.
|
||||
* For `x > y` or `x >= y`, this will return `x`.`
|
||||
*/
|
||||
final SemExpr getGreaterOperand() {
|
||||
if opcode instanceof Opcode::CompareGT or opcode instanceof Opcode::CompareGE
|
||||
then result = getLeftOperand()
|
||||
else result = getRightOperand()
|
||||
}
|
||||
|
||||
/** Holds if this comparison returns `false` if the two operands are equal. */
|
||||
final predicate isStrict() {
|
||||
opcode instanceof Opcode::CompareLT or opcode instanceof Opcode::CompareGT
|
||||
}
|
||||
}
|
||||
|
||||
class SemAddExpr extends SemBinaryExpr {
|
||||
SemAddExpr() { opcode instanceof Opcode::Add }
|
||||
}
|
||||
|
||||
class SemSubExpr extends SemBinaryExpr {
|
||||
SemSubExpr() { opcode instanceof Opcode::Sub }
|
||||
}
|
||||
|
||||
class SemMulExpr extends SemBinaryExpr {
|
||||
SemMulExpr() { opcode instanceof Opcode::Mul }
|
||||
}
|
||||
|
||||
class SemDivExpr extends SemBinaryExpr {
|
||||
SemDivExpr() { opcode instanceof Opcode::Div }
|
||||
}
|
||||
|
||||
class SemRemExpr extends SemBinaryExpr {
|
||||
SemRemExpr() { opcode instanceof Opcode::Rem }
|
||||
}
|
||||
|
||||
class SemShiftLeftExpr extends SemBinaryExpr {
|
||||
SemShiftLeftExpr() { opcode instanceof Opcode::ShiftLeft }
|
||||
}
|
||||
|
||||
class SemShiftRightExpr extends SemBinaryExpr {
|
||||
SemShiftRightExpr() { opcode instanceof Opcode::ShiftRight }
|
||||
}
|
||||
|
||||
class SemShiftRightUnsignedExpr extends SemBinaryExpr {
|
||||
SemShiftRightUnsignedExpr() { opcode instanceof Opcode::ShiftRightUnsigned }
|
||||
}
|
||||
|
||||
class SemBitAndExpr extends SemBinaryExpr {
|
||||
SemBitAndExpr() { opcode instanceof Opcode::BitAnd }
|
||||
}
|
||||
|
||||
class SemBitOrExpr extends SemBinaryExpr {
|
||||
SemBitOrExpr() { opcode instanceof Opcode::BitOr }
|
||||
}
|
||||
|
||||
class SemBitXorExpr extends SemBinaryExpr {
|
||||
SemBitXorExpr() { opcode instanceof Opcode::BitXor }
|
||||
}
|
||||
|
||||
class SemUnaryExpr extends SemKnownExpr {
|
||||
SemExpr operand;
|
||||
|
||||
SemUnaryExpr() { Specific::unaryExpr(this, opcode, type, operand) }
|
||||
|
||||
final SemExpr getOperand() { result = operand }
|
||||
}
|
||||
|
||||
class SemBoxExpr extends SemUnaryExpr {
|
||||
SemBoxExpr() { opcode instanceof Opcode::Box }
|
||||
}
|
||||
|
||||
class SemUnboxExpr extends SemUnaryExpr {
|
||||
SemUnboxExpr() { opcode instanceof Opcode::Unbox }
|
||||
}
|
||||
|
||||
class SemConvertExpr extends SemUnaryExpr {
|
||||
SemConvertExpr() { opcode instanceof Opcode::Convert }
|
||||
}
|
||||
|
||||
class SemCopyValueExpr extends SemUnaryExpr {
|
||||
SemCopyValueExpr() { opcode instanceof Opcode::CopyValue }
|
||||
}
|
||||
|
||||
class SemNegateExpr extends SemUnaryExpr {
|
||||
SemNegateExpr() { opcode instanceof Opcode::Negate }
|
||||
}
|
||||
|
||||
class SemBitComplementExpr extends SemUnaryExpr {
|
||||
SemBitComplementExpr() { opcode instanceof Opcode::BitComplement }
|
||||
}
|
||||
|
||||
class SemLogicalNotExpr extends SemUnaryExpr {
|
||||
SemLogicalNotExpr() { opcode instanceof Opcode::LogicalNot }
|
||||
}
|
||||
|
||||
class SemAddOneExpr extends SemUnaryExpr {
|
||||
SemAddOneExpr() { opcode instanceof Opcode::AddOne }
|
||||
}
|
||||
|
||||
class SemSubOneExpr extends SemUnaryExpr {
|
||||
SemSubOneExpr() { opcode instanceof Opcode::SubOne }
|
||||
}
|
||||
|
||||
private class SemNullaryExpr extends SemKnownExpr {
|
||||
SemNullaryExpr() { Specific::nullaryExpr(this, opcode, type) }
|
||||
}
|
||||
|
||||
class SemInitializeParameterExpr extends SemNullaryExpr {
|
||||
SemInitializeParameterExpr() { opcode instanceof Opcode::InitializeParameter }
|
||||
}
|
||||
|
||||
class SemLoadExpr extends SemNullaryExpr {
|
||||
SemLoadExpr() { opcode instanceof Opcode::Load }
|
||||
|
||||
final SemSsaVariable getDef() { result.getAUse() = this }
|
||||
}
|
||||
|
||||
class SemSsaLoadExpr extends SemLoadExpr {
|
||||
SemSsaLoadExpr() { exists(getDef()) }
|
||||
}
|
||||
|
||||
class SemNonSsaLoadExpr extends SemLoadExpr {
|
||||
SemNonSsaLoadExpr() { not exists(getDef()) }
|
||||
}
|
||||
|
||||
class SemStoreExpr extends SemUnaryExpr {
|
||||
SemStoreExpr() { opcode instanceof Opcode::Store }
|
||||
}
|
||||
|
||||
class SemConditionalExpr extends SemKnownExpr {
|
||||
SemExpr condition;
|
||||
SemExpr trueResult;
|
||||
SemExpr falseResult;
|
||||
|
||||
SemConditionalExpr() {
|
||||
opcode instanceof Opcode::Conditional and
|
||||
Specific::conditionalExpr(this, type, condition, trueResult, falseResult)
|
||||
}
|
||||
|
||||
final SemExpr getBranchExpr(boolean branch) {
|
||||
branch = true and result = trueResult
|
||||
or
|
||||
branch = false and result = falseResult
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,297 @@
|
||||
/**
|
||||
* C++-specific implementation of the semantic interface.
|
||||
*/
|
||||
|
||||
private import cpp as Cpp
|
||||
private import semmle.code.cpp.ir.IR as IR
|
||||
private import Semantic
|
||||
private import experimental.semmle.code.cpp.rangeanalysis.Bound as IRBound
|
||||
private import semmle.code.cpp.controlflow.IRGuards as IRGuards
|
||||
|
||||
module SemanticExprConfig {
|
||||
class Location = Cpp::Location;
|
||||
|
||||
class Expr = IR::Instruction;
|
||||
|
||||
SemBasicBlock getExprBasicBlock(Expr e) { result = getSemanticBasicBlock(e.getBlock()) }
|
||||
|
||||
private predicate anyConstantExpr(Expr expr, SemType type, string value) {
|
||||
exists(IR::ConstantInstruction instr | instr = expr |
|
||||
type = getSemanticType(instr.getResultIRType()) and
|
||||
value = instr.getValue()
|
||||
)
|
||||
}
|
||||
|
||||
predicate integerLiteral(Expr expr, SemIntegerType type, int value) {
|
||||
exists(string valueString |
|
||||
anyConstantExpr(expr, type, valueString) and
|
||||
value = valueString.toInt()
|
||||
)
|
||||
}
|
||||
|
||||
predicate largeIntegerLiteral(Expr expr, SemIntegerType type, float approximateFloatValue) {
|
||||
exists(string valueString |
|
||||
anyConstantExpr(expr, type, valueString) and
|
||||
not exists(valueString.toInt()) and
|
||||
approximateFloatValue = valueString.toFloat()
|
||||
)
|
||||
}
|
||||
|
||||
predicate floatingPointLiteral(Expr expr, SemFloatingPointType type, float value) {
|
||||
exists(string valueString |
|
||||
anyConstantExpr(expr, type, valueString) and value = valueString.toFloat()
|
||||
)
|
||||
}
|
||||
|
||||
predicate booleanLiteral(Expr expr, SemBooleanType type, boolean value) {
|
||||
exists(string valueString |
|
||||
anyConstantExpr(expr, type, valueString) and
|
||||
(
|
||||
valueString = "true" and value = true
|
||||
or
|
||||
valueString = "false" and value = false
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
predicate nullLiteral(Expr expr, SemAddressType type) { anyConstantExpr(expr, type, _) }
|
||||
|
||||
predicate stringLiteral(Expr expr, SemType type, string value) {
|
||||
anyConstantExpr(expr, type, value) and expr instanceof IR::StringConstantInstruction
|
||||
}
|
||||
|
||||
predicate binaryExpr(Expr expr, Opcode opcode, SemType type, Expr leftOperand, Expr rightOperand) {
|
||||
exists(IR::BinaryInstruction instr | instr = expr |
|
||||
type = getSemanticType(instr.getResultIRType()) and
|
||||
leftOperand = instr.getLeft() and
|
||||
rightOperand = instr.getRight() and
|
||||
// REVIEW: Merge the two `Opcode` types.
|
||||
opcode.toString() = instr.getOpcode().toString()
|
||||
)
|
||||
}
|
||||
|
||||
predicate unaryExpr(Expr expr, Opcode opcode, SemType type, Expr operand) {
|
||||
type = getSemanticType(expr.getResultIRType()) and
|
||||
(
|
||||
exists(IR::UnaryInstruction instr | instr = expr |
|
||||
operand = instr.getUnary() and
|
||||
// REVIEW: Merge the two operand types.
|
||||
opcode.toString() = instr.getOpcode().toString()
|
||||
)
|
||||
or
|
||||
exists(IR::StoreInstruction instr | instr = expr |
|
||||
operand = instr.getSourceValue() and
|
||||
opcode instanceof Opcode::Store
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
predicate nullaryExpr(Expr expr, Opcode opcode, SemType type) {
|
||||
type = getSemanticType(expr.getResultIRType()) and
|
||||
(
|
||||
expr instanceof IR::LoadInstruction and opcode instanceof Opcode::Load
|
||||
or
|
||||
expr instanceof IR::InitializeParameterInstruction and
|
||||
opcode instanceof Opcode::InitializeParameter
|
||||
)
|
||||
}
|
||||
|
||||
predicate conditionalExpr(
|
||||
Expr expr, SemType type, Expr condition, Expr trueResult, Expr falseResult
|
||||
) {
|
||||
none()
|
||||
}
|
||||
|
||||
SemType getUnknownExprType(Expr expr) { result = getSemanticType(expr.getResultIRType()) }
|
||||
|
||||
class BasicBlock = IR::IRBlock;
|
||||
|
||||
predicate bbDominates(BasicBlock dominator, BasicBlock dominated) {
|
||||
dominator.dominates(dominated)
|
||||
}
|
||||
|
||||
predicate hasDominanceInformation(BasicBlock block) { any() }
|
||||
|
||||
int getBasicBlockUniqueId(BasicBlock block) {
|
||||
// REVIEW: `getDisplayIndex()` is not intended for use in real queries, but for now it's the
|
||||
// best we can do because `equivalentRelation` won't accept a predicate whose parameters are IPA
|
||||
// types.
|
||||
result = block.getDisplayIndex()
|
||||
}
|
||||
|
||||
class SsaVariable instanceof IR::Instruction {
|
||||
SsaVariable() { super.hasMemoryResult() }
|
||||
|
||||
final string toString() { result = super.toString() }
|
||||
|
||||
final Location getLocation() { result = super.getLocation() }
|
||||
}
|
||||
|
||||
predicate explicitUpdate(SsaVariable v, Expr sourceExpr) { v = sourceExpr }
|
||||
|
||||
predicate phi(SsaVariable v) { v instanceof IR::PhiInstruction }
|
||||
|
||||
SsaVariable getAPhiInput(SsaVariable v) { result = v.(IR::PhiInstruction).getAnInput() }
|
||||
|
||||
Expr getAUse(SsaVariable v) { result.(IR::LoadInstruction).getSourceValue() = v }
|
||||
|
||||
SemType getSsaVariableType(SsaVariable v) {
|
||||
result = getSemanticType(v.(IR::Instruction).getResultIRType())
|
||||
}
|
||||
|
||||
BasicBlock getSsaVariableBasicBlock(SsaVariable v) { result = v.(IR::Instruction).getBlock() }
|
||||
|
||||
private newtype TReadPosition =
|
||||
TReadPositionBlock(IR::IRBlock block) or
|
||||
TReadPositionPhiInputEdge(IR::IRBlock pred, IR::IRBlock succ) {
|
||||
exists(IR::PhiInputOperand input |
|
||||
pred = input.getPredecessorBlock() and
|
||||
succ = input.getUse().getBlock()
|
||||
)
|
||||
}
|
||||
|
||||
class SsaReadPosition extends TReadPosition {
|
||||
string toString() { none() }
|
||||
|
||||
Location getLocation() { none() }
|
||||
|
||||
predicate hasRead(SsaVariable v) { none() }
|
||||
}
|
||||
|
||||
private class SsaReadPositionBlock extends SsaReadPosition, TReadPositionBlock {
|
||||
IR::IRBlock block;
|
||||
|
||||
SsaReadPositionBlock() { this = TReadPositionBlock(block) }
|
||||
|
||||
final override string toString() { result = block.toString() }
|
||||
|
||||
final override Location getLocation() { result = block.getLocation() }
|
||||
|
||||
final override predicate hasRead(SsaVariable v) {
|
||||
exists(IR::Operand operand |
|
||||
operand.getDef() = v and not operand instanceof IR::PhiInputOperand
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private class SsaReadPositionPhiInputEdge extends SsaReadPosition, TReadPositionPhiInputEdge {
|
||||
IR::IRBlock pred;
|
||||
IR::IRBlock succ;
|
||||
|
||||
SsaReadPositionPhiInputEdge() { this = TReadPositionPhiInputEdge(pred, succ) }
|
||||
|
||||
final override string toString() { result = pred.toString() + "->" + succ.toString() }
|
||||
|
||||
final override Location getLocation() { result = succ.getLocation() }
|
||||
|
||||
final override predicate hasRead(SsaVariable v) {
|
||||
exists(IR::PhiInputOperand operand |
|
||||
operand.getDef() = v and
|
||||
operand.getPredecessorBlock() = pred and
|
||||
operand.getUse().getBlock() = succ
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
predicate hasReadOfSsaVariable(SsaReadPosition pos, SsaVariable v) { pos.hasRead(v) }
|
||||
|
||||
predicate readBlock(SsaReadPosition pos, BasicBlock block) { pos = TReadPositionBlock(block) }
|
||||
|
||||
predicate phiInputEdge(SsaReadPosition pos, BasicBlock origBlock, BasicBlock phiBlock) {
|
||||
pos = TReadPositionPhiInputEdge(origBlock, phiBlock)
|
||||
}
|
||||
|
||||
predicate phiInput(SsaReadPosition pos, SsaVariable phi, SsaVariable input) {
|
||||
exists(IR::PhiInputOperand operand |
|
||||
pos = TReadPositionPhiInputEdge(operand.getPredecessorBlock(), operand.getUse().getBlock())
|
||||
|
|
||||
phi = operand.getUse() and input = operand.getDef()
|
||||
)
|
||||
}
|
||||
|
||||
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() }
|
||||
}
|
||||
|
||||
private class ValueNumberBound extends Bound {
|
||||
IRBound::ValueNumberBound bound;
|
||||
|
||||
ValueNumberBound() { bound = this }
|
||||
|
||||
override string toString() {
|
||||
result =
|
||||
min(SsaVariable instr |
|
||||
instr = bound.getValueNumber().getAnInstruction()
|
||||
|
|
||||
instr
|
||||
order by
|
||||
instr.(IR::Instruction).getBlock().getDisplayIndex(),
|
||||
instr.(IR::Instruction).getDisplayIndexInBlock()
|
||||
).toString()
|
||||
}
|
||||
}
|
||||
|
||||
predicate zeroBound(Bound bound) { bound instanceof IRBound::ZeroBound }
|
||||
|
||||
predicate ssaBound(Bound bound, SsaVariable v) {
|
||||
v = bound.(IRBound::ValueNumberBound).getValueNumber().getAnInstruction()
|
||||
}
|
||||
|
||||
Expr getBoundExpr(Bound bound, int delta) {
|
||||
result = bound.(IRBound::Bound).getInstruction(delta)
|
||||
}
|
||||
|
||||
class Guard = IRGuards::IRGuardCondition;
|
||||
|
||||
predicate guard(Guard guard, BasicBlock block) {
|
||||
block = guard.(IRGuards::IRGuardCondition).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)
|
||||
}
|
||||
|
||||
predicate guardDirectlyControlsBlock(Guard guard, BasicBlock controlled, boolean branch) {
|
||||
guard.(IRGuards::IRGuardCondition).controls(controlled, branch)
|
||||
}
|
||||
|
||||
predicate guardHasBranchEdge(Guard guard, BasicBlock bb1, BasicBlock bb2, boolean branch) {
|
||||
guard.(IRGuards::IRGuardCondition).controlsEdge(bb1, bb2, branch)
|
||||
}
|
||||
|
||||
Guard comparisonGuard(Expr e) { result = e }
|
||||
|
||||
predicate implies_v2(Guard g1, boolean b1, Guard g2, boolean b2) {
|
||||
none() // TODO
|
||||
}
|
||||
}
|
||||
|
||||
SemExpr getSemanticExpr(IR::Instruction instr) { result = instr }
|
||||
|
||||
IR::Instruction getCppInstruction(SemExpr e) { e = result }
|
||||
|
||||
SemBasicBlock getSemanticBasicBlock(IR::IRBlock block) { result = block }
|
||||
|
||||
IR::IRBlock getCppBasicBlock(SemBasicBlock block) { block = result }
|
||||
|
||||
SemSsaVariable getSemanticSsaVariable(IR::Instruction instr) { result = instr }
|
||||
|
||||
IR::Instruction getCppSsaVariableInstruction(SemSsaVariable v) { v = result }
|
||||
|
||||
SemBound getSemanticBound(IRBound::Bound bound) { result = bound }
|
||||
|
||||
IRBound::Bound getCppBound(SemBound bound) { bound = result }
|
||||
|
||||
SemGuard getSemanticGuard(IRGuards::IRGuardCondition guard) { result = guard }
|
||||
|
||||
IRGuards::IRGuardCondition getCppGuard(SemGuard guard) { guard = result }
|
||||
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* Semantic interface to the guards library.
|
||||
*/
|
||||
|
||||
private import Semantic
|
||||
private import SemanticExprSpecific::SemanticExprConfig as Specific
|
||||
|
||||
class SemGuard instanceof Specific::Guard {
|
||||
SemBasicBlock block;
|
||||
|
||||
SemGuard() { Specific::guard(this, block) }
|
||||
|
||||
final string toString() { result = super.toString() }
|
||||
|
||||
final Specific::Location getLocation() { result = super.getLocation() }
|
||||
|
||||
final predicate isEquality(SemExpr e1, SemExpr e2, boolean polarity) {
|
||||
Specific::equalityGuard(this, e1, e2, polarity)
|
||||
}
|
||||
|
||||
final predicate directlyControls(SemBasicBlock controlled, boolean branch) {
|
||||
Specific::guardDirectlyControlsBlock(this, controlled, branch)
|
||||
}
|
||||
|
||||
final predicate hasBranchEdge(SemBasicBlock bb1, SemBasicBlock bb2, boolean branch) {
|
||||
Specific::guardHasBranchEdge(this, bb1, bb2, branch)
|
||||
}
|
||||
|
||||
final SemBasicBlock getBasicBlock() { result = block }
|
||||
|
||||
final SemExpr asExpr() { result = Specific::getGuardAsExpr(this) }
|
||||
}
|
||||
|
||||
predicate semImplies_v2(SemGuard g1, boolean b1, SemGuard g2, boolean b2) {
|
||||
Specific::implies_v2(g1, b1, g2, b2)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `guard` directly controls the position `controlled` with the
|
||||
* value `testIsTrue`.
|
||||
*/
|
||||
predicate semGuardDirectlyControlsSsaRead(
|
||||
SemGuard guard, SemSsaReadPosition controlled, boolean testIsTrue
|
||||
) {
|
||||
guard.directlyControls(controlled.(SemSsaReadPositionBlock).getBlock(), testIsTrue)
|
||||
or
|
||||
exists(SemSsaReadPositionPhiInputEdge controlledEdge | controlledEdge = controlled |
|
||||
guard.directlyControls(controlledEdge.getOrigBlock(), testIsTrue) or
|
||||
guard.hasBranchEdge(controlledEdge.getOrigBlock(), controlledEdge.getPhiBlock(), testIsTrue)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `guard` controls the position `controlled` with the value `testIsTrue`.
|
||||
*/
|
||||
predicate semGuardControlsSsaRead(SemGuard guard, SemSsaReadPosition controlled, boolean testIsTrue) {
|
||||
semGuardDirectlyControlsSsaRead(guard, controlled, testIsTrue)
|
||||
or
|
||||
exists(SemGuard guard0, boolean testIsTrue0 |
|
||||
semImplies_v2(guard0, testIsTrue0, guard, testIsTrue) and
|
||||
semGuardControlsSsaRead(guard0, controlled, testIsTrue0)
|
||||
)
|
||||
}
|
||||
|
||||
SemGuard semGetComparisonGuard(SemRelationalExpr e) { result = Specific::comparisonGuard(e) }
|
||||
@@ -0,0 +1,179 @@
|
||||
/**
|
||||
* Definitions of all possible opcodes for `SemExpr`.
|
||||
*/
|
||||
private newtype TOpcode =
|
||||
TInitializeParameter() or
|
||||
TCopyValue() or
|
||||
TLoad() or
|
||||
TStore() or
|
||||
TAdd() or
|
||||
TSub() or
|
||||
TMul() or
|
||||
TDiv() or
|
||||
TRem() or
|
||||
TNegate() or
|
||||
TShiftLeft() or
|
||||
TShiftRight() or
|
||||
TShiftRightUnsigned() or // TODO: Based on type
|
||||
TBitAnd() or
|
||||
TBitOr() or
|
||||
TBitXor() or
|
||||
TBitComplement() or
|
||||
TLogicalNot() or
|
||||
TCompareEQ() or
|
||||
TCompareNE() or
|
||||
TCompareLT() or
|
||||
TCompareGT() or
|
||||
TCompareLE() or
|
||||
TCompareGE() or
|
||||
TPointerAdd() or
|
||||
TPointerSub() or
|
||||
TPointerDiff() or
|
||||
TConvert() or
|
||||
TConstant() or
|
||||
TStringConstant() or
|
||||
TAddOne() or // TODO: Combine with `TAdd`
|
||||
TSubOne() or // TODO: Combine with `TSub`
|
||||
TConditional() or // TODO: Represent as flow
|
||||
TCall() or
|
||||
TBox() or
|
||||
TUnbox() or
|
||||
TUnknown()
|
||||
|
||||
class Opcode extends TOpcode {
|
||||
string toString() { result = "???" }
|
||||
}
|
||||
|
||||
module Opcode {
|
||||
class InitializeParameter extends Opcode, TInitializeParameter {
|
||||
override string toString() { result = "InitializeParameter" }
|
||||
}
|
||||
|
||||
class CopyValue extends Opcode, TCopyValue {
|
||||
override string toString() { result = "CopyValue" }
|
||||
}
|
||||
|
||||
class Load extends Opcode, TLoad {
|
||||
override string toString() { result = "Load" }
|
||||
}
|
||||
|
||||
class Store extends Opcode, TStore {
|
||||
override string toString() { result = "Store" }
|
||||
}
|
||||
|
||||
class Add extends Opcode, TAdd {
|
||||
override string toString() { result = "Add" }
|
||||
}
|
||||
|
||||
class Sub extends Opcode, TSub {
|
||||
override string toString() { result = "Sub" }
|
||||
}
|
||||
|
||||
class Mul extends Opcode, TMul {
|
||||
override string toString() { result = "Mul" }
|
||||
}
|
||||
|
||||
class Div extends Opcode, TDiv {
|
||||
override string toString() { result = "Div" }
|
||||
}
|
||||
|
||||
class Rem extends Opcode, TRem {
|
||||
override string toString() { result = "Rem" }
|
||||
}
|
||||
|
||||
class Negate extends Opcode, TNegate {
|
||||
override string toString() { result = "Negate" }
|
||||
}
|
||||
|
||||
class ShiftLeft extends Opcode, TShiftLeft {
|
||||
override string toString() { result = "ShiftLeft" }
|
||||
}
|
||||
|
||||
class ShiftRight extends Opcode, TShiftRight {
|
||||
override string toString() { result = "ShiftRight" }
|
||||
}
|
||||
|
||||
class ShiftRightUnsigned extends Opcode, TShiftRightUnsigned {
|
||||
override string toString() { result = "ShiftRightUnsigned" }
|
||||
}
|
||||
|
||||
class BitAnd extends Opcode, TBitAnd {
|
||||
override string toString() { result = "BitAnd" }
|
||||
}
|
||||
|
||||
class BitOr extends Opcode, TBitOr {
|
||||
override string toString() { result = "BitOr" }
|
||||
}
|
||||
|
||||
class BitXor extends Opcode, TBitXor {
|
||||
override string toString() { result = "BitXor" }
|
||||
}
|
||||
|
||||
class BitComplement extends Opcode, TBitComplement {
|
||||
override string toString() { result = "BitComplement" }
|
||||
}
|
||||
|
||||
class LogicalNot extends Opcode, TLogicalNot {
|
||||
override string toString() { result = "LogicalNot" }
|
||||
}
|
||||
|
||||
class CompareEQ extends Opcode, TCompareEQ {
|
||||
override string toString() { result = "CompareEQ" }
|
||||
}
|
||||
|
||||
class CompareNE extends Opcode, TCompareNE {
|
||||
override string toString() { result = "CompareNE" }
|
||||
}
|
||||
|
||||
class CompareLT extends Opcode, TCompareLT {
|
||||
override string toString() { result = "CompareLT" }
|
||||
}
|
||||
|
||||
class CompareLE extends Opcode, TCompareLE {
|
||||
override string toString() { result = "CompareLE" }
|
||||
}
|
||||
|
||||
class CompareGT extends Opcode, TCompareGT {
|
||||
override string toString() { result = "CompareGT" }
|
||||
}
|
||||
|
||||
class CompareGE extends Opcode, TCompareGE {
|
||||
override string toString() { result = "CompareGE" }
|
||||
}
|
||||
|
||||
class Convert extends Opcode, TConvert {
|
||||
override string toString() { result = "Convert" }
|
||||
}
|
||||
|
||||
class AddOne extends Opcode, TAddOne {
|
||||
override string toString() { result = "AddOne" }
|
||||
}
|
||||
|
||||
class SubOne extends Opcode, TSubOne {
|
||||
override string toString() { result = "SubOne" }
|
||||
}
|
||||
|
||||
class Conditional extends Opcode, TConditional {
|
||||
override string toString() { result = "Conditional" }
|
||||
}
|
||||
|
||||
class Constant extends Opcode, TConstant {
|
||||
override string toString() { result = "Constant" }
|
||||
}
|
||||
|
||||
class StringConstant extends Opcode, TStringConstant {
|
||||
override string toString() { result = "StringConstant" }
|
||||
}
|
||||
|
||||
class Box extends Opcode, TBox {
|
||||
override string toString() { result = "Box" }
|
||||
}
|
||||
|
||||
class Unbox extends Opcode, TUnbox {
|
||||
override string toString() { result = "Unbox" }
|
||||
}
|
||||
|
||||
class Unknown extends Opcode, TUnknown {
|
||||
override string toString() { result = "Unknown" }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* Semantic interface to the SSA library.
|
||||
*/
|
||||
|
||||
private import Semantic
|
||||
private import SemanticExprSpecific::SemanticExprConfig as Specific
|
||||
|
||||
class SemSsaVariable instanceof Specific::SsaVariable {
|
||||
final string toString() { result = super.toString() }
|
||||
|
||||
final Specific::Location getLocation() { result = super.getLocation() }
|
||||
|
||||
final SemLoadExpr getAUse() { result = Specific::getAUse(this) }
|
||||
|
||||
final SemType getType() { result = Specific::getSsaVariableType(this) }
|
||||
|
||||
final SemBasicBlock getBasicBlock() { result = Specific::getSsaVariableBasicBlock(this) }
|
||||
}
|
||||
|
||||
class SemSsaExplicitUpdate extends SemSsaVariable {
|
||||
SemExpr sourceExpr;
|
||||
|
||||
SemSsaExplicitUpdate() { Specific::explicitUpdate(this, sourceExpr) }
|
||||
|
||||
final SemExpr getSourceExpr() { result = sourceExpr }
|
||||
}
|
||||
|
||||
class SemSsaPhiNode extends SemSsaVariable {
|
||||
SemSsaPhiNode() { Specific::phi(this) }
|
||||
|
||||
final SemSsaVariable getAPhiInput() { result = Specific::getAPhiInput(this) }
|
||||
}
|
||||
|
||||
class SemSsaReadPosition instanceof Specific::SsaReadPosition {
|
||||
final string toString() { result = super.toString() }
|
||||
|
||||
final Specific::Location getLocation() { result = super.getLocation() }
|
||||
|
||||
final predicate hasReadOfVar(SemSsaVariable var) { Specific::hasReadOfSsaVariable(this, var) }
|
||||
}
|
||||
|
||||
class SemSsaReadPositionPhiInputEdge extends SemSsaReadPosition {
|
||||
SemBasicBlock origBlock;
|
||||
SemBasicBlock phiBlock;
|
||||
|
||||
SemSsaReadPositionPhiInputEdge() { Specific::phiInputEdge(this, origBlock, phiBlock) }
|
||||
|
||||
predicate phiInput(SemSsaPhiNode phi, SemSsaVariable inp) { Specific::phiInput(this, phi, inp) }
|
||||
|
||||
SemBasicBlock getOrigBlock() { result = origBlock }
|
||||
|
||||
SemBasicBlock getPhiBlock() { result = phiBlock }
|
||||
}
|
||||
|
||||
class SemSsaReadPositionBlock extends SemSsaReadPosition {
|
||||
SemBasicBlock block;
|
||||
|
||||
SemSsaReadPositionBlock() { Specific::readBlock(this, block) }
|
||||
|
||||
SemBasicBlock getBlock() { result = block }
|
||||
|
||||
SemExpr getAnExpr() { result = getBlock().getAnExpr() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `inp` is an input to `phi` along a back edge.
|
||||
*/
|
||||
predicate semBackEdge(SemSsaPhiNode phi, SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge) {
|
||||
edge.phiInput(phi, inp) and
|
||||
// Conservatively assume that every edge is a back edge if we don't have dominance information.
|
||||
(
|
||||
phi.getBasicBlock().bbDominates(edge.getOrigBlock()) or
|
||||
not edge.getOrigBlock().hasDominanceInformation()
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,301 @@
|
||||
/**
|
||||
* Minimal, language-neutral type system for semantic analysis.
|
||||
*/
|
||||
|
||||
private import SemanticTypeSpecific as Specific
|
||||
|
||||
class LanguageType = Specific::Type;
|
||||
|
||||
cached
|
||||
private newtype TSemType =
|
||||
TSemVoidType() { Specific::voidType(_) } or
|
||||
TSemUnknownType() { Specific::unknownType(_) } or
|
||||
TSemErrorType() { Specific::errorType(_) } or
|
||||
TSemBooleanType(int byteSize) { Specific::booleanType(_, byteSize) } or
|
||||
TSemIntegerType(int byteSize, boolean signed) { Specific::integerType(_, byteSize, signed) } or
|
||||
TSemFloatingPointType(int byteSize) { Specific::floatingPointType(_, byteSize) } or
|
||||
TSemAddressType(int byteSize) { Specific::addressType(_, byteSize) } or
|
||||
TSemFunctionAddressType(int byteSize) { Specific::functionAddressType(_, byteSize) } or
|
||||
TSemOpaqueType(int byteSize, Specific::OpaqueTypeTag tag) {
|
||||
Specific::opaqueType(_, byteSize, tag)
|
||||
}
|
||||
|
||||
/**
|
||||
* The language-neutral type of a semantic expression,
|
||||
* The interface to `SemType` and its subclasses is the same across all languages for which the IR
|
||||
* is supported, so analyses that expect to be used for multiple languages should generally use
|
||||
* `SemType` rather than a language-specific type.
|
||||
*
|
||||
* Many types from the language-specific type system will map to a single canonical `SemType`. Two
|
||||
* types that map to the same `SemType` are considered equivalent by semantic analysis. As an
|
||||
* example, in C++, all pointer types map to the same instance of `SemAddressType`.
|
||||
*/
|
||||
class SemType extends TSemType {
|
||||
/** Gets a textual representation of this type. */
|
||||
string toString() { none() }
|
||||
|
||||
/**
|
||||
* Gets a string that uniquely identifies this `SemType`. This string is often the same as the
|
||||
* result of `SemType.toString()`, but for some types it may be more verbose to ensure uniqueness.
|
||||
*/
|
||||
string getIdentityString() { result = toString() }
|
||||
|
||||
/**
|
||||
* Gets the size of the type, in bytes, if known.
|
||||
*
|
||||
* This will hold for all `SemType` objects except `SemUnknownType` and `SemErrorType`.
|
||||
*/
|
||||
// This predicate is overridden with `pragma[noinline]` in every leaf subclass.
|
||||
// This allows callers to ask for things like _the_ floating-point type of
|
||||
// size 4 without getting a join that first finds all types of size 4 and
|
||||
// _then_ restricts them to floating-point types.
|
||||
int getByteSize() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An unknown type. Generally used to represent results and operands that access an unknown set of
|
||||
* memory locations, such as the side effects of a function call.
|
||||
*/
|
||||
class SemUnknownType extends SemType, TSemUnknownType {
|
||||
final override string toString() { result = "unknown" }
|
||||
|
||||
final override int getByteSize() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A void type, which has no values. Used to represent the result type of an expression that does
|
||||
* not produce a result.
|
||||
*/
|
||||
class SemVoidType extends SemType, TSemVoidType {
|
||||
final override string toString() { result = "void" }
|
||||
|
||||
final override int getByteSize() { result = 0 }
|
||||
}
|
||||
|
||||
/**
|
||||
* An error type. Used when an error in the source code prevents the extractor from determining the
|
||||
* proper type.
|
||||
*/
|
||||
class SemErrorType extends SemType, TSemErrorType {
|
||||
final override string toString() { result = "error" }
|
||||
|
||||
final override int getByteSize() { result = 0 }
|
||||
}
|
||||
|
||||
private class SemSizedType extends SemType {
|
||||
int byteSize;
|
||||
|
||||
SemSizedType() {
|
||||
this = TSemBooleanType(byteSize) or
|
||||
this = TSemIntegerType(byteSize, _) or
|
||||
this = TSemFloatingPointType(byteSize) or
|
||||
this = TSemAddressType(byteSize) or
|
||||
this = TSemFunctionAddressType(byteSize) or
|
||||
this = TSemOpaqueType(byteSize, _)
|
||||
}
|
||||
// Don't override `getByteSize()` here. The optimizer seems to generate better code when this is
|
||||
// overridden only in the leaf classes.
|
||||
}
|
||||
|
||||
/**
|
||||
* A Boolean type, which can hold the values `true` (non-zero) or `false` (zero).
|
||||
*/
|
||||
class SemBooleanType extends SemSizedType, TSemBooleanType {
|
||||
final override string toString() { result = "bool" + byteSize.toString() }
|
||||
|
||||
pragma[noinline]
|
||||
final override int getByteSize() { result = byteSize }
|
||||
}
|
||||
|
||||
/**
|
||||
* A numeric type. This includes `SemSignedIntegerType`, `SemUnsignedIntegerType`, and
|
||||
* `SemFloatingPointType`.
|
||||
*/
|
||||
class SemNumericType extends SemSizedType {
|
||||
SemNumericType() {
|
||||
this = TSemIntegerType(byteSize, _) or
|
||||
this = TSemFloatingPointType(byteSize)
|
||||
}
|
||||
// Don't override `getByteSize()` here. The optimizer seems to generate better code when this is
|
||||
// overridden only in the leaf classes.
|
||||
}
|
||||
|
||||
/**
|
||||
* An integer type. This includes `SemSignedIntegerType` and `SemUnsignedIntegerType`.
|
||||
*/
|
||||
class SemIntegerType extends SemNumericType {
|
||||
boolean signed;
|
||||
|
||||
SemIntegerType() { this = TSemIntegerType(byteSize, signed) }
|
||||
|
||||
/** Holds if this integer type is signed. */
|
||||
final predicate isSigned() { signed = true }
|
||||
|
||||
/** Holds if this integer type is unsigned. */
|
||||
final predicate isUnsigned() { not isSigned() }
|
||||
// Don't override `getByteSize()` here. The optimizer seems to generate better code when this is
|
||||
// overridden only in the leaf classes.
|
||||
}
|
||||
|
||||
/**
|
||||
* A signed two's-complement integer. Also used to represent enums whose underlying type is a signed
|
||||
* integer, as well as character types whose representation is signed.
|
||||
*/
|
||||
class SemSignedIntegerType extends SemIntegerType {
|
||||
SemSignedIntegerType() { signed = true }
|
||||
|
||||
final override string toString() { result = "int" + byteSize.toString() }
|
||||
|
||||
pragma[noinline]
|
||||
final override int getByteSize() { result = byteSize }
|
||||
}
|
||||
|
||||
/**
|
||||
* An unsigned two's-complement integer. Also used to represent enums whose underlying type is an
|
||||
* unsigned integer, as well as character types whose representation is unsigned.
|
||||
*/
|
||||
class SemUnsignedIntegerType extends SemIntegerType {
|
||||
SemUnsignedIntegerType() { signed = false }
|
||||
|
||||
final override string toString() { result = "uint" + byteSize.toString() }
|
||||
|
||||
pragma[noinline]
|
||||
final override int getByteSize() { result = byteSize }
|
||||
}
|
||||
|
||||
/**
|
||||
* A floating-point type.
|
||||
*/
|
||||
class SemFloatingPointType extends SemNumericType, TSemFloatingPointType {
|
||||
final override string toString() { result = "float" + byteSize.toString() }
|
||||
|
||||
pragma[noinline]
|
||||
final override int getByteSize() { result = byteSize }
|
||||
}
|
||||
|
||||
/**
|
||||
* An address type, representing the memory address of data. Used to represent pointers, references,
|
||||
* and lvalues, include those that are garbage collected.
|
||||
*
|
||||
* The address of a function is represented by the separate `SemFunctionAddressType`.
|
||||
*/
|
||||
class SemAddressType extends SemSizedType, TSemAddressType {
|
||||
final override string toString() { result = "addr" + byteSize.toString() }
|
||||
|
||||
pragma[noinline]
|
||||
final override int getByteSize() { result = byteSize }
|
||||
}
|
||||
|
||||
/**
|
||||
* An address type, representing the memory address of code. Used to represent function pointers,
|
||||
* function references, and the target of a direct function call.
|
||||
*/
|
||||
class SemFunctionAddressType extends SemSizedType, TSemFunctionAddressType {
|
||||
final override string toString() { result = "func" + byteSize.toString() }
|
||||
|
||||
pragma[noinline]
|
||||
final override int getByteSize() { result = byteSize }
|
||||
}
|
||||
|
||||
/**
|
||||
* A type with known size that does not fit any of the other kinds of type. Used to represent
|
||||
* classes, structs, unions, fixed-size arrays, pointers-to-member, and more.
|
||||
*/
|
||||
class SemOpaqueType extends SemSizedType, TSemOpaqueType {
|
||||
Specific::OpaqueTypeTag tag;
|
||||
|
||||
SemOpaqueType() { this = TSemOpaqueType(byteSize, tag) }
|
||||
|
||||
final override string toString() {
|
||||
result = "opaque" + byteSize.toString() + "{" + tag.toString() + "}"
|
||||
}
|
||||
|
||||
final override string getIdentityString() {
|
||||
result = "opaque" + byteSize.toString() + "{" + Specific::getOpaqueTagIdentityString(tag) + "}"
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the "tag" that differentiates this type from other incompatible opaque types that have the
|
||||
* same size.
|
||||
*/
|
||||
final Specific::OpaqueTypeTag getTag() { result = tag }
|
||||
|
||||
pragma[noinline]
|
||||
final override int getByteSize() { result = byteSize }
|
||||
}
|
||||
|
||||
cached
|
||||
SemType getSemanticType(Specific::Type type) {
|
||||
exists(int byteSize |
|
||||
Specific::booleanType(type, byteSize) and result = TSemBooleanType(byteSize)
|
||||
or
|
||||
exists(boolean signed |
|
||||
Specific::integerType(type, byteSize, signed) and
|
||||
result = TSemIntegerType(byteSize, signed)
|
||||
)
|
||||
or
|
||||
Specific::floatingPointType(type, byteSize) and result = TSemFloatingPointType(byteSize)
|
||||
or
|
||||
Specific::addressType(type, byteSize) and result = TSemAddressType(byteSize)
|
||||
or
|
||||
Specific::functionAddressType(type, byteSize) and result = TSemFunctionAddressType(byteSize)
|
||||
or
|
||||
exists(Specific::OpaqueTypeTag tag |
|
||||
Specific::opaqueType(type, byteSize, tag) and result = TSemOpaqueType(byteSize, tag)
|
||||
)
|
||||
)
|
||||
or
|
||||
Specific::errorType(type) and result = TSemErrorType()
|
||||
or
|
||||
Specific::unknownType(type) and result = TSemUnknownType()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the conversion from `fromType` to `toType` can never overflow or underflow.
|
||||
*/
|
||||
predicate conversionCannotOverflow(SemNumericType fromType, SemNumericType toType) {
|
||||
// Identity cast
|
||||
fromType = toType
|
||||
or
|
||||
// Treat any cast to an FP type as safe. It can lose precision, but not overflow.
|
||||
toType instanceof SemFloatingPointType and fromType = any(SemNumericType n)
|
||||
or
|
||||
exists(SemIntegerType fromInteger, SemIntegerType toInteger, int fromSize, int toSize |
|
||||
fromInteger = fromType and
|
||||
toInteger = toType and
|
||||
fromSize = fromInteger.getByteSize() and
|
||||
toSize = toInteger.getByteSize()
|
||||
|
|
||||
// Conversion to a larger type. Safe unless converting signed -> unsigned.
|
||||
fromSize < toSize and
|
||||
(
|
||||
toInteger.isSigned()
|
||||
or
|
||||
not fromInteger.isSigned()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
* Query predicates used to check invariants that should hold for all `SemType` objects.
|
||||
*/
|
||||
module SemTypeConsistency {
|
||||
/**
|
||||
* Holds if the type has no result for `getSemanticType()`.
|
||||
*/
|
||||
query predicate missingSemType(Specific::Type type, string message) {
|
||||
not exists(getSemanticType(type)) and
|
||||
message = "`Type` does not have a corresponding `SemType`."
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the type has more than one result for `getSemanticType()`.
|
||||
*/
|
||||
query predicate multipleSemTypes(Specific::Type type, string message) {
|
||||
strictcount(getSemanticType(type)) > 1 and
|
||||
message =
|
||||
"`Type` " + type + " has multiple `SemType`s: " +
|
||||
concat(getSemanticType(type).toString(), ", ")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* C++-specific implementation of the semantic type system.
|
||||
*/
|
||||
|
||||
private import semmle.code.cpp.ir.IR as IR
|
||||
private import cpp as Cpp
|
||||
private import semmle.code.cpp.ir.internal.IRCppLanguage as Language
|
||||
|
||||
class Type = IR::IRType;
|
||||
|
||||
class OpaqueTypeTag = Language::OpaqueTypeTag;
|
||||
|
||||
predicate voidType(Type type) { type instanceof IR::IRVoidType }
|
||||
|
||||
predicate errorType(Type type) { type instanceof IR::IRErrorType }
|
||||
|
||||
predicate unknownType(Type type) { type instanceof IR::IRUnknownType }
|
||||
|
||||
predicate booleanType(Type type, int byteSize) { byteSize = type.(IR::IRBooleanType).getByteSize() }
|
||||
|
||||
predicate integerType(Type type, int byteSize, boolean signed) {
|
||||
byteSize = type.(IR::IRSignedIntegerType).getByteSize() and signed = true
|
||||
or
|
||||
byteSize = type.(IR::IRUnsignedIntegerType).getByteSize() and signed = false
|
||||
}
|
||||
|
||||
predicate floatingPointType(Type type, int byteSize) {
|
||||
byteSize = type.(IR::IRFloatingPointType).getByteSize()
|
||||
}
|
||||
|
||||
predicate addressType(Type type, int byteSize) { byteSize = type.(IR::IRAddressType).getByteSize() }
|
||||
|
||||
predicate functionAddressType(Type type, int byteSize) {
|
||||
byteSize = type.(IR::IRFunctionAddressType).getByteSize()
|
||||
}
|
||||
|
||||
predicate opaqueType(Type type, int byteSize, OpaqueTypeTag tag) {
|
||||
exists(IR::IROpaqueType opaque | opaque = type |
|
||||
byteSize = opaque.getByteSize() and tag = opaque.getTag()
|
||||
)
|
||||
}
|
||||
|
||||
predicate getOpaqueTagIdentityString = Language::getOpaqueTagIdentityString/1;
|
||||
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* Simple constant analysis using the Semantic interface.
|
||||
*/
|
||||
|
||||
private import experimental.semmle.code.cpp.semantic.Semantic
|
||||
private import ConstantAnalysisSpecific as Specific
|
||||
|
||||
/** An expression that always has the same integer value. */
|
||||
pragma[nomagic]
|
||||
private predicate constantIntegerExpr(SemExpr e, int val) {
|
||||
// An integer literal
|
||||
e.(SemIntegerLiteralExpr).getIntValue() = val
|
||||
or
|
||||
// Copy of another constant
|
||||
exists(SemSsaExplicitUpdate v, SemExpr src |
|
||||
e = v.getAUse() and
|
||||
src = v.getSourceExpr() and
|
||||
constantIntegerExpr(src, val)
|
||||
)
|
||||
or
|
||||
// Language-specific enhancements
|
||||
val = Specific::getIntConstantValue(e)
|
||||
}
|
||||
|
||||
/** An expression that always has the same integer value. */
|
||||
class SemConstantIntegerExpr extends SemExpr {
|
||||
SemConstantIntegerExpr() { constantIntegerExpr(this, _) }
|
||||
|
||||
/** Gets the integer value of this expression. */
|
||||
int getIntValue() { constantIntegerExpr(this, result) }
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
/**
|
||||
* C++-specific implementation of constant analysis.
|
||||
*/
|
||||
|
||||
private import experimental.semmle.code.cpp.semantic.Semantic
|
||||
|
||||
/**
|
||||
* Gets the constant integer value of the specified expression, if any.
|
||||
*/
|
||||
int getIntConstantValue(SemExpr expr) { none() }
|
||||
@@ -0,0 +1,310 @@
|
||||
/**
|
||||
* Provides inferences of the form: `e` equals `b + v` modulo `m` where `e` is
|
||||
* an expression, `b` is a `Bound` (typically zero or the value of an SSA
|
||||
* variable), and `v` is an integer in the range `[0 .. m-1]`.
|
||||
*/
|
||||
|
||||
private import ModulusAnalysisSpecific::Private
|
||||
private import experimental.semmle.code.cpp.semantic.Semantic
|
||||
private import ConstantAnalysis
|
||||
private import RangeUtils
|
||||
|
||||
/**
|
||||
* Holds if `e + delta` equals `v` at `pos`.
|
||||
*/
|
||||
private predicate valueFlowStepSsa(SemSsaVariable v, SemSsaReadPosition pos, SemExpr e, int delta) {
|
||||
semSsaUpdateStep(v, e, delta) and pos.hasReadOfVar(v)
|
||||
or
|
||||
exists(SemGuard guard, boolean testIsTrue |
|
||||
pos.hasReadOfVar(v) and
|
||||
guard = semEqFlowCond(v, e, delta, true, testIsTrue) and
|
||||
semGuardDirectlyControlsSsaRead(guard, pos, testIsTrue)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `add` is the addition of `larg` and `rarg`, neither of which are
|
||||
* `ConstantIntegerExpr`s.
|
||||
*/
|
||||
private predicate nonConstAddition(SemExpr add, SemExpr larg, SemExpr rarg) {
|
||||
exists(SemAddExpr a | a = add |
|
||||
larg = a.getLeftOperand() and
|
||||
rarg = a.getRightOperand()
|
||||
) and
|
||||
not larg instanceof SemConstantIntegerExpr and
|
||||
not rarg instanceof SemConstantIntegerExpr
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `sub` is the subtraction of `larg` and `rarg`, where `rarg` is not
|
||||
* a `ConstantIntegerExpr`.
|
||||
*/
|
||||
private predicate nonConstSubtraction(SemExpr sub, SemExpr larg, SemExpr rarg) {
|
||||
exists(SemSubExpr s | s = sub |
|
||||
larg = s.getLeftOperand() and
|
||||
rarg = s.getRightOperand()
|
||||
) and
|
||||
not rarg instanceof SemConstantIntegerExpr
|
||||
}
|
||||
|
||||
/** Gets an expression that is the remainder modulo `mod` of `arg`. */
|
||||
private SemExpr modExpr(SemExpr arg, int mod) {
|
||||
exists(SemRemExpr rem |
|
||||
result = rem and
|
||||
arg = rem.getLeftOperand() and
|
||||
rem.getRightOperand().(SemConstantIntegerExpr).getIntValue() = mod and
|
||||
mod >= 2
|
||||
)
|
||||
or
|
||||
exists(SemConstantIntegerExpr c |
|
||||
mod = 2.pow([1 .. 30]) and
|
||||
c.getIntValue() = mod - 1 and
|
||||
result.(SemBitAndExpr).hasOperands(arg, c)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a guard that tests whether `v` is congruent with `val` modulo `mod` on
|
||||
* its `testIsTrue` branch.
|
||||
*/
|
||||
private SemGuard moduloCheck(SemSsaVariable v, int val, int mod, boolean testIsTrue) {
|
||||
exists(SemExpr rem, SemConstantIntegerExpr c, int r, boolean polarity |
|
||||
result.isEquality(rem, c, polarity) and
|
||||
c.getIntValue() = r and
|
||||
rem = modExpr(v.getAUse(), mod) and
|
||||
(
|
||||
testIsTrue = polarity and val = r
|
||||
or
|
||||
testIsTrue = polarity.booleanNot() and
|
||||
mod = 2 and
|
||||
val = 1 - r and
|
||||
(r = 0 or r = 1)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if a guard ensures that `v` at `pos` is congruent with `val` modulo `mod`.
|
||||
*/
|
||||
private predicate moduloGuardedRead(SemSsaVariable v, SemSsaReadPosition pos, int val, int mod) {
|
||||
exists(SemGuard guard, boolean testIsTrue |
|
||||
pos.hasReadOfVar(v) and
|
||||
guard = moduloCheck(v, val, mod, testIsTrue) and
|
||||
semGuardControlsSsaRead(guard, pos, testIsTrue)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `factor` is a power of 2 that divides `mask`. */
|
||||
bindingset[mask]
|
||||
private predicate andmaskFactor(int mask, int factor) {
|
||||
mask % factor = 0 and
|
||||
factor = 2.pow([1 .. 30])
|
||||
}
|
||||
|
||||
/** Holds if `e` is evenly divisible by `factor`. */
|
||||
private predicate evenlyDivisibleExpr(SemExpr e, int factor) {
|
||||
exists(SemConstantIntegerExpr c, int k | k = c.getIntValue() |
|
||||
e.(SemMulExpr).getAnOperand() = c and factor = k.abs() and factor >= 2
|
||||
or
|
||||
e.(SemShiftLeftExpr).getRightOperand() = c and factor = 2.pow(k) and k > 0
|
||||
or
|
||||
e.(SemBitAndExpr).getAnOperand() = c and factor = max(int f | andmaskFactor(k, f))
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `rix` is the number of input edges to `phi`.
|
||||
*/
|
||||
private predicate maxPhiInputRank(SemSsaPhiNode phi, int rix) {
|
||||
rix = max(int r | rankedPhiInput(phi, _, _, r))
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the remainder of `val` modulo `mod`.
|
||||
*
|
||||
* For `mod = 0` the result equals `val` and for `mod > 1` the result is within
|
||||
* the range `[0 .. mod-1]`.
|
||||
*/
|
||||
bindingset[val, mod]
|
||||
private int remainder(int val, int mod) {
|
||||
mod = 0 and result = val
|
||||
or
|
||||
mod > 1 and result = ((val % mod) + mod) % mod
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `inp` is an input to `phi` and equals `phi` modulo `mod` along `edge`.
|
||||
*/
|
||||
private predicate phiSelfModulus(
|
||||
SemSsaPhiNode phi, SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge, int mod
|
||||
) {
|
||||
exists(SemSsaBound phibound, int v, int m |
|
||||
edge.phiInput(phi, inp) and
|
||||
phibound.getAVariable() = phi and
|
||||
ssaModulus(inp, edge, phibound, v, m) and
|
||||
mod = m.gcd(v) and
|
||||
mod != 1
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `b + val` modulo `mod` is a candidate congruence class for `phi`.
|
||||
*/
|
||||
private predicate phiModulusInit(SemSsaPhiNode phi, SemBound b, int val, int mod) {
|
||||
exists(SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge |
|
||||
edge.phiInput(phi, inp) and
|
||||
ssaModulus(inp, edge, b, val, mod)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if all inputs to `phi` numbered `1` to `rix` are equal to `b + val` modulo `mod`.
|
||||
*/
|
||||
private predicate phiModulusRankStep(SemSsaPhiNode phi, SemBound b, int val, int mod, int rix) {
|
||||
rix = 0 and
|
||||
phiModulusInit(phi, b, val, mod)
|
||||
or
|
||||
exists(SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge, int v1, int m1 |
|
||||
mod != 1 and
|
||||
val = remainder(v1, mod)
|
||||
|
|
||||
exists(int v2, int m2 |
|
||||
rankedPhiInput(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)
|
||||
)
|
||||
or
|
||||
exists(int m2 |
|
||||
rankedPhiInput(phi, inp, edge, rix) and
|
||||
phiModulusRankStep(phi, b, v1, m1, rix - 1) and
|
||||
phiSelfModulus(phi, inp, edge, m2) and
|
||||
mod = m1.gcd(m2)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `phi` is equal to `b + val` modulo `mod`.
|
||||
*/
|
||||
private predicate phiModulus(SemSsaPhiNode phi, SemBound b, int val, int mod) {
|
||||
exists(int r |
|
||||
maxPhiInputRank(phi, r) and
|
||||
phiModulusRankStep(phi, b, val, mod, r)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `v` at `pos` is equal to `b + val` modulo `mod`.
|
||||
*/
|
||||
private predicate ssaModulus(SemSsaVariable v, SemSsaReadPosition pos, SemBound b, int val, int mod) {
|
||||
phiModulus(v, b, val, mod) and pos.hasReadOfVar(v)
|
||||
or
|
||||
b.(SemSsaBound).getAVariable() = v and pos.hasReadOfVar(v) and val = 0 and mod = 0
|
||||
or
|
||||
exists(SemExpr e, int val0, int delta |
|
||||
semExprModulus(e, b, val0, mod) and
|
||||
valueFlowStepSsa(v, pos, e, delta) and
|
||||
val = remainder(val0 + delta, mod)
|
||||
)
|
||||
or
|
||||
moduloGuardedRead(v, pos, val, mod) and b instanceof SemZeroBound
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `e` is equal to `b + val` modulo `mod`.
|
||||
*
|
||||
* There are two cases for the modulus:
|
||||
* - `mod = 0`: The equality `e = b + val` is an ordinary equality.
|
||||
* - `mod > 1`: `val` lies within the range `[0 .. mod-1]`.
|
||||
*/
|
||||
cached
|
||||
predicate semExprModulus(SemExpr e, SemBound b, int val, int mod) {
|
||||
not ignoreExprModulus(e) and
|
||||
(
|
||||
e = b.getExpr(val) and mod = 0
|
||||
or
|
||||
evenlyDivisibleExpr(e, mod) and
|
||||
val = 0 and
|
||||
b instanceof SemZeroBound
|
||||
or
|
||||
exists(SemSsaVariable v, SemSsaReadPositionBlock bb |
|
||||
ssaModulus(v, bb, b, val, mod) and
|
||||
e = v.getAUse() and
|
||||
bb.getAnExpr() = e
|
||||
)
|
||||
or
|
||||
exists(SemExpr mid, int val0, int delta |
|
||||
semExprModulus(mid, b, val0, mod) and
|
||||
semValueFlowStep(e, mid, delta) and
|
||||
val = remainder(val0 + delta, mod)
|
||||
)
|
||||
or
|
||||
exists(SemConditionalExpr cond, int v1, int v2, int m1, int m2 |
|
||||
cond = e and
|
||||
condExprBranchModulus(cond, true, b, v1, m1) and
|
||||
condExprBranchModulus(cond, false, b, v2, m2) and
|
||||
mod = m1.gcd(m2).gcd(v1 - v2) and
|
||||
mod != 1 and
|
||||
val = remainder(v1, mod)
|
||||
)
|
||||
or
|
||||
exists(SemBound b1, SemBound b2, int v1, int v2, int m1, int m2 |
|
||||
addModulus(e, true, b1, v1, m1) and
|
||||
addModulus(e, false, b2, v2, m2) and
|
||||
mod = m1.gcd(m2) and
|
||||
mod != 1 and
|
||||
val = remainder(v1 + v2, mod)
|
||||
|
|
||||
b = b1 and b2 instanceof SemZeroBound
|
||||
or
|
||||
b = b2 and b1 instanceof SemZeroBound
|
||||
)
|
||||
or
|
||||
exists(int v1, int v2, int m1, int m2 |
|
||||
subModulus(e, true, b, v1, m1) and
|
||||
subModulus(e, false, any(SemZeroBound zb), v2, m2) and
|
||||
mod = m1.gcd(m2) and
|
||||
mod != 1 and
|
||||
val = remainder(v1 - v2, mod)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate condExprBranchModulus(
|
||||
SemConditionalExpr cond, boolean branch, SemBound b, int val, int mod
|
||||
) {
|
||||
semExprModulus(cond.getBranchExpr(branch), b, val, mod)
|
||||
}
|
||||
|
||||
private predicate addModulus(SemExpr add, boolean isLeft, SemBound b, int val, int mod) {
|
||||
exists(SemExpr larg, SemExpr rarg | nonConstAddition(add, larg, rarg) |
|
||||
semExprModulus(larg, b, val, mod) and isLeft = true
|
||||
or
|
||||
semExprModulus(rarg, b, val, mod) and isLeft = false
|
||||
)
|
||||
}
|
||||
|
||||
private predicate subModulus(SemExpr sub, boolean isLeft, SemBound b, int val, int mod) {
|
||||
exists(SemExpr larg, SemExpr rarg | nonConstSubtraction(sub, larg, rarg) |
|
||||
semExprModulus(larg, b, val, mod) and isLeft = true
|
||||
or
|
||||
semExprModulus(rarg, b, val, mod) and isLeft = false
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `inp` is an input to `phi` along `edge` and this input has index `r`
|
||||
* in an arbitrary 1-based numbering of the input edges to `phi`.
|
||||
*/
|
||||
private predicate rankedPhiInput(
|
||||
SemSsaPhiNode phi, SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge, int r
|
||||
) {
|
||||
edge.phiInput(phi, inp) and
|
||||
edge =
|
||||
rank[r](SemSsaReadPositionPhiInputEdge e |
|
||||
e.phiInput(phi, _)
|
||||
|
|
||||
e order by e.getOrigBlock().getUniqueId()
|
||||
)
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
/**
|
||||
* C++-specific implementation of modulus analysis.
|
||||
*/
|
||||
module Private {
|
||||
private import experimental.semmle.code.cpp.semantic.Semantic
|
||||
|
||||
predicate ignoreExprModulus(SemExpr e) { none() }
|
||||
}
|
||||
@@ -0,0 +1,807 @@
|
||||
/**
|
||||
* Provides classes and predicates for range analysis.
|
||||
*
|
||||
* An inferred bound can either be a specific integer, the abstract value of an
|
||||
* SSA variable, or the abstract value of an interesting expression. The latter
|
||||
* category includes array lengths that are not SSA variables.
|
||||
*
|
||||
* If an inferred bound relies directly on a condition, then this condition is
|
||||
* reported as the reason for the bound.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This library tackles range analysis as a flow problem. Consider e.g.:
|
||||
* ```
|
||||
* len = arr.length;
|
||||
* if (x < len) { ... y = x-1; ... y ... }
|
||||
* ```
|
||||
* In this case we would like to infer `y <= arr.length - 2`, and this is
|
||||
* accomplished by tracking the bound through a sequence of steps:
|
||||
* ```
|
||||
* arr.length --> len = .. --> x < len --> x-1 --> y = .. --> y
|
||||
* ```
|
||||
*
|
||||
* In its simplest form the step relation `E1 --> E2` relates two expressions
|
||||
* such that `E1 <= B` implies `E2 <= B` for any `B` (with a second separate
|
||||
* step relation handling lower bounds). Examples of such steps include
|
||||
* assignments `E2 = E1` and conditions `x <= E1` where `E2` is a use of `x`
|
||||
* guarded by the condition.
|
||||
*
|
||||
* In order to handle subtractions and additions with constants, and strict
|
||||
* comparisons, the step relation is augmented with an integer delta. With this
|
||||
* generalization `E1 --(delta)--> E2` relates two expressions and an integer
|
||||
* such that `E1 <= B` implies `E2 <= B + delta` for any `B`. This corresponds
|
||||
* to the predicate `boundFlowStep`.
|
||||
*
|
||||
* The complete range analysis is then implemented as the transitive closure of
|
||||
* the step relation summing the deltas along the way. If `E1` transitively
|
||||
* steps to `E2`, `delta` is the sum of deltas along the path, and `B` is an
|
||||
* interesting bound equal to the value of `E1` then `E2 <= B + delta`. This
|
||||
* corresponds to the predicate `bounded`.
|
||||
*
|
||||
* Phi nodes need a little bit of extra handling. Consider `x0 = phi(x1, x2)`.
|
||||
* There are essentially two cases:
|
||||
* - If `x1 <= B + d1` and `x2 <= B + d2` then `x0 <= B + max(d1,d2)`.
|
||||
* - If `x1 <= B + d1` and `x2 <= x0 + d2` with `d2 <= 0` then `x0 <= B + d1`.
|
||||
* The first case is for whenever a bound can be proven without taking looping
|
||||
* into account. The second case is relevant when `x2` comes from a back-edge
|
||||
* where we can prove that the variable has been non-increasing through the
|
||||
* loop-iteration as this means that any upper bound that holds prior to the
|
||||
* loop also holds for the variable during the loop.
|
||||
* This generalizes to a phi node with `n` inputs, so if
|
||||
* `x0 = phi(x1, ..., xn)` and `xi <= B + delta` for one of the inputs, then we
|
||||
* also have `x0 <= B + delta` if we can prove either:
|
||||
* - `xj <= B + d` with `d <= delta` or
|
||||
* - `xj <= x0 + d` with `d <= 0`
|
||||
* for each input `xj`.
|
||||
*
|
||||
* As all inferred bounds can be related directly to a path in the source code
|
||||
* the only source of non-termination is if successive redundant (and thereby
|
||||
* increasingly worse) bounds are calculated along a loop in the source code.
|
||||
* We prevent this by weakening the bound to a small finite set of bounds when
|
||||
* a path follows a second back-edge (we postpone weakening till the second
|
||||
* back-edge as a precise bound might require traversing a loop once).
|
||||
*/
|
||||
|
||||
private import RangeAnalysisSpecific as Specific
|
||||
private import RangeUtils
|
||||
private import SignAnalysisCommon
|
||||
private import ModulusAnalysis
|
||||
private import experimental.semmle.code.cpp.semantic.Semantic
|
||||
private import ConstantAnalysis
|
||||
|
||||
cached
|
||||
private module RangeAnalysisCache {
|
||||
cached
|
||||
module RangeAnalysisPublic {
|
||||
/**
|
||||
* Holds if `b + delta` is a valid bound for `e`.
|
||||
* - `upper = true` : `e <= b + delta`
|
||||
* - `upper = false` : `e >= b + delta`
|
||||
*
|
||||
* The reason for the bound is given by `reason` and may be either a condition
|
||||
* or `NoReason` if the bound was proven directly without the use of a bounding
|
||||
* condition.
|
||||
*/
|
||||
cached
|
||||
predicate semBounded(SemExpr e, SemBound b, int delta, boolean upper, SemReason reason) {
|
||||
bounded(e, b, delta, upper, _, _, reason) and
|
||||
bestBound(e, b, delta, upper)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `guard = boundFlowCond(_, _, _, _, _) or guard = eqFlowCond(_, _, _, _, _)`.
|
||||
*/
|
||||
cached
|
||||
predicate possibleReason(SemGuard guard) {
|
||||
guard = boundFlowCond(_, _, _, _, _) or guard = semEqFlowCond(_, _, _, _, _)
|
||||
}
|
||||
}
|
||||
|
||||
private import RangeAnalysisCache
|
||||
import RangeAnalysisPublic
|
||||
|
||||
/**
|
||||
* Holds if `b + delta` is a valid bound for `e` and this is the best such delta.
|
||||
* - `upper = true` : `e <= b + delta`
|
||||
* - `upper = false` : `e >= b + delta`
|
||||
*/
|
||||
private predicate bestBound(SemExpr e, SemBound b, int delta, boolean upper) {
|
||||
delta = min(int d | bounded(e, b, d, upper, _, _, _)) and upper = true
|
||||
or
|
||||
delta = max(int d | bounded(e, b, d, upper, _, _, _)) and upper = false
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `comp` corresponds to:
|
||||
* - `upper = true` : `v <= e + delta` or `v < e + delta`
|
||||
* - `upper = false` : `v >= e + delta` or `v > e + delta`
|
||||
*/
|
||||
private predicate boundCondition(
|
||||
SemRelationalExpr comp, SemSsaVariable v, SemExpr e, int delta, boolean upper
|
||||
) {
|
||||
comp.getLesserOperand() = semSsaRead(v, delta) and e = comp.getGreaterOperand() and upper = true
|
||||
or
|
||||
comp.getGreaterOperand() = semSsaRead(v, delta) and e = comp.getLesserOperand() and upper = false
|
||||
or
|
||||
exists(SemSubExpr sub, SemConstantIntegerExpr c, int d |
|
||||
// (v - d) - e < c
|
||||
comp.getLesserOperand() = sub and
|
||||
comp.getGreaterOperand() = c and
|
||||
sub.getLeftOperand() = semSsaRead(v, d) and
|
||||
sub.getRightOperand() = e and
|
||||
upper = true and
|
||||
delta = d + c.getIntValue()
|
||||
or
|
||||
// (v - d) - e > c
|
||||
comp.getGreaterOperand() = sub and
|
||||
comp.getLesserOperand() = c and
|
||||
sub.getLeftOperand() = semSsaRead(v, d) and
|
||||
sub.getRightOperand() = e and
|
||||
upper = false and
|
||||
delta = d + c.getIntValue()
|
||||
or
|
||||
// e - (v - d) < c
|
||||
comp.getLesserOperand() = sub and
|
||||
comp.getGreaterOperand() = c and
|
||||
sub.getLeftOperand() = e and
|
||||
sub.getRightOperand() = semSsaRead(v, d) and
|
||||
upper = false and
|
||||
delta = d - c.getIntValue()
|
||||
or
|
||||
// e - (v - d) > c
|
||||
comp.getGreaterOperand() = sub and
|
||||
comp.getLesserOperand() = c and
|
||||
sub.getLeftOperand() = e and
|
||||
sub.getRightOperand() = semSsaRead(v, d) and
|
||||
upper = true and
|
||||
delta = d - c.getIntValue()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `comp` is a comparison between `x` and `y` for which `y - x` has a
|
||||
* fixed value modulo some `mod > 1`, such that the comparison can be
|
||||
* strengthened by `strengthen` when evaluating to `testIsTrue`.
|
||||
*/
|
||||
private predicate modulusComparison(SemRelationalExpr comp, boolean testIsTrue, int strengthen) {
|
||||
exists(
|
||||
SemBound b, int v1, int v2, int mod1, int mod2, int mod, boolean resultIsStrict, int d, int k
|
||||
|
|
||||
// If `x <= y` and `x =(mod) b + v1` and `y =(mod) b + v2` then
|
||||
// `0 <= y - x =(mod) v2 - v1`. By choosing `k =(mod) v2 - v1` with
|
||||
// `0 <= k < mod` we get `k <= y - x`. If the resulting comparison is
|
||||
// strict then the strengthening amount is instead `k - 1` modulo `mod`:
|
||||
// `x < y` means `0 <= y - x - 1 =(mod) k - 1` so `k - 1 <= y - x - 1` and
|
||||
// thus `k - 1 < y - x` with `0 <= k - 1 < mod`.
|
||||
semExprModulus(comp.getLesserOperand(), b, v1, mod1) and
|
||||
semExprModulus(comp.getGreaterOperand(), b, v2, mod2) and
|
||||
mod = mod1.gcd(mod2) and
|
||||
mod != 1 and
|
||||
(testIsTrue = true or testIsTrue = false) and
|
||||
(
|
||||
if comp.isStrict()
|
||||
then resultIsStrict = testIsTrue
|
||||
else resultIsStrict = testIsTrue.booleanNot()
|
||||
) and
|
||||
(
|
||||
resultIsStrict = true and d = 1
|
||||
or
|
||||
resultIsStrict = false and d = 0
|
||||
) and
|
||||
(
|
||||
testIsTrue = true and k = v2 - v1
|
||||
or
|
||||
testIsTrue = false and k = v1 - v2
|
||||
) and
|
||||
strengthen = (((k - d) % mod) + mod) % mod
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a condition that tests whether `v` is bounded by `e + delta`.
|
||||
*
|
||||
* If the condition evaluates to `testIsTrue`:
|
||||
* - `upper = true` : `v <= e + delta`
|
||||
* - `upper = false` : `v >= e + delta`
|
||||
*/
|
||||
private SemGuard boundFlowCond(
|
||||
SemSsaVariable v, SemExpr e, int delta, boolean upper, boolean testIsTrue
|
||||
) {
|
||||
exists(
|
||||
SemRelationalExpr comp, int d1, int d2, int d3, int strengthen, boolean compIsUpper,
|
||||
boolean resultIsStrict
|
||||
|
|
||||
comp = result.asExpr() and
|
||||
boundCondition(comp, v, e, d1, compIsUpper) and
|
||||
(testIsTrue = true or testIsTrue = false) and
|
||||
upper = compIsUpper.booleanXor(testIsTrue.booleanNot()) and
|
||||
(
|
||||
if comp.isStrict()
|
||||
then resultIsStrict = testIsTrue
|
||||
else resultIsStrict = testIsTrue.booleanNot()
|
||||
) and
|
||||
(
|
||||
if getTrackedTypeForSsaVariable(v) instanceof SemIntegerType
|
||||
then
|
||||
upper = true and strengthen = -1
|
||||
or
|
||||
upper = false and strengthen = 1
|
||||
else strengthen = 0
|
||||
) and
|
||||
(
|
||||
exists(int k | modulusComparison(comp, testIsTrue, k) and d2 = strengthen * k)
|
||||
or
|
||||
not modulusComparison(comp, testIsTrue, _) and d2 = 0
|
||||
) and
|
||||
// A strict inequality `x < y` can be strengthened to `x <= y - 1`.
|
||||
(
|
||||
resultIsStrict = true and d3 = strengthen
|
||||
or
|
||||
resultIsStrict = false and d3 = 0
|
||||
) and
|
||||
delta = d1 + d2 + d3
|
||||
)
|
||||
or
|
||||
exists(boolean testIsTrue0 |
|
||||
semImplies_v2(result, testIsTrue, boundFlowCond(v, e, delta, upper, testIsTrue0), testIsTrue0)
|
||||
)
|
||||
or
|
||||
result = semEqFlowCond(v, e, delta, true, testIsTrue) and
|
||||
(upper = true or upper = false)
|
||||
or
|
||||
// guard that tests whether `v2` is bounded by `e + delta + d1 - d2` and
|
||||
// exists a guard `guardEq` such that `v = v2 - d1 + d2`.
|
||||
exists(SemSsaVariable v2, SemGuard guardEq, boolean eqIsTrue, int d1, int d2 |
|
||||
guardEq = semEqFlowCond(v, semSsaRead(v2, d1), d2, true, eqIsTrue) and
|
||||
result = boundFlowCond(v2, e, delta + d1 - d2, upper, testIsTrue) and
|
||||
// guardEq needs to control guard
|
||||
guardEq.directlyControls(result.getBasicBlock(), eqIsTrue)
|
||||
)
|
||||
}
|
||||
|
||||
private newtype TSemReason =
|
||||
TSemNoReason() or
|
||||
TSemCondReason(SemGuard guard) { possibleReason(guard) }
|
||||
|
||||
/**
|
||||
* A reason for an inferred bound. This can either be `CondReason` if the bound
|
||||
* is due to a specific condition, or `NoReason` if the bound is inferred
|
||||
* without going through a bounding condition.
|
||||
*/
|
||||
abstract class SemReason extends TSemReason {
|
||||
/** Gets a textual representation of this reason. */
|
||||
abstract string toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* A reason for an inferred bound that indicates that the bound is inferred
|
||||
* without going through a bounding condition.
|
||||
*/
|
||||
class SemNoReason extends SemReason, TSemNoReason {
|
||||
override string toString() { result = "NoReason" }
|
||||
}
|
||||
|
||||
/** A reason for an inferred bound pointing to a condition. */
|
||||
class SemCondReason extends SemReason, TSemCondReason {
|
||||
/** Gets the condition that is the reason for the bound. */
|
||||
SemGuard getCond() { this = TSemCondReason(result) }
|
||||
|
||||
override string toString() { result = getCond().toString() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `e + delta` is a valid bound for `v` at `pos`.
|
||||
* - `upper = true` : `v <= e + delta`
|
||||
* - `upper = false` : `v >= e + delta`
|
||||
*/
|
||||
private predicate boundFlowStepSsa(
|
||||
SemSsaVariable v, SemSsaReadPosition pos, SemExpr e, int delta, boolean upper, SemReason reason
|
||||
) {
|
||||
semSsaUpdateStep(v, e, delta) and
|
||||
pos.hasReadOfVar(v) and
|
||||
(upper = true or upper = false) and
|
||||
reason = TSemNoReason()
|
||||
or
|
||||
exists(SemGuard guard, boolean testIsTrue |
|
||||
pos.hasReadOfVar(v) and
|
||||
guard = boundFlowCond(v, e, delta, upper, testIsTrue) and
|
||||
semGuardDirectlyControlsSsaRead(guard, pos, testIsTrue) and
|
||||
reason = TSemCondReason(guard)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `v != e + delta` at `pos` and `v` is of integral type. */
|
||||
private predicate unequalFlowStepIntegralSsa(
|
||||
SemSsaVariable v, SemSsaReadPosition pos, SemExpr e, int delta, SemReason reason
|
||||
) {
|
||||
getTrackedTypeForSsaVariable(v) instanceof SemIntegerType and
|
||||
exists(SemGuard guard, boolean testIsTrue |
|
||||
pos.hasReadOfVar(v) and
|
||||
guard = semEqFlowCond(v, e, delta, false, testIsTrue) and
|
||||
semGuardDirectlyControlsSsaRead(guard, pos, testIsTrue) and
|
||||
reason = TSemCondReason(guard)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* An expression that does conversion, boxing, or unboxing
|
||||
*/
|
||||
private class ConvertOrBoxExpr extends SemUnaryExpr {
|
||||
ConvertOrBoxExpr() {
|
||||
this instanceof SemConvertExpr
|
||||
or
|
||||
this instanceof SemBoxExpr
|
||||
or
|
||||
this instanceof SemUnboxExpr
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A cast that can be ignored for the purpose of range analysis.
|
||||
*/
|
||||
private class SafeCastExpr extends ConvertOrBoxExpr {
|
||||
SafeCastExpr() { conversionCannotOverflow(getTrackedType(getOperand()), getTrackedType(this)) }
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `typ` is a small integral type with the given lower and upper bounds.
|
||||
*/
|
||||
private predicate typeBound(SemIntegerType typ, int lowerbound, int upperbound) {
|
||||
exists(int bitSize | bitSize = typ.getByteSize() * 8 |
|
||||
bitSize < 32 and
|
||||
(
|
||||
if typ.isSigned()
|
||||
then (
|
||||
upperbound = 1.bitShiftLeft(bitSize - 1) - 1 and
|
||||
lowerbound = -upperbound - 1
|
||||
) else (
|
||||
lowerbound = 0 and
|
||||
upperbound = 1.bitShiftLeft(bitSize) - 1
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* A cast to a small integral type that may overflow or underflow.
|
||||
*/
|
||||
private class NarrowingCastExpr extends ConvertOrBoxExpr {
|
||||
NarrowingCastExpr() {
|
||||
not this instanceof SafeCastExpr and
|
||||
typeBound(getTrackedType(this), _, _)
|
||||
}
|
||||
|
||||
/** Gets the lower bound of the resulting type. */
|
||||
int getLowerBound() { typeBound(getTrackedType(this), result, _) }
|
||||
|
||||
/** Gets the upper bound of the resulting type. */
|
||||
int getUpperBound() { typeBound(getTrackedType(this), _, result) }
|
||||
}
|
||||
|
||||
/** Holds if `e >= 1` as determined by sign analysis. */
|
||||
private predicate strictlyPositiveIntegralExpr(SemExpr e) {
|
||||
semStrictlyPositive(e) and getTrackedType(e) instanceof SemIntegerType
|
||||
}
|
||||
|
||||
/** Holds if `e <= -1` as determined by sign analysis. */
|
||||
private predicate strictlyNegativeIntegralExpr(SemExpr e) {
|
||||
semStrictlyNegative(e) and getTrackedType(e) instanceof SemIntegerType
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `e1 + delta` is a valid bound for `e2`.
|
||||
* - `upper = true` : `e2 <= e1 + delta`
|
||||
* - `upper = false` : `e2 >= e1 + delta`
|
||||
*/
|
||||
private predicate boundFlowStep(SemExpr e2, SemExpr e1, int delta, boolean upper) {
|
||||
semValueFlowStep(e2, e1, delta) and
|
||||
(upper = true or upper = false)
|
||||
or
|
||||
e2.(SafeCastExpr).getOperand() = e1 and
|
||||
delta = 0 and
|
||||
(upper = true or upper = false)
|
||||
or
|
||||
exists(SemExpr x | e2.(SemAddExpr).hasOperands(e1, x) |
|
||||
// `x instanceof ConstantIntegerExpr` is covered by valueFlowStep
|
||||
not x instanceof SemConstantIntegerExpr and
|
||||
not e1 instanceof SemConstantIntegerExpr and
|
||||
if strictlyPositiveIntegralExpr(x)
|
||||
then upper = false and delta = 1
|
||||
else
|
||||
if semPositive(x)
|
||||
then upper = false and delta = 0
|
||||
else
|
||||
if strictlyNegativeIntegralExpr(x)
|
||||
then upper = true and delta = -1
|
||||
else
|
||||
if semNegative(x)
|
||||
then upper = true and delta = 0
|
||||
else none()
|
||||
)
|
||||
or
|
||||
exists(SemExpr x, SemSubExpr sub |
|
||||
e2 = sub and
|
||||
sub.getLeftOperand() = e1 and
|
||||
sub.getRightOperand() = x
|
||||
|
|
||||
// `x instanceof ConstantIntegerExpr` is covered by valueFlowStep
|
||||
not x instanceof SemConstantIntegerExpr and
|
||||
if strictlyPositiveIntegralExpr(x)
|
||||
then upper = true and delta = -1
|
||||
else
|
||||
if semPositive(x)
|
||||
then upper = true and delta = 0
|
||||
else
|
||||
if strictlyNegativeIntegralExpr(x)
|
||||
then upper = false and delta = 1
|
||||
else
|
||||
if semNegative(x)
|
||||
then upper = false and delta = 0
|
||||
else none()
|
||||
)
|
||||
or
|
||||
e2.(SemRemExpr).getRightOperand() = e1 and
|
||||
semPositive(e1) and
|
||||
delta = -1 and
|
||||
upper = true
|
||||
or
|
||||
e2.(SemRemExpr).getLeftOperand() = e1 and semPositive(e1) and delta = 0 and upper = true
|
||||
or
|
||||
e2.(SemBitAndExpr).getAnOperand() = e1 and
|
||||
semPositive(e1) and
|
||||
delta = 0 and
|
||||
upper = true
|
||||
or
|
||||
e2.(SemBitOrExpr).getAnOperand() = e1 and
|
||||
semPositive(e2) and
|
||||
delta = 0 and
|
||||
upper = false
|
||||
or
|
||||
Specific::hasBound(e2, e1, delta, upper)
|
||||
}
|
||||
|
||||
/** Holds if `e2 = e1 * factor` and `factor > 0`. */
|
||||
private predicate boundFlowStepMul(SemExpr e2, SemExpr e1, int factor) {
|
||||
exists(SemConstantIntegerExpr c, int k | k = c.getIntValue() and k > 0 |
|
||||
e2.(SemMulExpr).hasOperands(e1, c) and factor = k
|
||||
or
|
||||
exists(SemShiftLeftExpr e |
|
||||
e = e2 and e.getLeftOperand() = e1 and e.getRightOperand() = c and factor = 2.pow(k)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `e2 = e1 / factor` and `factor > 0`.
|
||||
*
|
||||
* This conflates division, right shift, and unsigned right shift and is
|
||||
* therefore only valid for non-negative numbers.
|
||||
*/
|
||||
private predicate boundFlowStepDiv(SemExpr e2, SemExpr e1, int factor) {
|
||||
exists(SemConstantIntegerExpr c, int k | k = c.getIntValue() and k > 0 |
|
||||
exists(SemDivExpr e |
|
||||
e = e2 and e.getLeftOperand() = e1 and e.getRightOperand() = c and factor = k
|
||||
)
|
||||
or
|
||||
exists(SemShiftRightExpr e |
|
||||
e = e2 and e.getLeftOperand() = e1 and e.getRightOperand() = c and factor = 2.pow(k)
|
||||
)
|
||||
or
|
||||
exists(SemShiftRightUnsignedExpr e |
|
||||
e = e2 and e.getLeftOperand() = e1 and e.getRightOperand() = c and factor = 2.pow(k)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `b + delta` is a valid bound for `v` at `pos`.
|
||||
* - `upper = true` : `v <= b + delta`
|
||||
* - `upper = false` : `v >= b + delta`
|
||||
*/
|
||||
private predicate boundedSsa(
|
||||
SemSsaVariable v, SemSsaReadPosition pos, SemBound b, int delta, boolean upper,
|
||||
boolean fromBackEdge, int origdelta, SemReason reason
|
||||
) {
|
||||
exists(SemExpr mid, int d1, int d2, SemReason r1, SemReason r2 |
|
||||
boundFlowStepSsa(v, pos, mid, d1, upper, r1) and
|
||||
bounded(mid, b, d2, upper, fromBackEdge, origdelta, r2) and
|
||||
// upper = true: v <= mid + d1 <= b + d1 + d2 = b + delta
|
||||
// upper = false: v >= mid + d1 >= b + d1 + d2 = b + delta
|
||||
delta = d1 + d2 and
|
||||
(if r1 instanceof SemNoReason then reason = r2 else reason = r1)
|
||||
)
|
||||
or
|
||||
exists(int d, SemReason r1, SemReason r2 |
|
||||
boundedSsa(v, pos, b, d, upper, fromBackEdge, origdelta, r2) or
|
||||
boundedPhi(v, b, d, upper, fromBackEdge, origdelta, r2)
|
||||
|
|
||||
unequalIntegralSsa(v, pos, b, d, r1) and
|
||||
(
|
||||
upper = true and delta = d - 1
|
||||
or
|
||||
upper = false and delta = d + 1
|
||||
) and
|
||||
(
|
||||
reason = r1
|
||||
or
|
||||
reason = r2 and not r2 instanceof SemNoReason
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `v != b + delta` at `pos` and `v` is of integral type.
|
||||
*/
|
||||
private predicate unequalIntegralSsa(
|
||||
SemSsaVariable v, SemSsaReadPosition pos, SemBound b, int delta, SemReason reason
|
||||
) {
|
||||
exists(SemExpr e, int d1, int d2 |
|
||||
unequalFlowStepIntegralSsa(v, pos, e, d1, reason) and
|
||||
bounded(e, b, d2, true, _, _, _) and
|
||||
bounded(e, b, d2, false, _, _, _) and
|
||||
delta = d2 + d1
|
||||
)
|
||||
}
|
||||
|
||||
/** Weakens a delta to lie in the range `[-1..1]`. */
|
||||
bindingset[delta, upper]
|
||||
private int weakenDelta(boolean upper, int delta) {
|
||||
delta in [-1 .. 1] and result = delta
|
||||
or
|
||||
upper = true and result = -1 and delta < -1
|
||||
or
|
||||
upper = false and result = 1 and delta > 1
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `b + delta` is a valid bound for `inp` when used as an input to
|
||||
* `phi` along `edge`.
|
||||
* - `upper = true` : `inp <= b + delta`
|
||||
* - `upper = false` : `inp >= b + delta`
|
||||
*/
|
||||
private predicate boundedPhiInp(
|
||||
SemSsaPhiNode phi, SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge, SemBound b, int delta,
|
||||
boolean upper, boolean fromBackEdge, int origdelta, SemReason reason
|
||||
) {
|
||||
edge.phiInput(phi, inp) and
|
||||
exists(int d, boolean fromBackEdge0 |
|
||||
boundedSsa(inp, edge, b, d, upper, fromBackEdge0, origdelta, reason)
|
||||
or
|
||||
boundedPhi(inp, b, d, upper, fromBackEdge0, origdelta, reason)
|
||||
or
|
||||
b.(SemSsaBound).getAVariable() = inp and
|
||||
d = 0 and
|
||||
(upper = true or upper = false) and
|
||||
fromBackEdge0 = false and
|
||||
origdelta = 0 and
|
||||
reason = TSemNoReason()
|
||||
|
|
||||
if semBackEdge(phi, inp, edge)
|
||||
then
|
||||
fromBackEdge = true and
|
||||
(
|
||||
fromBackEdge0 = true and delta = weakenDelta(upper, d - origdelta) + origdelta
|
||||
or
|
||||
fromBackEdge0 = false and delta = d
|
||||
)
|
||||
else (
|
||||
delta = d and fromBackEdge = fromBackEdge0
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `b + delta` is a valid bound for `inp` when used as an input to
|
||||
* `phi` along `edge`.
|
||||
* - `upper = true` : `inp <= b + delta`
|
||||
* - `upper = false` : `inp >= b + delta`
|
||||
*
|
||||
* Equivalent to `boundedPhiInp(phi, inp, edge, b, delta, upper, _, _, _)`.
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate boundedPhiInp1(
|
||||
SemSsaPhiNode phi, SemBound b, boolean upper, SemSsaVariable inp,
|
||||
SemSsaReadPositionPhiInputEdge edge, int delta
|
||||
) {
|
||||
boundedPhiInp(phi, inp, edge, b, delta, upper, _, _, _)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `phi` is a valid bound for `inp` when used as an input to `phi`
|
||||
* along `edge`.
|
||||
* - `upper = true` : `inp <= phi`
|
||||
* - `upper = false` : `inp >= phi`
|
||||
*/
|
||||
private predicate selfBoundedPhiInp(
|
||||
SemSsaPhiNode phi, SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge, boolean upper
|
||||
) {
|
||||
exists(int d, SemSsaBound phibound |
|
||||
phibound.getAVariable() = phi and
|
||||
boundedPhiInp(phi, inp, edge, phibound, d, upper, _, _, _) and
|
||||
(
|
||||
upper = true and d <= 0
|
||||
or
|
||||
upper = false and d >= 0
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `b + delta` is a valid bound for some input, `inp`, to `phi`, and
|
||||
* thus a candidate bound for `phi`.
|
||||
* - `upper = true` : `inp <= b + delta`
|
||||
* - `upper = false` : `inp >= b + delta`
|
||||
*/
|
||||
pragma[noinline]
|
||||
private predicate boundedPhiCand(
|
||||
SemSsaPhiNode phi, boolean upper, SemBound b, int delta, boolean fromBackEdge, int origdelta,
|
||||
SemReason reason
|
||||
) {
|
||||
exists(SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge |
|
||||
boundedPhiInp(phi, inp, edge, b, delta, upper, fromBackEdge, origdelta, reason)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the candidate bound `b + delta` for `phi` is valid for the phi input
|
||||
* `inp` along `edge`.
|
||||
*/
|
||||
private predicate boundedPhiCandValidForEdge(
|
||||
SemSsaPhiNode phi, SemBound b, int delta, boolean upper, boolean fromBackEdge, int origdelta,
|
||||
SemReason reason, SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge
|
||||
) {
|
||||
boundedPhiCand(phi, upper, b, delta, fromBackEdge, origdelta, reason) and
|
||||
(
|
||||
exists(int d | boundedPhiInp1(phi, b, upper, inp, edge, d) | upper = true and d <= delta)
|
||||
or
|
||||
exists(int d | boundedPhiInp1(phi, b, upper, inp, edge, d) | upper = false and d >= delta)
|
||||
or
|
||||
selfBoundedPhiInp(phi, inp, edge, upper)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `b + delta` is a valid bound for `phi`.
|
||||
* - `upper = true` : `phi <= b + delta`
|
||||
* - `upper = false` : `phi >= b + delta`
|
||||
*/
|
||||
private predicate boundedPhi(
|
||||
SemSsaPhiNode phi, SemBound b, int delta, boolean upper, boolean fromBackEdge, int origdelta,
|
||||
SemReason reason
|
||||
) {
|
||||
forex(SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge | edge.phiInput(phi, inp) |
|
||||
boundedPhiCandValidForEdge(phi, b, delta, upper, fromBackEdge, origdelta, reason, inp, edge)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `e` has an upper (for `upper = true`) or lower
|
||||
* (for `upper = false`) bound of `b`.
|
||||
*/
|
||||
private predicate baseBound(SemExpr e, int b, boolean upper) {
|
||||
Specific::hasConstantBound(e, b, upper)
|
||||
or
|
||||
upper = false and
|
||||
b = 0 and
|
||||
semPositive(e.(SemBitAndExpr).getAnOperand()) and
|
||||
// REVIEW: We let the language opt out here to preserve original results.
|
||||
not Specific::ignoreZeroLowerBound(e)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the value being cast has an upper (for `upper = true`) or lower
|
||||
* (for `upper = false`) bound within the bounds of the resulting type.
|
||||
* For `upper = true` this means that the cast will not overflow and for
|
||||
* `upper = false` this means that the cast will not underflow.
|
||||
*/
|
||||
private predicate safeNarrowingCast(NarrowingCastExpr cast, boolean upper) {
|
||||
exists(int bound | bounded(cast.getOperand(), any(SemZeroBound zb), bound, upper, _, _, _) |
|
||||
upper = true and bound <= cast.getUpperBound()
|
||||
or
|
||||
upper = false and bound >= cast.getLowerBound()
|
||||
)
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
private predicate boundedCastExpr(
|
||||
NarrowingCastExpr cast, SemBound b, int delta, boolean upper, boolean fromBackEdge, int origdelta,
|
||||
SemReason reason
|
||||
) {
|
||||
bounded(cast.getOperand(), b, delta, upper, fromBackEdge, origdelta, reason)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `b + delta` is a valid bound for `e`.
|
||||
* - `upper = true` : `e <= b + delta`
|
||||
* - `upper = false` : `e >= b + delta`
|
||||
*/
|
||||
private predicate bounded(
|
||||
SemExpr e, SemBound b, int delta, boolean upper, boolean fromBackEdge, int origdelta,
|
||||
SemReason reason
|
||||
) {
|
||||
not Specific::ignoreExprBound(e) and
|
||||
(
|
||||
e = b.getExpr(delta) and
|
||||
(upper = true or upper = false) and
|
||||
fromBackEdge = false and
|
||||
origdelta = delta and
|
||||
reason = TSemNoReason()
|
||||
or
|
||||
baseBound(e, delta, upper) and
|
||||
b instanceof SemZeroBound and
|
||||
fromBackEdge = false and
|
||||
origdelta = delta and
|
||||
reason = TSemNoReason()
|
||||
or
|
||||
exists(SemSsaVariable v, SemSsaReadPositionBlock bb |
|
||||
boundedSsa(v, bb, b, delta, upper, fromBackEdge, origdelta, reason) and
|
||||
e = v.getAUse() and
|
||||
bb.getBlock() = e.getBasicBlock()
|
||||
)
|
||||
or
|
||||
exists(SemExpr mid, int d1, int d2 |
|
||||
boundFlowStep(e, mid, d1, upper) and
|
||||
// Constants have easy, base-case bounds, so let's not infer any recursive bounds.
|
||||
not e instanceof SemConstantIntegerExpr and
|
||||
bounded(mid, b, d2, upper, fromBackEdge, origdelta, reason) and
|
||||
// upper = true: e <= mid + d1 <= b + d1 + d2 = b + delta
|
||||
// upper = false: e >= mid + d1 >= b + d1 + d2 = b + delta
|
||||
delta = d1 + d2
|
||||
)
|
||||
or
|
||||
exists(SemSsaPhiNode phi |
|
||||
boundedPhi(phi, b, delta, upper, fromBackEdge, origdelta, reason) and
|
||||
e = phi.getAUse()
|
||||
)
|
||||
or
|
||||
exists(SemExpr mid, int factor, int d |
|
||||
boundFlowStepMul(e, mid, factor) and
|
||||
not e instanceof SemConstantIntegerExpr and
|
||||
bounded(mid, b, d, upper, fromBackEdge, origdelta, reason) and
|
||||
b instanceof SemZeroBound and
|
||||
delta = d * factor
|
||||
)
|
||||
or
|
||||
exists(SemExpr mid, int factor, int d |
|
||||
boundFlowStepDiv(e, mid, factor) and
|
||||
not e instanceof SemConstantIntegerExpr and
|
||||
bounded(mid, b, d, upper, fromBackEdge, origdelta, reason) and
|
||||
b instanceof SemZeroBound and
|
||||
d >= 0 and
|
||||
delta = d / factor
|
||||
)
|
||||
or
|
||||
exists(NarrowingCastExpr cast |
|
||||
cast = e and
|
||||
safeNarrowingCast(cast, upper.booleanNot()) and
|
||||
boundedCastExpr(cast, b, delta, upper, fromBackEdge, origdelta, reason)
|
||||
)
|
||||
or
|
||||
exists(
|
||||
SemConditionalExpr cond, int d1, int d2, boolean fbe1, boolean fbe2, int od1, int od2,
|
||||
SemReason r1, SemReason r2
|
||||
|
|
||||
cond = e and
|
||||
boundedConditionalExpr(cond, b, upper, true, d1, fbe1, od1, r1) and
|
||||
boundedConditionalExpr(cond, b, upper, false, d2, fbe2, od2, r2) and
|
||||
(
|
||||
delta = d1 and fromBackEdge = fbe1 and origdelta = od1 and reason = r1
|
||||
or
|
||||
delta = d2 and fromBackEdge = fbe2 and origdelta = od2 and reason = r2
|
||||
)
|
||||
|
|
||||
upper = true and delta = d1.maximum(d2)
|
||||
or
|
||||
upper = false and delta = d1.minimum(d2)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate boundedConditionalExpr(
|
||||
SemConditionalExpr cond, SemBound b, boolean upper, boolean branch, int delta,
|
||||
boolean fromBackEdge, int origdelta, SemReason reason
|
||||
) {
|
||||
bounded(cond.getBranchExpr(branch), b, delta, upper, fromBackEdge, origdelta, reason)
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/**
|
||||
* C++-specific implementation of range analysis.
|
||||
*/
|
||||
|
||||
private import experimental.semmle.code.cpp.semantic.Semantic
|
||||
|
||||
/**
|
||||
* Holds if the specified expression should be excluded from the result of `ssaRead()`.
|
||||
*
|
||||
* This predicate is to keep the results identical to the original Java implementation. It should be
|
||||
* removed once we have the new implementation matching the old results exactly.
|
||||
*/
|
||||
predicate ignoreSsaReadCopy(SemExpr e) { none() }
|
||||
|
||||
/**
|
||||
* Ignore the bound on this expression.
|
||||
*
|
||||
* This predicate is to keep the results identical to the original Java implementation. It should be
|
||||
* removed once we have the new implementation matching the old results exactly.
|
||||
*/
|
||||
predicate ignoreExprBound(SemExpr e) { none() }
|
||||
|
||||
/**
|
||||
* Ignore any inferred zero lower bound on this expression.
|
||||
*
|
||||
* This predicate is to keep the results identical to the original Java implementation. It should be
|
||||
* removed once we have the new implementation matching the old results exactly.
|
||||
*/
|
||||
predicate ignoreZeroLowerBound(SemExpr e) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the specified expression should be excluded from the result of `ssaRead()`.
|
||||
*
|
||||
* This predicate is to keep the results identical to the original Java implementation. It should be
|
||||
* removed once we have the new implementation matching the old results exactly.
|
||||
*/
|
||||
predicate ignoreSsaReadArithmeticExpr(SemExpr e) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the specified variable should be excluded from the result of `ssaRead()`.
|
||||
*
|
||||
* This predicate is to keep the results identical to the original Java implementation. It should be
|
||||
* removed once we have the new implementation matching the old results exactly.
|
||||
*/
|
||||
predicate ignoreSsaReadAssignment(SemSsaVariable v) { none() }
|
||||
|
||||
/**
|
||||
* Adds additional results to `ssaRead()` that are specific to Java.
|
||||
*
|
||||
* This predicate handles propagation of offsets for post-increment and post-decrement expressions
|
||||
* in exactly the same way as the old Java implementation. Once the new implementation matches the
|
||||
* old one, we should remove this predicate and propagate deltas for all similar patterns, whether
|
||||
* or not they come from a post-increment/decrement expression.
|
||||
*/
|
||||
SemExpr specificSsaRead(SemSsaVariable v, int delta) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `e >= bound` (if `upper = false`) or `e <= bound` (if `upper = true`).
|
||||
*/
|
||||
predicate hasConstantBound(SemExpr e, int bound, boolean upper) { none() }
|
||||
|
||||
/**
|
||||
* Holds if `e >= bound + delta` (if `upper = false`) or `e <= bound + delta` (if `upper = true`).
|
||||
*/
|
||||
predicate hasBound(SemExpr e, SemExpr bound, int delta, boolean upper) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the value of `dest` is known to be `src + delta`.
|
||||
*/
|
||||
predicate additionalValueFlowStep(SemExpr dest, SemExpr src, int delta) { none() }
|
||||
|
||||
/**
|
||||
* Gets the type that range analysis should use to track the result of the specified expression,
|
||||
* if a type other than the original type of the expression is to be used.
|
||||
*
|
||||
* This predicate is commonly used in languages that support immutable "boxed" types that are
|
||||
* actually references but whose values can be tracked as the type contained in the box.
|
||||
*/
|
||||
SemType getAlternateType(SemExpr e) { none() }
|
||||
|
||||
/**
|
||||
* Gets the type that range analysis should use to track the result of the specified source
|
||||
* variable, if a type other than the original type of the expression is to be used.
|
||||
*
|
||||
* This predicate is commonly used in languages that support immutable "boxed" types that are
|
||||
* actually references but whose values can be tracked as the type contained in the box.
|
||||
*/
|
||||
SemType getAlternateTypeForSsaVariable(SemSsaVariable var) { none() }
|
||||
@@ -0,0 +1,135 @@
|
||||
/**
|
||||
* Provides utility predicates for range analysis.
|
||||
*/
|
||||
|
||||
private import experimental.semmle.code.cpp.semantic.Semantic
|
||||
private import RangeAnalysisSpecific as Specific
|
||||
private import ConstantAnalysis
|
||||
|
||||
/**
|
||||
* Gets an expression that equals `v - d`.
|
||||
*/
|
||||
SemExpr semSsaRead(SemSsaVariable v, int delta) {
|
||||
// There are various language-specific extension points that can be removed once we no longer
|
||||
// expect to match the original Java implementation's results exactly.
|
||||
result = v.getAUse() and delta = 0
|
||||
or
|
||||
exists(int d1, SemConstantIntegerExpr c |
|
||||
result.(SemAddExpr).hasOperands(semSsaRead(v, d1), c) and
|
||||
delta = d1 - c.getIntValue() and
|
||||
not Specific::ignoreSsaReadArithmeticExpr(result)
|
||||
)
|
||||
or
|
||||
exists(SemSubExpr sub, int d1, SemConstantIntegerExpr c |
|
||||
result = sub and
|
||||
sub.getLeftOperand() = semSsaRead(v, d1) and
|
||||
sub.getRightOperand() = c and
|
||||
delta = d1 + c.getIntValue() and
|
||||
not Specific::ignoreSsaReadArithmeticExpr(result)
|
||||
)
|
||||
or
|
||||
result = v.(SemSsaExplicitUpdate).getSourceExpr() and
|
||||
delta = 0 and
|
||||
not Specific::ignoreSsaReadAssignment(v)
|
||||
or
|
||||
result = Specific::specificSsaRead(v, delta)
|
||||
or
|
||||
result.(SemCopyValueExpr).getOperand() = semSsaRead(v, delta) and
|
||||
not Specific::ignoreSsaReadCopy(result)
|
||||
or
|
||||
result.(SemStoreExpr).getOperand() = semSsaRead(v, delta)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a condition that tests whether `v` equals `e + delta`.
|
||||
*
|
||||
* If the condition evaluates to `testIsTrue`:
|
||||
* - `isEq = true` : `v == e + delta`
|
||||
* - `isEq = false` : `v != e + delta`
|
||||
*/
|
||||
SemGuard semEqFlowCond(SemSsaVariable v, SemExpr e, int delta, boolean isEq, boolean testIsTrue) {
|
||||
exists(boolean eqpolarity |
|
||||
result.isEquality(semSsaRead(v, delta), e, eqpolarity) and
|
||||
(testIsTrue = true or testIsTrue = false) and
|
||||
eqpolarity.booleanXor(testIsTrue).booleanNot() = isEq
|
||||
)
|
||||
or
|
||||
exists(boolean testIsTrue0 |
|
||||
semImplies_v2(result, testIsTrue, semEqFlowCond(v, e, delta, isEq, testIsTrue0), testIsTrue0)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `v` is an `SsaExplicitUpdate` that equals `e + delta`.
|
||||
*/
|
||||
predicate semSsaUpdateStep(SemSsaExplicitUpdate v, SemExpr e, int delta) {
|
||||
exists(SemExpr defExpr | defExpr = v.getSourceExpr() |
|
||||
defExpr.(SemCopyValueExpr).getOperand() = e and delta = 0
|
||||
or
|
||||
defExpr.(SemStoreExpr).getOperand() = e and delta = 0
|
||||
or
|
||||
defExpr.(SemAddOneExpr).getOperand() = e and delta = 1
|
||||
or
|
||||
defExpr.(SemSubOneExpr).getOperand() = e and delta = -1
|
||||
or
|
||||
e = defExpr and
|
||||
not (
|
||||
defExpr instanceof SemCopyValueExpr or
|
||||
defExpr instanceof SemStoreExpr or
|
||||
defExpr instanceof SemAddOneExpr or
|
||||
defExpr instanceof SemSubOneExpr
|
||||
) and
|
||||
delta = 0
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `e1 + delta` equals `e2`.
|
||||
*/
|
||||
predicate semValueFlowStep(SemExpr e2, SemExpr e1, int delta) {
|
||||
e2.(SemCopyValueExpr).getOperand() = e1 and delta = 0
|
||||
or
|
||||
e2.(SemStoreExpr).getOperand() = e1 and delta = 0
|
||||
or
|
||||
e2.(SemAddOneExpr).getOperand() = e1 and delta = 1
|
||||
or
|
||||
e2.(SemSubOneExpr).getOperand() = e1 and delta = -1
|
||||
or
|
||||
Specific::additionalValueFlowStep(e2, e1, delta)
|
||||
or
|
||||
exists(SemExpr x | e2.(SemAddExpr).hasOperands(e1, x) |
|
||||
x.(SemConstantIntegerExpr).getIntValue() = delta
|
||||
)
|
||||
or
|
||||
exists(SemExpr x, SemSubExpr sub |
|
||||
e2 = sub and
|
||||
sub.getLeftOperand() = e1 and
|
||||
sub.getRightOperand() = x
|
||||
|
|
||||
x.(SemConstantIntegerExpr).getIntValue() = -delta
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type used to track the specified expression's range information.
|
||||
*
|
||||
* Usually, this just `e.getSemType()`, but the language can override this to track immutable boxed
|
||||
* primitive types as the underlying primitive type.
|
||||
*/
|
||||
SemType getTrackedType(SemExpr e) {
|
||||
result = Specific::getAlternateType(e)
|
||||
or
|
||||
not exists(Specific::getAlternateType(e)) and result = e.getSemType()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type used to track the specified source variable's range information.
|
||||
*
|
||||
* Usually, this just `e.getType()`, but the language can override this to track immutable boxed
|
||||
* primitive types as the underlying primitive type.
|
||||
*/
|
||||
SemType getTrackedTypeForSsaVariable(SemSsaVariable var) {
|
||||
result = Specific::getAlternateTypeForSsaVariable(var)
|
||||
or
|
||||
not exists(Specific::getAlternateTypeForSsaVariable(var)) and result = var.getType()
|
||||
}
|
||||
@@ -0,0 +1,267 @@
|
||||
private import experimental.semmle.code.cpp.semantic.Semantic
|
||||
|
||||
newtype TSign =
|
||||
TNeg() or
|
||||
TZero() or
|
||||
TPos()
|
||||
|
||||
/** Class representing expression signs (+, -, 0). */
|
||||
class Sign extends TSign {
|
||||
/** Gets the string representation of this sign. */
|
||||
string toString() {
|
||||
result = "-" and this = TNeg()
|
||||
or
|
||||
result = "0" and this = TZero()
|
||||
or
|
||||
result = "+" and this = TPos()
|
||||
}
|
||||
|
||||
/** Gets a possible sign after incrementing an expression that has this sign. */
|
||||
Sign inc() {
|
||||
this = TNeg() and result = TNeg()
|
||||
or
|
||||
this = TNeg() and result = TZero()
|
||||
or
|
||||
this = TZero() and result = TPos()
|
||||
or
|
||||
this = TPos() and result = TPos()
|
||||
}
|
||||
|
||||
/** Gets a possible sign after decrementing an expression that has this sign. */
|
||||
Sign dec() { result.inc() = this }
|
||||
|
||||
/** Gets a possible sign after negating an expression that has this sign. */
|
||||
Sign neg() {
|
||||
this = TNeg() and result = TPos()
|
||||
or
|
||||
this = TZero() and result = TZero()
|
||||
or
|
||||
this = TPos() and result = TNeg()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a possible sign after bitwise complementing an expression that has this
|
||||
* sign.
|
||||
*/
|
||||
Sign bitnot() {
|
||||
this = TNeg() and result = TPos()
|
||||
or
|
||||
this = TNeg() and result = TZero()
|
||||
or
|
||||
this = TZero() and result = TNeg()
|
||||
or
|
||||
this = TPos() and result = TNeg()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a possible sign after adding an expression with sign `s` to an expression
|
||||
* that has this sign.
|
||||
*/
|
||||
Sign add(Sign s) {
|
||||
this = TZero() and result = s
|
||||
or
|
||||
s = TZero() and result = this
|
||||
or
|
||||
this = s and this = result
|
||||
or
|
||||
this = TPos() and s = TNeg()
|
||||
or
|
||||
this = TNeg() and s = TPos()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a possible sign after subtracting an expression with sign `s` from an expression
|
||||
* that has this sign.
|
||||
*/
|
||||
Sign sub(Sign s) { result = add(s.neg()) }
|
||||
|
||||
/**
|
||||
* Gets a possible sign after multiplying an expression with sign `s` to an expression
|
||||
* that has this sign.
|
||||
*/
|
||||
Sign mul(Sign s) {
|
||||
result = TZero() and this = TZero()
|
||||
or
|
||||
result = TZero() and s = TZero()
|
||||
or
|
||||
result = TNeg() and this = TPos() and s = TNeg()
|
||||
or
|
||||
result = TNeg() and this = TNeg() and s = TPos()
|
||||
or
|
||||
result = TPos() and this = TPos() and s = TPos()
|
||||
or
|
||||
result = TPos() and this = TNeg() and s = TNeg()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a possible sign after integer dividing an expression that has this sign
|
||||
* by an expression with sign `s`.
|
||||
*/
|
||||
Sign div(Sign s) {
|
||||
result = TZero() and s = TNeg() // ex: 3 / -5 = 0
|
||||
or
|
||||
result = TZero() and s = TPos() // ex: 3 / 5 = 0
|
||||
or
|
||||
result = TNeg() and this = TPos() and s = TNeg()
|
||||
or
|
||||
result = TNeg() and this = TNeg() and s = TPos()
|
||||
or
|
||||
result = TPos() and this = TPos() and s = TPos()
|
||||
or
|
||||
result = TPos() and this = TNeg() and s = TNeg()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a possible sign after modulo dividing an expression that has this sign
|
||||
* by an expression with sign `s`.
|
||||
*/
|
||||
Sign rem(Sign s) {
|
||||
result = TZero() and s = TNeg()
|
||||
or
|
||||
result = TZero() and s = TPos()
|
||||
or
|
||||
result = this and s = TNeg()
|
||||
or
|
||||
result = this and s = TPos()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a possible sign after bitwise `and` of an expression that has this sign
|
||||
* and an expression with sign `s`.
|
||||
*/
|
||||
Sign bitand(Sign s) {
|
||||
result = TZero() and this = TZero()
|
||||
or
|
||||
result = TZero() and s = TZero()
|
||||
or
|
||||
result = TZero() and this = TPos()
|
||||
or
|
||||
result = TZero() and s = TPos()
|
||||
or
|
||||
result = TNeg() and this = TNeg() and s = TNeg()
|
||||
or
|
||||
result = TPos() and this = TNeg() and s = TPos()
|
||||
or
|
||||
result = TPos() and this = TPos() and s = TNeg()
|
||||
or
|
||||
result = TPos() and this = TPos() and s = TPos()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a possible sign after bitwise `or` of an expression that has this sign
|
||||
* and an expression with sign `s`.
|
||||
*/
|
||||
Sign bitor(Sign s) {
|
||||
result = TZero() and this = TZero() and s = TZero()
|
||||
or
|
||||
result = TNeg() and this = TNeg()
|
||||
or
|
||||
result = TNeg() and s = TNeg()
|
||||
or
|
||||
result = TPos() and this = TPos() and s = TZero()
|
||||
or
|
||||
result = TPos() and this = TZero() and s = TPos()
|
||||
or
|
||||
result = TPos() and this = TPos() and s = TPos()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a possible sign after bitwise `xor` of an expression that has this sign
|
||||
* and an expression with sign `s`.
|
||||
*/
|
||||
Sign bitxor(Sign s) {
|
||||
result = TZero() and this = s
|
||||
or
|
||||
result = this and s = TZero()
|
||||
or
|
||||
result = s and this = TZero()
|
||||
or
|
||||
result = TPos() and this = TPos() and s = TPos()
|
||||
or
|
||||
result = TNeg() and this = TNeg() and s = TPos()
|
||||
or
|
||||
result = TNeg() and this = TPos() and s = TNeg()
|
||||
or
|
||||
result = TPos() and this = TNeg() and s = TNeg()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a possible sign after left shift of an expression that has this sign
|
||||
* by an expression with sign `s`.
|
||||
*/
|
||||
Sign lshift(Sign s) {
|
||||
result = TZero() and this = TZero()
|
||||
or
|
||||
result = this and s = TZero()
|
||||
or
|
||||
this != TZero() and s != TZero()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a possible sign after right shift of an expression that has this sign
|
||||
* by an expression with sign `s`.
|
||||
*/
|
||||
Sign rshift(Sign s) {
|
||||
result = TZero() and this = TZero()
|
||||
or
|
||||
result = this and s = TZero()
|
||||
or
|
||||
result = TNeg() and this = TNeg()
|
||||
or
|
||||
result != TNeg() and this = TPos() and s != TZero()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a possible sign after unsigned right shift of an expression that has
|
||||
* this sign by an expression with sign `s`.
|
||||
*/
|
||||
Sign urshift(Sign s) {
|
||||
result = TZero() and this = TZero()
|
||||
or
|
||||
result = this and s = TZero()
|
||||
or
|
||||
result != TZero() and this = TNeg() and s != TZero()
|
||||
or
|
||||
result != TNeg() and this = TPos() and s != TZero()
|
||||
}
|
||||
|
||||
/** Perform `op` on this sign. */
|
||||
Sign applyUnaryOp(Opcode op) {
|
||||
op instanceof Opcode::CopyValue and result = this
|
||||
or
|
||||
op instanceof Opcode::Store and result = this
|
||||
or
|
||||
op instanceof Opcode::AddOne and result = inc()
|
||||
or
|
||||
op instanceof Opcode::SubOne and result = dec()
|
||||
or
|
||||
op instanceof Opcode::Negate and result = neg()
|
||||
or
|
||||
op instanceof Opcode::BitComplement and result = bitnot()
|
||||
}
|
||||
|
||||
/** Perform `op` on this sign and sign `s`. */
|
||||
Sign applyBinaryOp(Sign s, Opcode op) {
|
||||
op instanceof Opcode::Add and result = add(s)
|
||||
or
|
||||
op instanceof Opcode::Sub and result = sub(s)
|
||||
or
|
||||
op instanceof Opcode::Mul and result = mul(s)
|
||||
or
|
||||
op instanceof Opcode::Div and result = div(s)
|
||||
or
|
||||
op instanceof Opcode::Rem and result = rem(s)
|
||||
or
|
||||
op instanceof Opcode::BitAnd and result = bitand(s)
|
||||
or
|
||||
op instanceof Opcode::BitOr and result = bitor(s)
|
||||
or
|
||||
op instanceof Opcode::BitXor and result = bitxor(s)
|
||||
or
|
||||
op instanceof Opcode::ShiftLeft and result = lshift(s)
|
||||
or
|
||||
op instanceof Opcode::ShiftRight and result = rshift(s)
|
||||
or
|
||||
op instanceof Opcode::ShiftRightUnsigned and result = urshift(s)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,493 @@
|
||||
/**
|
||||
* Provides sign analysis to determine whether expression are always positive
|
||||
* or negative.
|
||||
*
|
||||
* The analysis is implemented as an abstract interpretation over the
|
||||
* three-valued domain `{negative, zero, positive}`.
|
||||
*/
|
||||
|
||||
private import SignAnalysisSpecific as Specific
|
||||
private import experimental.semmle.code.cpp.semantic.Semantic
|
||||
private import ConstantAnalysis
|
||||
private import RangeUtils
|
||||
private import Sign
|
||||
|
||||
/**
|
||||
* An SSA definition for which the analysis can compute the sign.
|
||||
*
|
||||
* The actual computation of the sign is done in an override of the `getSign()` predicate. The
|
||||
* charpred of any subclass must _not_ invoke `getSign()`, directly or indirectly. This ensures
|
||||
* that the charpred does not introduce negative recursion. The `getSign()` predicate may be
|
||||
* recursive.
|
||||
*/
|
||||
abstract private class SignDef instanceof SemSsaVariable {
|
||||
final string toString() { result = super.toString() }
|
||||
|
||||
/** Gets the possible signs of this SSA definition. */
|
||||
abstract Sign getSign();
|
||||
}
|
||||
|
||||
/** An SSA definition whose sign is computed based on standard flow. */
|
||||
abstract private class FlowSignDef extends SignDef {
|
||||
abstract override Sign getSign();
|
||||
}
|
||||
|
||||
/** An SSA definition whose sign is determined by the sign of that definitions source expression. */
|
||||
private class ExplicitSignDef extends FlowSignDef {
|
||||
SemSsaExplicitUpdate update;
|
||||
|
||||
ExplicitSignDef() { update = this }
|
||||
|
||||
final override Sign getSign() { result = semExprSign(update.getSourceExpr()) }
|
||||
}
|
||||
|
||||
/** An SSA Phi definition, whose sign is the union of the signs of its inputs. */
|
||||
private class PhiSignDef extends FlowSignDef {
|
||||
SemSsaPhiNode phi;
|
||||
|
||||
PhiSignDef() { phi = this }
|
||||
|
||||
final override Sign getSign() {
|
||||
exists(SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge |
|
||||
edge.phiInput(phi, inp) and
|
||||
result = semSsaSign(inp, edge)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** An SSA definition whose sign is computed by a language-specific implementation. */
|
||||
abstract class CustomSignDef extends SignDef {
|
||||
abstract override Sign getSign();
|
||||
}
|
||||
|
||||
/**
|
||||
* An expression for which the analysis can compute the sign.
|
||||
*
|
||||
* The actual computation of the sign is done in an override of the `getSign()` predicate. The
|
||||
* charpred of any subclass must _not_ invoke `getSign()`, directly or indirectly. This ensures
|
||||
* that the charpred does not introduce negative recursion. The `getSign()` predicate may be
|
||||
* recursive.
|
||||
*
|
||||
* Concrete implementations extend one of the following subclasses:
|
||||
* - `ConstantSignExpr`, for expressions with a compile-time constant value.
|
||||
* - `FlowSignExpr`, for expressions whose sign can be computed from the signs of their operands.
|
||||
* - `CustomsignExpr`, for expressions shose sign can be computed by a language-specific
|
||||
* implementation.
|
||||
*
|
||||
* If the same expression matches more than one of the above subclasses, the sign is computed as
|
||||
* follows:
|
||||
* - The sign of a `ConstantSignExpr` is computed solely from `ConstantSignExpr.getSign()`,
|
||||
* regardless of any other subclasses.
|
||||
* - If a non-`ConstantSignExpr` expression matches exactly one of `FlowSignExpr` or
|
||||
* `CustomSignExpr`, the sign is computed by that class' `getSign()` predicate.
|
||||
* - If a non-`ConstantSignExpr` expression matches both `FlowSignExpr` and `CustomSignExpr`, the
|
||||
* sign is the _intersection_ of the signs of those two classes' `getSign()` predicates. Thus,
|
||||
* both classes have the opportunity to _restrict_ the set of possible signs, not to generate new
|
||||
* possible signs.
|
||||
* - If an expression does not match any of the three subclasses, then it can have any sign.
|
||||
*
|
||||
* Note that the `getSign()` predicate is introduced only in subclasses of `SignExpr`.
|
||||
*/
|
||||
abstract class SignExpr instanceof SemExpr {
|
||||
SignExpr() { not Specific::ignoreExprSign(this) }
|
||||
|
||||
final string toString() { result = super.toString() }
|
||||
|
||||
abstract Sign getSign();
|
||||
}
|
||||
|
||||
/** An expression whose sign is determined by its constant numeric value. */
|
||||
private class ConstantSignExpr extends SignExpr {
|
||||
ConstantSignExpr() {
|
||||
this instanceof SemConstantIntegerExpr or
|
||||
exists(this.(SemNumericLiteralExpr).getApproximateFloatValue())
|
||||
}
|
||||
|
||||
final override Sign getSign() {
|
||||
exists(int i | this.(SemConstantIntegerExpr).getIntValue() = i |
|
||||
i < 0 and result = TNeg()
|
||||
or
|
||||
i = 0 and result = TZero()
|
||||
or
|
||||
i > 0 and result = TPos()
|
||||
)
|
||||
or
|
||||
not exists(this.(SemConstantIntegerExpr).getIntValue()) and
|
||||
exists(float f | f = this.(SemNumericLiteralExpr).getApproximateFloatValue() |
|
||||
f < 0 and result = TNeg()
|
||||
or
|
||||
f = 0 and result = TZero()
|
||||
or
|
||||
f > 0 and result = TPos()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
abstract private class NonConstantSignExpr extends SignExpr {
|
||||
NonConstantSignExpr() { not this instanceof ConstantSignExpr }
|
||||
|
||||
final override Sign getSign() {
|
||||
// The result is the _intersection_ of the signs computed from flow and by the language.
|
||||
(result = this.(FlowSignExpr).getSignRestriction() or not this instanceof FlowSignExpr) and
|
||||
(result = this.(CustomSignExpr).getSignRestriction() or not this instanceof CustomSignExpr)
|
||||
}
|
||||
}
|
||||
|
||||
/** An expression whose sign is computed from the signs of its operands. */
|
||||
abstract private class FlowSignExpr extends NonConstantSignExpr {
|
||||
abstract Sign getSignRestriction();
|
||||
}
|
||||
|
||||
/** An expression whose sign is computed by a language-specific implementation. */
|
||||
abstract class CustomSignExpr extends NonConstantSignExpr {
|
||||
abstract Sign getSignRestriction();
|
||||
}
|
||||
|
||||
/** An expression whose sign is unknown. */
|
||||
private class UnknownSignExpr extends SignExpr {
|
||||
UnknownSignExpr() {
|
||||
not this instanceof FlowSignExpr and
|
||||
not this instanceof CustomSignExpr and
|
||||
not this instanceof ConstantSignExpr and
|
||||
(
|
||||
// Only track numeric types.
|
||||
getTrackedType(this) instanceof SemNumericType
|
||||
or
|
||||
// Unless the language says to track this expression anyway.
|
||||
Specific::trackUnknownNonNumericExpr(this)
|
||||
)
|
||||
}
|
||||
|
||||
final override Sign getSign() { semAnySign(result) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A `Load` expression whose sign is computed from the sign of its SSA definition, restricted by
|
||||
* inference from any intervening guards.
|
||||
*/
|
||||
class UseSignExpr extends FlowSignExpr {
|
||||
SemSsaVariable v;
|
||||
|
||||
UseSignExpr() { v.getAUse() = this }
|
||||
|
||||
override Sign getSignRestriction() {
|
||||
// Propagate via SSA
|
||||
// Propagate the sign from the def of `v`, incorporating any inference from guards.
|
||||
result = semSsaSign(v, any(SemSsaReadPositionBlock bb | bb.getAnExpr() = this))
|
||||
or
|
||||
// No block for this read. Just use the sign of the def.
|
||||
// REVIEW: How can this happen?
|
||||
not exists(SemSsaReadPositionBlock bb | bb.getAnExpr() = this) and
|
||||
result = semSsaDefSign(v)
|
||||
}
|
||||
}
|
||||
|
||||
/** A binary expression whose sign is computed from the signs of its operands. */
|
||||
private class BinarySignExpr extends FlowSignExpr {
|
||||
SemBinaryExpr binary;
|
||||
|
||||
BinarySignExpr() { binary = this }
|
||||
|
||||
override Sign getSignRestriction() {
|
||||
result =
|
||||
semExprSign(binary.getLeftOperand())
|
||||
.applyBinaryOp(semExprSign(binary.getRightOperand()), binary.getOpcode())
|
||||
or
|
||||
exists(SemDivExpr div | div = binary |
|
||||
result = semExprSign(div.getLeftOperand()) and
|
||||
result != TZero() and
|
||||
div.getRightOperand().(SemFloatingPointLiteralExpr).getFloatValue() = 0
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A `Convert`, `Box`, or `Unbox` expression.
|
||||
*/
|
||||
private class SemCastExpr extends SemUnaryExpr {
|
||||
SemCastExpr() {
|
||||
this instanceof SemConvertExpr
|
||||
or
|
||||
this instanceof SemBoxExpr
|
||||
or
|
||||
this instanceof SemUnboxExpr
|
||||
}
|
||||
}
|
||||
|
||||
/** A unary expression whose sign is computed from the sign of its operand. */
|
||||
private class UnarySignExpr extends FlowSignExpr {
|
||||
SemUnaryExpr unary;
|
||||
|
||||
UnarySignExpr() { unary = this and not this instanceof SemCastExpr }
|
||||
|
||||
override Sign getSignRestriction() {
|
||||
result = semExprSign(unary.getOperand()).applyUnaryOp(unary.getOpcode())
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A `Convert`, `Box`, or `Unbox` expression, whose sign is computed based on
|
||||
* the sign of its operand and the source and destination types.
|
||||
*/
|
||||
abstract private class CastSignExpr extends FlowSignExpr {
|
||||
SemUnaryExpr cast;
|
||||
|
||||
CastSignExpr() { cast = this and cast instanceof SemCastExpr }
|
||||
|
||||
override Sign getSignRestriction() { result = semExprSign(cast.getOperand()) }
|
||||
}
|
||||
|
||||
/**
|
||||
* A `Convert` expression.
|
||||
*/
|
||||
private class ConvertSignExpr extends CastSignExpr {
|
||||
override SemConvertExpr cast;
|
||||
}
|
||||
|
||||
/**
|
||||
* A `Box` expression.
|
||||
*/
|
||||
private class BoxSignExpr extends CastSignExpr {
|
||||
override SemBoxExpr cast;
|
||||
}
|
||||
|
||||
/**
|
||||
* An `Unbox` expression.
|
||||
*/
|
||||
private class UnboxSignExpr extends CastSignExpr {
|
||||
override SemUnboxExpr cast;
|
||||
|
||||
UnboxSignExpr() {
|
||||
exists(SemType fromType | fromType = getTrackedType(cast.getOperand()) |
|
||||
// Only numeric source types are handled here.
|
||||
fromType instanceof SemNumericType
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private predicate unknownSign(SemExpr e) { e instanceof UnknownSignExpr }
|
||||
|
||||
/**
|
||||
* Holds if `lowerbound` is a lower bound for `v` at `pos`. This is restricted
|
||||
* to only include bounds for which we might determine a sign.
|
||||
*/
|
||||
private predicate lowerBound(
|
||||
SemExpr lowerbound, SemSsaVariable v, SemSsaReadPosition pos, boolean isStrict
|
||||
) {
|
||||
exists(boolean testIsTrue, SemRelationalExpr comp |
|
||||
pos.hasReadOfVar(v) and
|
||||
semGuardControlsSsaRead(semGetComparisonGuard(comp), pos, testIsTrue) and
|
||||
not unknownSign(lowerbound)
|
||||
|
|
||||
testIsTrue = true and
|
||||
comp.getLesserOperand() = lowerbound and
|
||||
comp.getGreaterOperand() = semSsaRead(v, 0) and
|
||||
(if comp.isStrict() then isStrict = true else isStrict = false)
|
||||
or
|
||||
testIsTrue = false and
|
||||
comp.getGreaterOperand() = lowerbound and
|
||||
comp.getLesserOperand() = semSsaRead(v, 0) and
|
||||
(if comp.isStrict() then isStrict = false else isStrict = true)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `upperbound` is an upper bound for `v` at `pos`. This is restricted
|
||||
* to only include bounds for which we might determine a sign.
|
||||
*/
|
||||
private predicate upperBound(
|
||||
SemExpr upperbound, SemSsaVariable v, SemSsaReadPosition pos, boolean isStrict
|
||||
) {
|
||||
exists(boolean testIsTrue, SemRelationalExpr comp |
|
||||
pos.hasReadOfVar(v) and
|
||||
semGuardControlsSsaRead(semGetComparisonGuard(comp), pos, testIsTrue) and
|
||||
not unknownSign(upperbound)
|
||||
|
|
||||
testIsTrue = true and
|
||||
comp.getGreaterOperand() = upperbound and
|
||||
comp.getLesserOperand() = semSsaRead(v, 0) and
|
||||
(if comp.isStrict() then isStrict = true else isStrict = false)
|
||||
or
|
||||
testIsTrue = false and
|
||||
comp.getLesserOperand() = upperbound and
|
||||
comp.getGreaterOperand() = semSsaRead(v, 0) and
|
||||
(if comp.isStrict() then isStrict = false else isStrict = true)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `eqbound` is an equality/inequality for `v` at `pos`. This is
|
||||
* restricted to only include bounds for which we might determine a sign. The
|
||||
* boolean `isEq` gives the polarity:
|
||||
* - `isEq = true` : `v = eqbound`
|
||||
* - `isEq = false` : `v != eqbound`
|
||||
*/
|
||||
private predicate eqBound(SemExpr eqbound, SemSsaVariable v, SemSsaReadPosition pos, boolean isEq) {
|
||||
exists(SemGuard guard, boolean testIsTrue, boolean polarity |
|
||||
pos.hasReadOfVar(v) and
|
||||
semGuardControlsSsaRead(guard, pos, testIsTrue) and
|
||||
guard.isEquality(eqbound, semSsaRead(v, 0), polarity) and
|
||||
isEq = polarity.booleanXor(testIsTrue).booleanNot() and
|
||||
not unknownSign(eqbound)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `bound` is a bound for `v` at `pos` that needs to be positive in
|
||||
* order for `v` to be positive.
|
||||
*/
|
||||
private predicate posBound(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) {
|
||||
upperBound(bound, v, pos, _) or
|
||||
eqBound(bound, v, pos, true)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `bound` is a bound for `v` at `pos` that needs to be negative in
|
||||
* order for `v` to be negative.
|
||||
*/
|
||||
private predicate negBound(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) {
|
||||
lowerBound(bound, v, pos, _) or
|
||||
eqBound(bound, v, pos, true)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `bound` is a bound for `v` at `pos` that can restrict whether `v`
|
||||
* can be zero.
|
||||
*/
|
||||
private predicate zeroBound(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) {
|
||||
lowerBound(bound, v, pos, _) or
|
||||
upperBound(bound, v, pos, _) or
|
||||
eqBound(bound, v, pos, _)
|
||||
}
|
||||
|
||||
/** Holds if `bound` allows `v` to be positive at `pos`. */
|
||||
private predicate posBoundOk(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) {
|
||||
posBound(bound, v, pos) and TPos() = semExprSign(bound)
|
||||
}
|
||||
|
||||
/** Holds if `bound` allows `v` to be negative at `pos`. */
|
||||
private predicate negBoundOk(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) {
|
||||
negBound(bound, v, pos) and TNeg() = semExprSign(bound)
|
||||
}
|
||||
|
||||
/** Holds if `bound` allows `v` to be zero at `pos`. */
|
||||
private predicate zeroBoundOk(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) {
|
||||
lowerBound(bound, v, pos, _) and TNeg() = semExprSign(bound)
|
||||
or
|
||||
lowerBound(bound, v, pos, false) and TZero() = semExprSign(bound)
|
||||
or
|
||||
upperBound(bound, v, pos, _) and TPos() = semExprSign(bound)
|
||||
or
|
||||
upperBound(bound, v, pos, false) and TZero() = semExprSign(bound)
|
||||
or
|
||||
eqBound(bound, v, pos, true) and TZero() = semExprSign(bound)
|
||||
or
|
||||
eqBound(bound, v, pos, false) and TZero() != semExprSign(bound)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there is a bound that might restrict whether `v` has the sign `s`
|
||||
* at `pos`.
|
||||
*/
|
||||
private predicate hasGuard(SemSsaVariable v, SemSsaReadPosition pos, Sign s) {
|
||||
s = TPos() and posBound(_, v, pos)
|
||||
or
|
||||
s = TNeg() and negBound(_, v, pos)
|
||||
or
|
||||
s = TZero() and zeroBound(_, v, pos)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a possible sign of `v` at `pos` based on its definition, where the sign
|
||||
* might be ruled out by a guard.
|
||||
*/
|
||||
pragma[noinline]
|
||||
private Sign guardedSsaSign(SemSsaVariable v, SemSsaReadPosition pos) {
|
||||
result = semSsaDefSign(v) and
|
||||
pos.hasReadOfVar(v) and
|
||||
hasGuard(v, pos, result)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a possible sign of `v` at `pos` based on its definition, where no guard
|
||||
* can rule it out.
|
||||
*/
|
||||
pragma[noinline]
|
||||
private Sign unguardedSsaSign(SemSsaVariable v, SemSsaReadPosition pos) {
|
||||
result = semSsaDefSign(v) and
|
||||
pos.hasReadOfVar(v) and
|
||||
not hasGuard(v, pos, result)
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a possible sign of `v` at read position `pos`, where a guard could have
|
||||
* ruled out the sign but does not.
|
||||
* This does not check that the definition of `v` also allows the sign.
|
||||
*/
|
||||
private Sign guardedSsaSignOk(SemSsaVariable v, SemSsaReadPosition pos) {
|
||||
result = TPos() and
|
||||
forex(SemExpr bound | posBound(bound, v, pos) | posBoundOk(bound, v, pos))
|
||||
or
|
||||
result = TNeg() and
|
||||
forex(SemExpr bound | negBound(bound, v, pos) | negBoundOk(bound, v, pos))
|
||||
or
|
||||
result = TZero() and
|
||||
forex(SemExpr bound | zeroBound(bound, v, pos) | zeroBoundOk(bound, v, pos))
|
||||
}
|
||||
|
||||
/** Gets a possible sign for `v` at `pos`. */
|
||||
private Sign semSsaSign(SemSsaVariable v, SemSsaReadPosition pos) {
|
||||
result = unguardedSsaSign(v, pos)
|
||||
or
|
||||
result = guardedSsaSign(v, pos) and
|
||||
result = guardedSsaSignOk(v, pos)
|
||||
}
|
||||
|
||||
/** Gets a possible sign for `v`. */
|
||||
pragma[nomagic]
|
||||
Sign semSsaDefSign(SemSsaVariable v) { result = v.(SignDef).getSign() }
|
||||
|
||||
/** Gets a possible sign for `e`. */
|
||||
cached
|
||||
Sign semExprSign(SemExpr e) {
|
||||
exists(Sign s | s = e.(SignExpr).getSign() |
|
||||
if
|
||||
getTrackedType(e) instanceof SemUnsignedIntegerType and
|
||||
s = TNeg() and
|
||||
not Specific::ignoreTypeRestrictions(e)
|
||||
then result = TPos()
|
||||
else result = s
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Dummy predicate that holds for any sign. This is added to improve readability
|
||||
* of cases where the sign is unrestricted.
|
||||
*/
|
||||
predicate semAnySign(Sign s) { any() }
|
||||
|
||||
/** Holds if `e` can be positive and cannot be negative. */
|
||||
predicate semPositive(SemExpr e) {
|
||||
semExprSign(e) = TPos() and
|
||||
not semExprSign(e) = TNeg()
|
||||
}
|
||||
|
||||
/** Holds if `e` can be negative and cannot be positive. */
|
||||
predicate semNegative(SemExpr e) {
|
||||
semExprSign(e) = TNeg() and
|
||||
not semExprSign(e) = TPos()
|
||||
}
|
||||
|
||||
/** Holds if `e` is strictly positive. */
|
||||
predicate semStrictlyPositive(SemExpr e) {
|
||||
semExprSign(e) = TPos() and
|
||||
not semExprSign(e) = TNeg() and
|
||||
not semExprSign(e) = TZero()
|
||||
}
|
||||
|
||||
/** Holds if `e` is strictly negative. */
|
||||
predicate semStrictlyNegative(SemExpr e) {
|
||||
semExprSign(e) = TNeg() and
|
||||
not semExprSign(e) = TPos() and
|
||||
not semExprSign(e) = TZero()
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* Provides C++-specific definitions for use in sign analysis.
|
||||
*/
|
||||
|
||||
private import experimental.semmle.code.cpp.semantic.Semantic
|
||||
|
||||
/**
|
||||
* Workaround to allow certain expressions to have a negative sign, even if the type of the
|
||||
* expression is unsigned.
|
||||
*/
|
||||
predicate ignoreTypeRestrictions(SemExpr e) { none() }
|
||||
|
||||
/**
|
||||
* Workaround to track the sign of cetain expressions even if the type of the expression is not
|
||||
* numeric.
|
||||
*/
|
||||
predicate trackUnknownNonNumericExpr(SemExpr e) { none() }
|
||||
|
||||
/**
|
||||
* Workaround to ignore tracking of certain expressions even if the type of the expression is
|
||||
* numeric.
|
||||
*/
|
||||
predicate ignoreExprSign(SemExpr e) { none() }
|
||||
@@ -73,8 +73,24 @@ class Location extends @location {
|
||||
|
||||
/** Holds if `this` comes on a line strictly before `l`. */
|
||||
pragma[inline]
|
||||
predicate isBefore(Location l) {
|
||||
this.getFile() = l.getFile() and this.getEndLine() < l.getStartLine()
|
||||
predicate isBefore(Location l) { this.isBefore(l, false) }
|
||||
|
||||
/**
|
||||
* Holds if `this` comes strictly before `l`. The boolean `sameLine` is
|
||||
* true if `l` is on the same line as `this`, but starts at a later column.
|
||||
* Otherwise, `sameLine` is false.
|
||||
*/
|
||||
pragma[inline]
|
||||
predicate isBefore(Location l, boolean sameLine) {
|
||||
this.getFile() = l.getFile() and
|
||||
(
|
||||
sameLine = false and
|
||||
this.getEndLine() < l.getStartLine()
|
||||
or
|
||||
sameLine = true and
|
||||
this.getEndLine() = l.getStartLine() and
|
||||
this.getEndColumn() < l.getStartColumn()
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if location `l` is completely contained within this one. */
|
||||
|
||||
@@ -94,6 +94,7 @@ class Type extends Locatable, @type {
|
||||
* The result of this predicate will be the type itself, except in the case of a TypedefType or a Decltype,
|
||||
* in which case the result will be type which results from (possibly recursively) resolving typedefs.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
Type getUnderlyingType() { result = this }
|
||||
|
||||
/**
|
||||
|
||||
@@ -112,15 +112,13 @@ abstract class Configuration extends string {
|
||||
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the additional flow step from `node1` to `node2` must be taken
|
||||
* into account in the analysis.
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
*/
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the additional flow step from `node1` to `node2` must be taken
|
||||
* into account in the analysis. This step is only applicable in `state1` and
|
||||
* updates the flow state to `state2`.
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
||||
*/
|
||||
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {
|
||||
none()
|
||||
@@ -1160,8 +1158,8 @@ private module Stage2 {
|
||||
if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone()
|
||||
}
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() }
|
||||
bindingset[node, cc]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc) { any() }
|
||||
|
||||
bindingset[node1, state1, config]
|
||||
bindingset[node2, state2, config]
|
||||
@@ -1248,7 +1246,7 @@ private module Stage2 {
|
||||
or
|
||||
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
|
||||
fwdFlow(mid, state0, cc, argAp, ap0, config) and
|
||||
localCc = getLocalCc(mid, cc, config)
|
||||
localCc = getLocalCc(mid, cc)
|
||||
|
|
||||
localStep(mid, state0, node, state, true, _, config, localCc) and
|
||||
ap = ap0
|
||||
@@ -1953,8 +1951,8 @@ private module Stage3 {
|
||||
bindingset[call, c, innercc]
|
||||
private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() }
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() }
|
||||
bindingset[node, cc]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc) { any() }
|
||||
|
||||
private predicate localStep(
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||
@@ -2037,7 +2035,7 @@ private module Stage3 {
|
||||
or
|
||||
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
|
||||
fwdFlow(mid, state0, cc, argAp, ap0, config) and
|
||||
localCc = getLocalCc(mid, cc, config)
|
||||
localCc = getLocalCc(mid, cc)
|
||||
|
|
||||
localStep(mid, state0, node, state, true, _, config, localCc) and
|
||||
ap = ap0
|
||||
@@ -2767,12 +2765,11 @@ private module Stage4 {
|
||||
if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone()
|
||||
}
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
|
||||
bindingset[node, cc]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc) {
|
||||
result =
|
||||
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
|
||||
node.getEnclosingCallable()) and
|
||||
exists(config)
|
||||
node.getEnclosingCallable())
|
||||
}
|
||||
|
||||
private predicate localStep(
|
||||
@@ -2865,7 +2862,7 @@ private module Stage4 {
|
||||
or
|
||||
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
|
||||
fwdFlow(mid, state0, cc, argAp, ap0, config) and
|
||||
localCc = getLocalCc(mid, cc, config)
|
||||
localCc = getLocalCc(mid, cc)
|
||||
|
|
||||
localStep(mid, state0, node, state, true, _, config, localCc) and
|
||||
ap = ap0
|
||||
|
||||
@@ -112,15 +112,13 @@ abstract class Configuration extends string {
|
||||
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the additional flow step from `node1` to `node2` must be taken
|
||||
* into account in the analysis.
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
*/
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the additional flow step from `node1` to `node2` must be taken
|
||||
* into account in the analysis. This step is only applicable in `state1` and
|
||||
* updates the flow state to `state2`.
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
||||
*/
|
||||
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {
|
||||
none()
|
||||
@@ -1160,8 +1158,8 @@ private module Stage2 {
|
||||
if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone()
|
||||
}
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() }
|
||||
bindingset[node, cc]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc) { any() }
|
||||
|
||||
bindingset[node1, state1, config]
|
||||
bindingset[node2, state2, config]
|
||||
@@ -1248,7 +1246,7 @@ private module Stage2 {
|
||||
or
|
||||
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
|
||||
fwdFlow(mid, state0, cc, argAp, ap0, config) and
|
||||
localCc = getLocalCc(mid, cc, config)
|
||||
localCc = getLocalCc(mid, cc)
|
||||
|
|
||||
localStep(mid, state0, node, state, true, _, config, localCc) and
|
||||
ap = ap0
|
||||
@@ -1953,8 +1951,8 @@ private module Stage3 {
|
||||
bindingset[call, c, innercc]
|
||||
private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() }
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() }
|
||||
bindingset[node, cc]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc) { any() }
|
||||
|
||||
private predicate localStep(
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||
@@ -2037,7 +2035,7 @@ private module Stage3 {
|
||||
or
|
||||
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
|
||||
fwdFlow(mid, state0, cc, argAp, ap0, config) and
|
||||
localCc = getLocalCc(mid, cc, config)
|
||||
localCc = getLocalCc(mid, cc)
|
||||
|
|
||||
localStep(mid, state0, node, state, true, _, config, localCc) and
|
||||
ap = ap0
|
||||
@@ -2767,12 +2765,11 @@ private module Stage4 {
|
||||
if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone()
|
||||
}
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
|
||||
bindingset[node, cc]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc) {
|
||||
result =
|
||||
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
|
||||
node.getEnclosingCallable()) and
|
||||
exists(config)
|
||||
node.getEnclosingCallable())
|
||||
}
|
||||
|
||||
private predicate localStep(
|
||||
@@ -2865,7 +2862,7 @@ private module Stage4 {
|
||||
or
|
||||
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
|
||||
fwdFlow(mid, state0, cc, argAp, ap0, config) and
|
||||
localCc = getLocalCc(mid, cc, config)
|
||||
localCc = getLocalCc(mid, cc)
|
||||
|
|
||||
localStep(mid, state0, node, state, true, _, config, localCc) and
|
||||
ap = ap0
|
||||
|
||||
@@ -112,15 +112,13 @@ abstract class Configuration extends string {
|
||||
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the additional flow step from `node1` to `node2` must be taken
|
||||
* into account in the analysis.
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
*/
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the additional flow step from `node1` to `node2` must be taken
|
||||
* into account in the analysis. This step is only applicable in `state1` and
|
||||
* updates the flow state to `state2`.
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
||||
*/
|
||||
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {
|
||||
none()
|
||||
@@ -1160,8 +1158,8 @@ private module Stage2 {
|
||||
if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone()
|
||||
}
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() }
|
||||
bindingset[node, cc]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc) { any() }
|
||||
|
||||
bindingset[node1, state1, config]
|
||||
bindingset[node2, state2, config]
|
||||
@@ -1248,7 +1246,7 @@ private module Stage2 {
|
||||
or
|
||||
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
|
||||
fwdFlow(mid, state0, cc, argAp, ap0, config) and
|
||||
localCc = getLocalCc(mid, cc, config)
|
||||
localCc = getLocalCc(mid, cc)
|
||||
|
|
||||
localStep(mid, state0, node, state, true, _, config, localCc) and
|
||||
ap = ap0
|
||||
@@ -1953,8 +1951,8 @@ private module Stage3 {
|
||||
bindingset[call, c, innercc]
|
||||
private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() }
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() }
|
||||
bindingset[node, cc]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc) { any() }
|
||||
|
||||
private predicate localStep(
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||
@@ -2037,7 +2035,7 @@ private module Stage3 {
|
||||
or
|
||||
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
|
||||
fwdFlow(mid, state0, cc, argAp, ap0, config) and
|
||||
localCc = getLocalCc(mid, cc, config)
|
||||
localCc = getLocalCc(mid, cc)
|
||||
|
|
||||
localStep(mid, state0, node, state, true, _, config, localCc) and
|
||||
ap = ap0
|
||||
@@ -2767,12 +2765,11 @@ private module Stage4 {
|
||||
if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone()
|
||||
}
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
|
||||
bindingset[node, cc]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc) {
|
||||
result =
|
||||
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
|
||||
node.getEnclosingCallable()) and
|
||||
exists(config)
|
||||
node.getEnclosingCallable())
|
||||
}
|
||||
|
||||
private predicate localStep(
|
||||
@@ -2865,7 +2862,7 @@ private module Stage4 {
|
||||
or
|
||||
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
|
||||
fwdFlow(mid, state0, cc, argAp, ap0, config) and
|
||||
localCc = getLocalCc(mid, cc, config)
|
||||
localCc = getLocalCc(mid, cc)
|
||||
|
|
||||
localStep(mid, state0, node, state, true, _, config, localCc) and
|
||||
ap = ap0
|
||||
|
||||
@@ -112,15 +112,13 @@ abstract class Configuration extends string {
|
||||
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the additional flow step from `node1` to `node2` must be taken
|
||||
* into account in the analysis.
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
*/
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the additional flow step from `node1` to `node2` must be taken
|
||||
* into account in the analysis. This step is only applicable in `state1` and
|
||||
* updates the flow state to `state2`.
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
||||
*/
|
||||
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {
|
||||
none()
|
||||
@@ -1160,8 +1158,8 @@ private module Stage2 {
|
||||
if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone()
|
||||
}
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() }
|
||||
bindingset[node, cc]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc) { any() }
|
||||
|
||||
bindingset[node1, state1, config]
|
||||
bindingset[node2, state2, config]
|
||||
@@ -1248,7 +1246,7 @@ private module Stage2 {
|
||||
or
|
||||
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
|
||||
fwdFlow(mid, state0, cc, argAp, ap0, config) and
|
||||
localCc = getLocalCc(mid, cc, config)
|
||||
localCc = getLocalCc(mid, cc)
|
||||
|
|
||||
localStep(mid, state0, node, state, true, _, config, localCc) and
|
||||
ap = ap0
|
||||
@@ -1953,8 +1951,8 @@ private module Stage3 {
|
||||
bindingset[call, c, innercc]
|
||||
private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() }
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() }
|
||||
bindingset[node, cc]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc) { any() }
|
||||
|
||||
private predicate localStep(
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||
@@ -2037,7 +2035,7 @@ private module Stage3 {
|
||||
or
|
||||
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
|
||||
fwdFlow(mid, state0, cc, argAp, ap0, config) and
|
||||
localCc = getLocalCc(mid, cc, config)
|
||||
localCc = getLocalCc(mid, cc)
|
||||
|
|
||||
localStep(mid, state0, node, state, true, _, config, localCc) and
|
||||
ap = ap0
|
||||
@@ -2767,12 +2765,11 @@ private module Stage4 {
|
||||
if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone()
|
||||
}
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
|
||||
bindingset[node, cc]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc) {
|
||||
result =
|
||||
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
|
||||
node.getEnclosingCallable()) and
|
||||
exists(config)
|
||||
node.getEnclosingCallable())
|
||||
}
|
||||
|
||||
private predicate localStep(
|
||||
@@ -2865,7 +2862,7 @@ private module Stage4 {
|
||||
or
|
||||
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
|
||||
fwdFlow(mid, state0, cc, argAp, ap0, config) and
|
||||
localCc = getLocalCc(mid, cc, config)
|
||||
localCc = getLocalCc(mid, cc)
|
||||
|
|
||||
localStep(mid, state0, node, state, true, _, config, localCc) and
|
||||
ap = ap0
|
||||
|
||||
@@ -112,15 +112,13 @@ abstract class Configuration extends string {
|
||||
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the additional flow step from `node1` to `node2` must be taken
|
||||
* into account in the analysis.
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
*/
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the additional flow step from `node1` to `node2` must be taken
|
||||
* into account in the analysis. This step is only applicable in `state1` and
|
||||
* updates the flow state to `state2`.
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
||||
*/
|
||||
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {
|
||||
none()
|
||||
@@ -1160,8 +1158,8 @@ private module Stage2 {
|
||||
if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone()
|
||||
}
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() }
|
||||
bindingset[node, cc]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc) { any() }
|
||||
|
||||
bindingset[node1, state1, config]
|
||||
bindingset[node2, state2, config]
|
||||
@@ -1248,7 +1246,7 @@ private module Stage2 {
|
||||
or
|
||||
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
|
||||
fwdFlow(mid, state0, cc, argAp, ap0, config) and
|
||||
localCc = getLocalCc(mid, cc, config)
|
||||
localCc = getLocalCc(mid, cc)
|
||||
|
|
||||
localStep(mid, state0, node, state, true, _, config, localCc) and
|
||||
ap = ap0
|
||||
@@ -1953,8 +1951,8 @@ private module Stage3 {
|
||||
bindingset[call, c, innercc]
|
||||
private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() }
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() }
|
||||
bindingset[node, cc]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc) { any() }
|
||||
|
||||
private predicate localStep(
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||
@@ -2037,7 +2035,7 @@ private module Stage3 {
|
||||
or
|
||||
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
|
||||
fwdFlow(mid, state0, cc, argAp, ap0, config) and
|
||||
localCc = getLocalCc(mid, cc, config)
|
||||
localCc = getLocalCc(mid, cc)
|
||||
|
|
||||
localStep(mid, state0, node, state, true, _, config, localCc) and
|
||||
ap = ap0
|
||||
@@ -2767,12 +2765,11 @@ private module Stage4 {
|
||||
if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone()
|
||||
}
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
|
||||
bindingset[node, cc]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc) {
|
||||
result =
|
||||
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
|
||||
node.getEnclosingCallable()) and
|
||||
exists(config)
|
||||
node.getEnclosingCallable())
|
||||
}
|
||||
|
||||
private predicate localStep(
|
||||
@@ -2865,7 +2862,7 @@ private module Stage4 {
|
||||
or
|
||||
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
|
||||
fwdFlow(mid, state0, cc, argAp, ap0, config) and
|
||||
localCc = getLocalCc(mid, cc, config)
|
||||
localCc = getLocalCc(mid, cc)
|
||||
|
|
||||
localStep(mid, state0, node, state, true, _, config, localCc) and
|
||||
ap = ap0
|
||||
|
||||
@@ -154,8 +154,7 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the additional taint propagation step from `node1` to `node2`
|
||||
* must be taken into account in the analysis.
|
||||
* Holds if taint may propagate from `node1` to `node2` in addition to the normal data-flow and taint steps.
|
||||
*/
|
||||
predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { none() }
|
||||
|
||||
@@ -165,9 +164,8 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the additional taint propagation step from `node1` to `node2`
|
||||
* must be taken into account in the analysis. This step is only applicable
|
||||
* in `state1` and updates the flow state to `state2`.
|
||||
* Holds if taint may propagate from `node1` to `node2` in addition to the normal data-flow and taint steps.
|
||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
||||
*/
|
||||
predicate isAdditionalTaintStep(
|
||||
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
|
||||
|
||||
@@ -154,8 +154,7 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the additional taint propagation step from `node1` to `node2`
|
||||
* must be taken into account in the analysis.
|
||||
* Holds if taint may propagate from `node1` to `node2` in addition to the normal data-flow and taint steps.
|
||||
*/
|
||||
predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { none() }
|
||||
|
||||
@@ -165,9 +164,8 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the additional taint propagation step from `node1` to `node2`
|
||||
* must be taken into account in the analysis. This step is only applicable
|
||||
* in `state1` and updates the flow state to `state2`.
|
||||
* Holds if taint may propagate from `node1` to `node2` in addition to the normal data-flow and taint steps.
|
||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
||||
*/
|
||||
predicate isAdditionalTaintStep(
|
||||
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
|
||||
|
||||
@@ -112,15 +112,13 @@ abstract class Configuration extends string {
|
||||
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the additional flow step from `node1` to `node2` must be taken
|
||||
* into account in the analysis.
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
*/
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the additional flow step from `node1` to `node2` must be taken
|
||||
* into account in the analysis. This step is only applicable in `state1` and
|
||||
* updates the flow state to `state2`.
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
||||
*/
|
||||
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {
|
||||
none()
|
||||
@@ -1160,8 +1158,8 @@ private module Stage2 {
|
||||
if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone()
|
||||
}
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() }
|
||||
bindingset[node, cc]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc) { any() }
|
||||
|
||||
bindingset[node1, state1, config]
|
||||
bindingset[node2, state2, config]
|
||||
@@ -1248,7 +1246,7 @@ private module Stage2 {
|
||||
or
|
||||
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
|
||||
fwdFlow(mid, state0, cc, argAp, ap0, config) and
|
||||
localCc = getLocalCc(mid, cc, config)
|
||||
localCc = getLocalCc(mid, cc)
|
||||
|
|
||||
localStep(mid, state0, node, state, true, _, config, localCc) and
|
||||
ap = ap0
|
||||
@@ -1953,8 +1951,8 @@ private module Stage3 {
|
||||
bindingset[call, c, innercc]
|
||||
private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() }
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() }
|
||||
bindingset[node, cc]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc) { any() }
|
||||
|
||||
private predicate localStep(
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||
@@ -2037,7 +2035,7 @@ private module Stage3 {
|
||||
or
|
||||
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
|
||||
fwdFlow(mid, state0, cc, argAp, ap0, config) and
|
||||
localCc = getLocalCc(mid, cc, config)
|
||||
localCc = getLocalCc(mid, cc)
|
||||
|
|
||||
localStep(mid, state0, node, state, true, _, config, localCc) and
|
||||
ap = ap0
|
||||
@@ -2767,12 +2765,11 @@ private module Stage4 {
|
||||
if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone()
|
||||
}
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
|
||||
bindingset[node, cc]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc) {
|
||||
result =
|
||||
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
|
||||
node.getEnclosingCallable()) and
|
||||
exists(config)
|
||||
node.getEnclosingCallable())
|
||||
}
|
||||
|
||||
private predicate localStep(
|
||||
@@ -2865,7 +2862,7 @@ private module Stage4 {
|
||||
or
|
||||
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
|
||||
fwdFlow(mid, state0, cc, argAp, ap0, config) and
|
||||
localCc = getLocalCc(mid, cc, config)
|
||||
localCc = getLocalCc(mid, cc)
|
||||
|
|
||||
localStep(mid, state0, node, state, true, _, config, localCc) and
|
||||
ap = ap0
|
||||
|
||||
@@ -112,15 +112,13 @@ abstract class Configuration extends string {
|
||||
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the additional flow step from `node1` to `node2` must be taken
|
||||
* into account in the analysis.
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
*/
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the additional flow step from `node1` to `node2` must be taken
|
||||
* into account in the analysis. This step is only applicable in `state1` and
|
||||
* updates the flow state to `state2`.
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
||||
*/
|
||||
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {
|
||||
none()
|
||||
@@ -1160,8 +1158,8 @@ private module Stage2 {
|
||||
if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone()
|
||||
}
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() }
|
||||
bindingset[node, cc]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc) { any() }
|
||||
|
||||
bindingset[node1, state1, config]
|
||||
bindingset[node2, state2, config]
|
||||
@@ -1248,7 +1246,7 @@ private module Stage2 {
|
||||
or
|
||||
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
|
||||
fwdFlow(mid, state0, cc, argAp, ap0, config) and
|
||||
localCc = getLocalCc(mid, cc, config)
|
||||
localCc = getLocalCc(mid, cc)
|
||||
|
|
||||
localStep(mid, state0, node, state, true, _, config, localCc) and
|
||||
ap = ap0
|
||||
@@ -1953,8 +1951,8 @@ private module Stage3 {
|
||||
bindingset[call, c, innercc]
|
||||
private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() }
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() }
|
||||
bindingset[node, cc]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc) { any() }
|
||||
|
||||
private predicate localStep(
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||
@@ -2037,7 +2035,7 @@ private module Stage3 {
|
||||
or
|
||||
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
|
||||
fwdFlow(mid, state0, cc, argAp, ap0, config) and
|
||||
localCc = getLocalCc(mid, cc, config)
|
||||
localCc = getLocalCc(mid, cc)
|
||||
|
|
||||
localStep(mid, state0, node, state, true, _, config, localCc) and
|
||||
ap = ap0
|
||||
@@ -2767,12 +2765,11 @@ private module Stage4 {
|
||||
if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone()
|
||||
}
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
|
||||
bindingset[node, cc]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc) {
|
||||
result =
|
||||
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
|
||||
node.getEnclosingCallable()) and
|
||||
exists(config)
|
||||
node.getEnclosingCallable())
|
||||
}
|
||||
|
||||
private predicate localStep(
|
||||
@@ -2865,7 +2862,7 @@ private module Stage4 {
|
||||
or
|
||||
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
|
||||
fwdFlow(mid, state0, cc, argAp, ap0, config) and
|
||||
localCc = getLocalCc(mid, cc, config)
|
||||
localCc = getLocalCc(mid, cc)
|
||||
|
|
||||
localStep(mid, state0, node, state, true, _, config, localCc) and
|
||||
ap = ap0
|
||||
|
||||
@@ -112,15 +112,13 @@ abstract class Configuration extends string {
|
||||
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the additional flow step from `node1` to `node2` must be taken
|
||||
* into account in the analysis.
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
*/
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the additional flow step from `node1` to `node2` must be taken
|
||||
* into account in the analysis. This step is only applicable in `state1` and
|
||||
* updates the flow state to `state2`.
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
||||
*/
|
||||
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {
|
||||
none()
|
||||
@@ -1160,8 +1158,8 @@ private module Stage2 {
|
||||
if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone()
|
||||
}
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() }
|
||||
bindingset[node, cc]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc) { any() }
|
||||
|
||||
bindingset[node1, state1, config]
|
||||
bindingset[node2, state2, config]
|
||||
@@ -1248,7 +1246,7 @@ private module Stage2 {
|
||||
or
|
||||
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
|
||||
fwdFlow(mid, state0, cc, argAp, ap0, config) and
|
||||
localCc = getLocalCc(mid, cc, config)
|
||||
localCc = getLocalCc(mid, cc)
|
||||
|
|
||||
localStep(mid, state0, node, state, true, _, config, localCc) and
|
||||
ap = ap0
|
||||
@@ -1953,8 +1951,8 @@ private module Stage3 {
|
||||
bindingset[call, c, innercc]
|
||||
private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() }
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() }
|
||||
bindingset[node, cc]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc) { any() }
|
||||
|
||||
private predicate localStep(
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||
@@ -2037,7 +2035,7 @@ private module Stage3 {
|
||||
or
|
||||
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
|
||||
fwdFlow(mid, state0, cc, argAp, ap0, config) and
|
||||
localCc = getLocalCc(mid, cc, config)
|
||||
localCc = getLocalCc(mid, cc)
|
||||
|
|
||||
localStep(mid, state0, node, state, true, _, config, localCc) and
|
||||
ap = ap0
|
||||
@@ -2767,12 +2765,11 @@ private module Stage4 {
|
||||
if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone()
|
||||
}
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
|
||||
bindingset[node, cc]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc) {
|
||||
result =
|
||||
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
|
||||
node.getEnclosingCallable()) and
|
||||
exists(config)
|
||||
node.getEnclosingCallable())
|
||||
}
|
||||
|
||||
private predicate localStep(
|
||||
@@ -2865,7 +2862,7 @@ private module Stage4 {
|
||||
or
|
||||
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
|
||||
fwdFlow(mid, state0, cc, argAp, ap0, config) and
|
||||
localCc = getLocalCc(mid, cc, config)
|
||||
localCc = getLocalCc(mid, cc)
|
||||
|
|
||||
localStep(mid, state0, node, state, true, _, config, localCc) and
|
||||
ap = ap0
|
||||
|
||||
@@ -112,15 +112,13 @@ abstract class Configuration extends string {
|
||||
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the additional flow step from `node1` to `node2` must be taken
|
||||
* into account in the analysis.
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
*/
|
||||
predicate isAdditionalFlowStep(Node node1, Node node2) { none() }
|
||||
|
||||
/**
|
||||
* Holds if the additional flow step from `node1` to `node2` must be taken
|
||||
* into account in the analysis. This step is only applicable in `state1` and
|
||||
* updates the flow state to `state2`.
|
||||
* Holds if data may flow from `node1` to `node2` in addition to the normal data-flow steps.
|
||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
||||
*/
|
||||
predicate isAdditionalFlowStep(Node node1, FlowState state1, Node node2, FlowState state2) {
|
||||
none()
|
||||
@@ -1160,8 +1158,8 @@ private module Stage2 {
|
||||
if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone()
|
||||
}
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() }
|
||||
bindingset[node, cc]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc) { any() }
|
||||
|
||||
bindingset[node1, state1, config]
|
||||
bindingset[node2, state2, config]
|
||||
@@ -1248,7 +1246,7 @@ private module Stage2 {
|
||||
or
|
||||
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
|
||||
fwdFlow(mid, state0, cc, argAp, ap0, config) and
|
||||
localCc = getLocalCc(mid, cc, config)
|
||||
localCc = getLocalCc(mid, cc)
|
||||
|
|
||||
localStep(mid, state0, node, state, true, _, config, localCc) and
|
||||
ap = ap0
|
||||
@@ -1953,8 +1951,8 @@ private module Stage3 {
|
||||
bindingset[call, c, innercc]
|
||||
private CcNoCall getCallContextReturn(DataFlowCallable c, DataFlowCall call, Cc innercc) { any() }
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) { any() }
|
||||
bindingset[node, cc]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc) { any() }
|
||||
|
||||
private predicate localStep(
|
||||
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
|
||||
@@ -2037,7 +2035,7 @@ private module Stage3 {
|
||||
or
|
||||
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
|
||||
fwdFlow(mid, state0, cc, argAp, ap0, config) and
|
||||
localCc = getLocalCc(mid, cc, config)
|
||||
localCc = getLocalCc(mid, cc)
|
||||
|
|
||||
localStep(mid, state0, node, state, true, _, config, localCc) and
|
||||
ap = ap0
|
||||
@@ -2767,12 +2765,11 @@ private module Stage4 {
|
||||
if reducedViableImplInReturn(c, call) then result = TReturn(c, call) else result = ccNone()
|
||||
}
|
||||
|
||||
bindingset[node, cc, config]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
|
||||
bindingset[node, cc]
|
||||
private LocalCc getLocalCc(NodeEx node, Cc cc) {
|
||||
result =
|
||||
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
|
||||
node.getEnclosingCallable()) and
|
||||
exists(config)
|
||||
node.getEnclosingCallable())
|
||||
}
|
||||
|
||||
private predicate localStep(
|
||||
@@ -2865,7 +2862,7 @@ private module Stage4 {
|
||||
or
|
||||
exists(NodeEx mid, FlowState state0, Ap ap0, LocalCc localCc |
|
||||
fwdFlow(mid, state0, cc, argAp, ap0, config) and
|
||||
localCc = getLocalCc(mid, cc, config)
|
||||
localCc = getLocalCc(mid, cc)
|
||||
|
|
||||
localStep(mid, state0, node, state, true, _, config, localCc) and
|
||||
ap = ap0
|
||||
|
||||
@@ -154,8 +154,7 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the additional taint propagation step from `node1` to `node2`
|
||||
* must be taken into account in the analysis.
|
||||
* Holds if taint may propagate from `node1` to `node2` in addition to the normal data-flow and taint steps.
|
||||
*/
|
||||
predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { none() }
|
||||
|
||||
@@ -165,9 +164,8 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the additional taint propagation step from `node1` to `node2`
|
||||
* must be taken into account in the analysis. This step is only applicable
|
||||
* in `state1` and updates the flow state to `state2`.
|
||||
* Holds if taint may propagate from `node1` to `node2` in addition to the normal data-flow and taint steps.
|
||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
||||
*/
|
||||
predicate isAdditionalTaintStep(
|
||||
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
|
||||
|
||||
@@ -154,8 +154,7 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the additional taint propagation step from `node1` to `node2`
|
||||
* must be taken into account in the analysis.
|
||||
* Holds if taint may propagate from `node1` to `node2` in addition to the normal data-flow and taint steps.
|
||||
*/
|
||||
predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { none() }
|
||||
|
||||
@@ -165,9 +164,8 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the additional taint propagation step from `node1` to `node2`
|
||||
* must be taken into account in the analysis. This step is only applicable
|
||||
* in `state1` and updates the flow state to `state2`.
|
||||
* Holds if taint may propagate from `node1` to `node2` in addition to the normal data-flow and taint steps.
|
||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
||||
*/
|
||||
predicate isAdditionalTaintStep(
|
||||
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
|
||||
|
||||
@@ -154,8 +154,7 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the additional taint propagation step from `node1` to `node2`
|
||||
* must be taken into account in the analysis.
|
||||
* Holds if taint may propagate from `node1` to `node2` in addition to the normal data-flow and taint steps.
|
||||
*/
|
||||
predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) { none() }
|
||||
|
||||
@@ -165,9 +164,8 @@ abstract class Configuration extends DataFlow::Configuration {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the additional taint propagation step from `node1` to `node2`
|
||||
* must be taken into account in the analysis. This step is only applicable
|
||||
* in `state1` and updates the flow state to `state2`.
|
||||
* Holds if taint may propagate from `node1` to `node2` in addition to the normal data-flow and taint steps.
|
||||
* This step is only applicable in `state1` and updates the flow state to `state2`.
|
||||
*/
|
||||
predicate isAdditionalTaintStep(
|
||||
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
|
||||
|
||||
@@ -161,8 +161,13 @@ class IRBlock extends IRBlockBase {
|
||||
*/
|
||||
pragma[noinline]
|
||||
final IRBlock dominanceFrontier() {
|
||||
this.dominates(result.getAPredecessor()) and
|
||||
not this.strictlyDominates(result)
|
||||
this.getASuccessor() = result and
|
||||
not this.immediatelyDominates(result)
|
||||
or
|
||||
exists(IRBlock prev | result = prev.dominanceFrontier() |
|
||||
this.immediatelyDominates(prev) and
|
||||
not this.immediatelyDominates(result)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -201,8 +206,13 @@ class IRBlock extends IRBlockBase {
|
||||
*/
|
||||
pragma[noinline]
|
||||
final IRBlock postDominanceFrontier() {
|
||||
this.postDominates(result.getASuccessor()) and
|
||||
not this.strictlyPostDominates(result)
|
||||
this.getAPredecessor() = result and
|
||||
not this.immediatelyPostDominates(result)
|
||||
or
|
||||
exists(IRBlock prev | result = prev.postDominanceFrontier() |
|
||||
this.immediatelyPostDominates(prev) and
|
||||
not this.immediatelyPostDominates(result)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -161,8 +161,13 @@ class IRBlock extends IRBlockBase {
|
||||
*/
|
||||
pragma[noinline]
|
||||
final IRBlock dominanceFrontier() {
|
||||
this.dominates(result.getAPredecessor()) and
|
||||
not this.strictlyDominates(result)
|
||||
this.getASuccessor() = result and
|
||||
not this.immediatelyDominates(result)
|
||||
or
|
||||
exists(IRBlock prev | result = prev.dominanceFrontier() |
|
||||
this.immediatelyDominates(prev) and
|
||||
not this.immediatelyDominates(result)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -201,8 +206,13 @@ class IRBlock extends IRBlockBase {
|
||||
*/
|
||||
pragma[noinline]
|
||||
final IRBlock postDominanceFrontier() {
|
||||
this.postDominates(result.getASuccessor()) and
|
||||
not this.strictlyPostDominates(result)
|
||||
this.getAPredecessor() = result and
|
||||
not this.immediatelyPostDominates(result)
|
||||
or
|
||||
exists(IRBlock prev | result = prev.postDominanceFrontier() |
|
||||
this.immediatelyPostDominates(prev) and
|
||||
not this.immediatelyPostDominates(result)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -349,7 +349,7 @@ Instruction getInstructionBackEdgeSuccessor(Instruction instruction, EdgeKind ki
|
||||
|
||||
/** Holds if `goto` jumps strictly forward in the program text. */
|
||||
private predicate isStrictlyForwardGoto(GotoStmt goto) {
|
||||
goto.getLocation().isBefore(goto.getTarget().getLocation())
|
||||
goto.getLocation().isBefore(goto.getTarget().getLocation(), _)
|
||||
}
|
||||
|
||||
Locatable getInstructionAst(TStageInstruction instr) {
|
||||
|
||||
@@ -154,13 +154,6 @@ private predicate ignoreSideEffects(Expr expr) {
|
||||
* around extractor bugs. Once the relevant extractor bugs are fixed, this predicate can be removed.
|
||||
*/
|
||||
private predicate isInvalidFunction(Function func) {
|
||||
exists(Literal literal |
|
||||
// Constructor field inits within a compiler-generated copy constructor have a source expression
|
||||
// that is a `Literal` with no value.
|
||||
literal = func.(Constructor).getAnInitializer().(ConstructorFieldInit).getExpr() and
|
||||
not exists(literal.getValue())
|
||||
)
|
||||
or
|
||||
exists(ThisExpr thisExpr |
|
||||
// An instantiation of a member function template is not treated as a `MemberFunction` if it has
|
||||
// only non-type template arguments.
|
||||
|
||||
@@ -161,8 +161,13 @@ class IRBlock extends IRBlockBase {
|
||||
*/
|
||||
pragma[noinline]
|
||||
final IRBlock dominanceFrontier() {
|
||||
this.dominates(result.getAPredecessor()) and
|
||||
not this.strictlyDominates(result)
|
||||
this.getASuccessor() = result and
|
||||
not this.immediatelyDominates(result)
|
||||
or
|
||||
exists(IRBlock prev | result = prev.dominanceFrontier() |
|
||||
this.immediatelyDominates(prev) and
|
||||
not this.immediatelyDominates(result)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -201,8 +206,13 @@ class IRBlock extends IRBlockBase {
|
||||
*/
|
||||
pragma[noinline]
|
||||
final IRBlock postDominanceFrontier() {
|
||||
this.postDominates(result.getASuccessor()) and
|
||||
not this.strictlyPostDominates(result)
|
||||
this.getAPredecessor() = result and
|
||||
not this.immediatelyPostDominates(result)
|
||||
or
|
||||
exists(IRBlock prev | result = prev.postDominanceFrontier() |
|
||||
this.immediatelyPostDominates(prev) and
|
||||
not this.immediatelyPostDominates(result)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -92,6 +92,7 @@ abstract class FormattingFunction extends ArrayFunction, TaintFunction {
|
||||
* snapshots there may be multiple results where we can't tell which is correct for a
|
||||
* particular function.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
Type getWideCharType() {
|
||||
result = getFormatCharType() and
|
||||
result.getSize() > 1
|
||||
|
||||
71
cpp/ql/lib/semmle/code/cpp/security/PrivateData.qll
Normal file
71
cpp/ql/lib/semmle/code/cpp/security/PrivateData.qll
Normal file
@@ -0,0 +1,71 @@
|
||||
/**
|
||||
* Provides classes for heuristically identifying variables and functions that
|
||||
* might contain or return sensitive private data.
|
||||
*
|
||||
* 'Private' data in general is anything that would compromise user privacy if
|
||||
* exposed. This library tries to guess where private data may either be stored
|
||||
* in a variable or returned by a function call.
|
||||
*
|
||||
* This library is not concerned with credentials. See `SensitiveExprs.qll` for
|
||||
* expressions related to credentials.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
/**
|
||||
* A string for `regexpMatch` that identifies strings that look like they
|
||||
* represent private data.
|
||||
*/
|
||||
private string privateNames() {
|
||||
result =
|
||||
".*(" +
|
||||
// Inspired by the list on https://cwe.mitre.org/data/definitions/359.html
|
||||
// Government identifiers, such as Social Security Numbers
|
||||
"social.?security|national.?insurance|" +
|
||||
// Contact information, such as home addresses
|
||||
"post.?code|zip.?code|home.?address|" +
|
||||
// and telephone numbers
|
||||
"telephone|home.?phone|mobile|fax.?no|fax.?number|" +
|
||||
// Geographic location - where the user is (or was)
|
||||
"latitude|longitude|" +
|
||||
// Financial data - such as credit card numbers, salary, bank accounts, and debts
|
||||
"credit.?card|debit.?card|salary|bank.?account|" +
|
||||
// Communications - e-mail addresses, private e-mail messages, SMS text messages, chat logs, etc.
|
||||
"email|" +
|
||||
// Health - medical conditions, insurance status, prescription records
|
||||
"birthday|birth.?date|date.?of.?birth|medical|" +
|
||||
// Relationships - work and family
|
||||
"employer|spouse" +
|
||||
// ---
|
||||
").*"
|
||||
}
|
||||
|
||||
/**
|
||||
* A variable that might contain sensitive private information.
|
||||
*/
|
||||
class PrivateDataVariable extends Variable {
|
||||
PrivateDataVariable() {
|
||||
this.getName().toLowerCase().regexpMatch(privateNames()) and
|
||||
not this.getUnspecifiedType() instanceof IntegralType
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A function that might return sensitive private information.
|
||||
*/
|
||||
class PrivateDataFunction extends Function {
|
||||
PrivateDataFunction() {
|
||||
this.getName().toLowerCase().regexpMatch(privateNames()) and
|
||||
not this.getUnspecifiedType() instanceof IntegralType
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An expression whose value might be sensitive private information.
|
||||
*/
|
||||
class PrivateDataExpr extends Expr {
|
||||
PrivateDataExpr() {
|
||||
this.(VariableAccess).getTarget() instanceof PrivateDataVariable or
|
||||
this.(FunctionCall).getTarget() instanceof PrivateDataFunction
|
||||
}
|
||||
}
|
||||
@@ -1,22 +1,25 @@
|
||||
/**
|
||||
* Provides classes for heuristically identifying variables and functions that
|
||||
* might contain or return a password or other sensitive information.
|
||||
* might contain or return a password or other credential.
|
||||
*
|
||||
* This library is not concerned with other kinds of sensitive private
|
||||
* information. See `PrivateData.qll` for expressions related to that.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
/**
|
||||
* Holds if the name `s` suggests something might contain or return a password
|
||||
* or other sensitive information.
|
||||
* or other credential.
|
||||
*/
|
||||
bindingset[s]
|
||||
private predicate suspicious(string s) {
|
||||
s.matches(["%password%", "%passwd%", "%trusted%"]) and
|
||||
not s.matches(["%hash%", "%crypt%", "%file%", "%path%"])
|
||||
s.regexpMatch(".*(password|passwd|accountid|account.?key|accnt.?key|license.?key|trusted).*") and
|
||||
not s.matches(["%hash%", "%crypt%", "%file%", "%path%", "%invalid%"])
|
||||
}
|
||||
|
||||
/**
|
||||
* A variable that might contain a password or other sensitive information.
|
||||
* A variable that might contain a password or other credential.
|
||||
*/
|
||||
class SensitiveVariable extends Variable {
|
||||
SensitiveVariable() {
|
||||
@@ -26,7 +29,7 @@ class SensitiveVariable extends Variable {
|
||||
}
|
||||
|
||||
/**
|
||||
* A function that might return a password or other sensitive information.
|
||||
* A function that might return a password or other credential.
|
||||
*/
|
||||
class SensitiveFunction extends Function {
|
||||
SensitiveFunction() {
|
||||
@@ -36,7 +39,7 @@ class SensitiveFunction extends Function {
|
||||
}
|
||||
|
||||
/**
|
||||
* An expression whose value might be a password or other sensitive information.
|
||||
* An expression whose value might be a password or other credential.
|
||||
*/
|
||||
class SensitiveExpr extends Expr {
|
||||
SensitiveExpr() {
|
||||
|
||||
@@ -58,11 +58,5 @@ where
|
||||
not exists(AsmStmt s | f = s.getEnclosingFunction()) and
|
||||
not v.getAnAttribute().getName() = "unused" and
|
||||
not any(ErrorExpr e).getEnclosingFunction() = f and // unextracted expr may use `v`
|
||||
not exists(
|
||||
Literal l // this case can be removed when the `myFunction2( [obj](){} );` test case doesn't depend on this exclusion
|
||||
|
|
||||
l.getEnclosingFunction() = f and
|
||||
not exists(l.getValue())
|
||||
) and
|
||||
not any(ConditionDeclExpr cde).getEnclosingFunction() = f // this case can be removed when the `if (a = b; a)` test case doesn't depend on this exclusion
|
||||
not any(ConditionDeclExpr cde).getEnclosingFunction() = f // this case can be removed when the `if (a = b; a)` and `switch (a = b; a)` test cases don't depend on this exclusion
|
||||
select v, "Variable " + v.getName() + " is not used"
|
||||
|
||||
21
cpp/ql/src/Diagnostics/Internal/ExtractionErrors.ql
Normal file
21
cpp/ql/src/Diagnostics/Internal/ExtractionErrors.ql
Normal file
@@ -0,0 +1,21 @@
|
||||
/**
|
||||
* @name Extraction errors
|
||||
* @description List all extraction errors for files in the source code directory.
|
||||
* @kind diagnostic
|
||||
* @id cpp/diagnostics/extraction-errors
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import ExtractionErrors
|
||||
|
||||
// NOTE:
|
||||
// This file looks like the other `diagnostics/extraction-errors` queries in other CodeQL supported
|
||||
// languages. However, since this diagnostic query is located in the `Internal` subdirectory it will not
|
||||
// appear in the Code Scanning suite. The related query `cpp/diagnostics/extraction-warnings` is,
|
||||
// however, included as a public diagnostics query.
|
||||
from ExtractionError error
|
||||
where
|
||||
error instanceof ExtractionUnknownError or
|
||||
exists(error.getFile().getRelativePath())
|
||||
select error, "Extraction failed in " + error.getFile() + " with error " + error.getErrorMessage(),
|
||||
error.getSeverity()
|
||||
137
cpp/ql/src/Diagnostics/Internal/ExtractionErrors.qll
Normal file
137
cpp/ql/src/Diagnostics/Internal/ExtractionErrors.qll
Normal file
@@ -0,0 +1,137 @@
|
||||
/**
|
||||
* Provides a common hierarchy of all types of errors that can occur during extraction.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
|
||||
/*
|
||||
* A note about how the C/C++ extractor emits diagnostics:
|
||||
* When the extractor frontend encounters an error, it emits a diagnostic message,
|
||||
* that includes a message, location and severity.
|
||||
* However, that process is best-effort and may fail (e.g. due to lack of memory).
|
||||
* Thus, if the extractor emitted at least one diagnostic of severity discretionary
|
||||
* error (or higher), it *also* emits a simple "There was an error during this compilation"
|
||||
* error diagnostic, without location information.
|
||||
* In the common case, this means that a compilation during which one or more errors happened also gets
|
||||
* the catch-all diagnostic.
|
||||
* This diagnostic has the empty string as file path.
|
||||
* We filter out these useless diagnostics if there is at least one error-level diagnostic
|
||||
* for the affected compilation in the database.
|
||||
* Otherwise, we show it to indicate that something went wrong and that we
|
||||
* don't know what exactly happened.
|
||||
*/
|
||||
|
||||
/**
|
||||
* An error that, if present, leads to a file being marked as non-successfully extracted.
|
||||
*/
|
||||
class ReportableError extends Diagnostic {
|
||||
ReportableError() {
|
||||
(
|
||||
this instanceof CompilerDiscretionaryError or
|
||||
this instanceof CompilerError or
|
||||
this instanceof CompilerCatastrophe
|
||||
) and
|
||||
// Filter for the catch-all diagnostic, see note above.
|
||||
not this.getFile().getAbsolutePath() = ""
|
||||
}
|
||||
}
|
||||
|
||||
private newtype TExtractionError =
|
||||
TReportableError(ReportableError err) or
|
||||
TCompilationFailed(Compilation c, File f) {
|
||||
f = c.getAFileCompiled() and not c.normalTermination()
|
||||
} or
|
||||
// Show the catch-all diagnostic (see note above) only if we haven't seen any other error-level diagnostic
|
||||
// for that compilation
|
||||
TUnknownError(CompilerError err) {
|
||||
not exists(ReportableError e | e.getCompilation() = err.getCompilation())
|
||||
}
|
||||
|
||||
/**
|
||||
* Superclass for the extraction error hierarchy.
|
||||
*/
|
||||
class ExtractionError extends TExtractionError {
|
||||
/** Gets the string representation of the error. */
|
||||
string toString() { none() }
|
||||
|
||||
/** Gets the error message for this error. */
|
||||
string getErrorMessage() { none() }
|
||||
|
||||
/** Gets the file this error occured in. */
|
||||
File getFile() { none() }
|
||||
|
||||
/** Gets the location this error occured in. */
|
||||
Location getLocation() { none() }
|
||||
|
||||
/** Gets the SARIF severity of this error. */
|
||||
int getSeverity() {
|
||||
// Unfortunately, we can't distinguish between errors and fatal errors in SARIF,
|
||||
// so all errors have severity 2.
|
||||
result = 2
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An unrecoverable extraction error, where extraction was unable to finish.
|
||||
* This can be caused by a multitude of reasons, for example:
|
||||
* - hitting a frontend assertion
|
||||
* - crashing due to dereferencing an invalid pointer
|
||||
* - stack overflow
|
||||
* - out of memory
|
||||
*/
|
||||
class ExtractionUnrecoverableError extends ExtractionError, TCompilationFailed {
|
||||
Compilation c;
|
||||
File f;
|
||||
|
||||
ExtractionUnrecoverableError() { this = TCompilationFailed(c, f) }
|
||||
|
||||
override string toString() {
|
||||
result = "Unrecoverable extraction error while compiling " + f.toString()
|
||||
}
|
||||
|
||||
override string getErrorMessage() { result = "unrecoverable compilation failure." }
|
||||
|
||||
override File getFile() { result = f }
|
||||
|
||||
override Location getLocation() { result = f.getLocation() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A recoverable extraction error.
|
||||
* These are compiler errors from the frontend.
|
||||
* Upon encountering one of these, we still continue extraction, but the
|
||||
* database will be incomplete for that file.
|
||||
*/
|
||||
class ExtractionRecoverableError extends ExtractionError, TReportableError {
|
||||
ReportableError err;
|
||||
|
||||
ExtractionRecoverableError() { this = TReportableError(err) }
|
||||
|
||||
override string toString() { result = "Recoverable extraction error: " + err }
|
||||
|
||||
override string getErrorMessage() { result = err.getFullMessage() }
|
||||
|
||||
override File getFile() { result = err.getFile() }
|
||||
|
||||
override Location getLocation() { result = err.getLocation() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An unknown error happened during extraction.
|
||||
* These are only displayed if we know that we encountered an error during extraction,
|
||||
* but, for some reason, failed to emit a proper diagnostic with location information
|
||||
* and error message.
|
||||
*/
|
||||
class ExtractionUnknownError extends ExtractionError, TUnknownError {
|
||||
CompilerError err;
|
||||
|
||||
ExtractionUnknownError() { this = TUnknownError(err) }
|
||||
|
||||
override string toString() { result = "Unknown extraction error: " + err }
|
||||
|
||||
override string getErrorMessage() { result = err.getFullMessage() }
|
||||
|
||||
override File getFile() { result = err.getFile() }
|
||||
|
||||
override Location getLocation() { result = err.getLocation() }
|
||||
}
|
||||
@@ -19,9 +19,9 @@ 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
|
||||
|
||||
Expr sinkAsArgumentIndirection(DataFlow::Node sink) {
|
||||
result =
|
||||
@@ -66,154 +66,70 @@ predicate interestingConcatenation(DataFlow::Node fst, DataFlow::Node snd) {
|
||||
)
|
||||
}
|
||||
|
||||
class TaintToConcatenationConfiguration extends TaintTracking::Configuration {
|
||||
TaintToConcatenationConfiguration() { this = "TaintToConcatenationConfiguration" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof FlowSource }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) { interestingConcatenation(sink, _) }
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node) {
|
||||
node.asInstruction().getResultType() instanceof IntegralType
|
||||
or
|
||||
node.asInstruction().getResultType() instanceof FloatingPointType
|
||||
}
|
||||
class ConcatState extends DataFlow::FlowState {
|
||||
ConcatState() { this = "ConcatState" }
|
||||
}
|
||||
|
||||
class ExecTaintConfiguration extends TaintTracking2::Configuration {
|
||||
class ExecState extends DataFlow::FlowState {
|
||||
DataFlow::Node fst;
|
||||
DataFlow::Node snd;
|
||||
|
||||
ExecState() {
|
||||
this =
|
||||
"ExecState (" + fst.getLocation() + " | " + fst + ", " + snd.getLocation() + " | " + snd + ")" and
|
||||
interestingConcatenation(fst, snd)
|
||||
}
|
||||
|
||||
DataFlow::Node getFstNode() { result = fst }
|
||||
|
||||
DataFlow::Node getSndNode() { result = snd }
|
||||
}
|
||||
|
||||
class ExecTaintConfiguration extends TaintTracking::Configuration {
|
||||
ExecTaintConfiguration() { this = "ExecTaintConfiguration" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
exists(DataFlow::Node prevSink, TaintToConcatenationConfiguration conf |
|
||||
conf.hasFlow(_, prevSink) and
|
||||
interestingConcatenation(prevSink, source)
|
||||
)
|
||||
override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) {
|
||||
source instanceof FlowSource and
|
||||
state instanceof ConcatState
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
shellCommand(sinkAsArgumentIndirection(sink), _)
|
||||
override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) {
|
||||
shellCommand(sinkAsArgumentIndirection(sink), _) and
|
||||
state instanceof ExecState
|
||||
}
|
||||
|
||||
override predicate isSanitizerOut(DataFlow::Node node) {
|
||||
isSink(node) // Prevent duplicates along a call chain, since `shellCommand` will include wrappers
|
||||
}
|
||||
}
|
||||
|
||||
module StitchedPathGraph {
|
||||
// There's a different PathNode class for each DataFlowImplN.qll, so we can't simply combine the
|
||||
// PathGraph predicates directly. Instead, we use a newtype so there's a single type that
|
||||
// contains both sets of PathNodes.
|
||||
newtype TMergedPathNode =
|
||||
TPathNode1(DataFlow::PathNode node) or
|
||||
TPathNode2(DataFlow2::PathNode node)
|
||||
|
||||
// this wraps the toString and location predicates so we can use the merged node type in a
|
||||
// selection
|
||||
class MergedPathNode extends TMergedPathNode {
|
||||
string toString() {
|
||||
exists(DataFlow::PathNode n |
|
||||
this = TPathNode1(n) and
|
||||
result = n.toString()
|
||||
)
|
||||
or
|
||||
exists(DataFlow2::PathNode n |
|
||||
this = TPathNode2(n) and
|
||||
result = n.toString()
|
||||
)
|
||||
}
|
||||
|
||||
DataFlow::Node getNode() {
|
||||
exists(DataFlow::PathNode n |
|
||||
this = TPathNode1(n) and
|
||||
result = n.getNode()
|
||||
)
|
||||
or
|
||||
exists(DataFlow2::PathNode n |
|
||||
this = TPathNode2(n) and
|
||||
result = n.getNode()
|
||||
)
|
||||
}
|
||||
|
||||
DataFlow::PathNode getPathNode1() { this = TPathNode1(result) }
|
||||
|
||||
DataFlow2::PathNode getPathNode2() { this = TPathNode2(result) }
|
||||
|
||||
predicate hasLocationInfo(
|
||||
string filepath, int startline, int startcolumn, int endline, int endcolumn
|
||||
) {
|
||||
exists(DataFlow::PathNode n |
|
||||
this = TPathNode1(n) and
|
||||
n.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
)
|
||||
or
|
||||
exists(DataFlow2::PathNode n |
|
||||
this = TPathNode2(n) and
|
||||
n.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
query predicate edges(MergedPathNode a, MergedPathNode b) {
|
||||
exists(DataFlow::PathNode an, DataFlow::PathNode bn |
|
||||
a = TPathNode1(an) and
|
||||
b = TPathNode1(bn) and
|
||||
DataFlow::PathGraph::edges(an, bn)
|
||||
)
|
||||
or
|
||||
exists(DataFlow2::PathNode an, DataFlow2::PathNode bn |
|
||||
a = TPathNode2(an) and
|
||||
b = TPathNode2(bn) and
|
||||
DataFlow2::PathGraph::edges(an, bn)
|
||||
)
|
||||
or
|
||||
// This is where paths from the two configurations are connected. `interestingConcatenation`
|
||||
// is the only thing in this module that's actually specific to the query - everything else is
|
||||
// just using types and predicates from the DataFlow library.
|
||||
interestingConcatenation(a.getNode(), b.getNode()) and
|
||||
a instanceof TPathNode1 and
|
||||
b instanceof TPathNode2
|
||||
}
|
||||
|
||||
query predicate nodes(MergedPathNode mpn, string key, string val) {
|
||||
// here we just need the union of the underlying `nodes` predicates
|
||||
exists(DataFlow::PathNode n |
|
||||
mpn = TPathNode1(n) and
|
||||
DataFlow::PathGraph::nodes(n, key, val)
|
||||
)
|
||||
or
|
||||
exists(DataFlow2::PathNode n |
|
||||
mpn = TPathNode2(n) and
|
||||
DataFlow2::PathGraph::nodes(n, key, val)
|
||||
)
|
||||
}
|
||||
|
||||
query predicate subpaths(
|
||||
MergedPathNode arg, MergedPathNode par, MergedPathNode ret, MergedPathNode out
|
||||
override predicate isAdditionalTaintStep(
|
||||
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
|
||||
DataFlow::FlowState state2
|
||||
) {
|
||||
// just forward subpaths from the underlying libraries. This might be slightly awkward when
|
||||
// the concatenation is deep in a call chain.
|
||||
DataFlow::PathGraph::subpaths(arg.getPathNode1(), par.getPathNode1(), ret.getPathNode1(),
|
||||
out.getPathNode1())
|
||||
or
|
||||
DataFlow2::PathGraph::subpaths(arg.getPathNode2(), par.getPathNode2(), ret.getPathNode2(),
|
||||
out.getPathNode2())
|
||||
state1 instanceof ConcatState and
|
||||
state2.(ExecState).getFstNode() = node1 and
|
||||
state2.(ExecState).getSndNode() = node2
|
||||
}
|
||||
|
||||
override predicate isSanitizer(DataFlow::Node node, DataFlow::FlowState state) {
|
||||
(
|
||||
node.asInstruction().getResultType() instanceof IntegralType
|
||||
or
|
||||
node.asInstruction().getResultType() instanceof FloatingPointType
|
||||
) and
|
||||
state instanceof ConcatState
|
||||
}
|
||||
|
||||
override predicate isSanitizerOut(DataFlow::Node node, DataFlow::FlowState state) {
|
||||
isSink(node, state) // Prevent duplicates along a call chain, since `shellCommand` will include wrappers
|
||||
}
|
||||
}
|
||||
|
||||
import StitchedPathGraph
|
||||
|
||||
from
|
||||
DataFlow::PathNode sourceNode, DataFlow::PathNode concatSink, DataFlow2::PathNode concatSource,
|
||||
DataFlow2::PathNode sinkNode, string taintCause, string callChain,
|
||||
TaintToConcatenationConfiguration conf1, ExecTaintConfiguration conf2
|
||||
ExecTaintConfiguration conf, DataFlow::PathNode sourceNode, DataFlow::PathNode sinkNode,
|
||||
string taintCause, string callChain, DataFlow::Node concatResult
|
||||
where
|
||||
conf.hasFlowPath(sourceNode, sinkNode) and
|
||||
taintCause = sourceNode.getNode().(FlowSource).getSourceType() and
|
||||
conf1.hasFlowPath(sourceNode, concatSink) and
|
||||
interestingConcatenation(concatSink.getNode(), concatSource.getNode()) and // this loses call context
|
||||
conf2.hasFlowPath(concatSource, sinkNode) and
|
||||
shellCommand(sinkAsArgumentIndirection(sinkNode.getNode()), callChain)
|
||||
select sinkAsArgumentIndirection(sinkNode.getNode()), TPathNode1(sourceNode).(MergedPathNode),
|
||||
TPathNode2(sinkNode).(MergedPathNode),
|
||||
shellCommand(sinkAsArgumentIndirection(sinkNode.getNode()), callChain) and
|
||||
concatResult = sinkNode.getState().(ExecState).getSndNode()
|
||||
select sinkAsArgumentIndirection(sinkNode.getNode()), sourceNode, sinkNode,
|
||||
"This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to "
|
||||
+ callChain, sourceNode, "user input (" + taintCause + ")", concatSource,
|
||||
concatSource.toString()
|
||||
+ callChain, sourceNode, "user input (" + taintCause + ")", concatResult,
|
||||
concatResult.toString()
|
||||
|
||||
@@ -9,28 +9,43 @@
|
||||
* @id cpp/cleartext-transmission
|
||||
* @tags security
|
||||
* external/cwe/cwe-319
|
||||
* external/cwe/cwe-359
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.security.SensitiveExprs
|
||||
import semmle.code.cpp.security.PrivateData
|
||||
import semmle.code.cpp.dataflow.TaintTracking
|
||||
import semmle.code.cpp.models.interfaces.FlowSource
|
||||
import semmle.code.cpp.commons.File
|
||||
import DataFlow::PathGraph
|
||||
|
||||
class SourceVariable extends Variable {
|
||||
SourceVariable() {
|
||||
this instanceof SensitiveVariable or
|
||||
this instanceof PrivateDataVariable
|
||||
}
|
||||
}
|
||||
|
||||
class SourceFunction extends Function {
|
||||
SourceFunction() {
|
||||
this instanceof SensitiveFunction or
|
||||
this instanceof PrivateDataFunction
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A DataFlow node corresponding to a variable or function call that
|
||||
* might contain or return a password or other sensitive information.
|
||||
*/
|
||||
class SensitiveNode extends DataFlow::Node {
|
||||
SensitiveNode() {
|
||||
this.asExpr() = any(SensitiveVariable sv).getInitializer().getExpr() or
|
||||
this.asExpr().(VariableAccess).getTarget() =
|
||||
any(SensitiveVariable sv).(GlobalOrNamespaceVariable) or
|
||||
this.asExpr().(VariableAccess).getTarget() = any(SensitiveVariable v | v instanceof Field) or
|
||||
this.asUninitialized() instanceof SensitiveVariable or
|
||||
this.asParameter() instanceof SensitiveVariable or
|
||||
this.asExpr().(FunctionCall).getTarget() instanceof SensitiveFunction
|
||||
class SourceNode extends DataFlow::Node {
|
||||
SourceNode() {
|
||||
this.asExpr() = any(SourceVariable sv).getInitializer().getExpr() or
|
||||
this.asExpr().(VariableAccess).getTarget() = any(SourceVariable sv).(GlobalOrNamespaceVariable) or
|
||||
this.asExpr().(VariableAccess).getTarget() = any(SourceVariable v | v instanceof Field) or
|
||||
this.asUninitialized() instanceof SourceVariable or
|
||||
this.asParameter() instanceof SourceVariable or
|
||||
this.asExpr().(FunctionCall).getTarget() instanceof SourceFunction
|
||||
}
|
||||
}
|
||||
|
||||
@@ -207,7 +222,7 @@ class Encrypted extends Expr {
|
||||
class FromSensitiveConfiguration extends TaintTracking::Configuration {
|
||||
FromSensitiveConfiguration() { this = "FromSensitiveConfiguration" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof SensitiveNode }
|
||||
override predicate isSource(DataFlow::Node source) { source instanceof SourceNode }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
sink.asExpr() = any(NetworkSendRecv nsr).getDataExpr()
|
||||
|
||||
@@ -3,17 +3,17 @@
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p>Exposing system data or debugging information may help an adversary to learn about the system and form an attack plan. An attacker can use error messages that reveal technologies, operating systems, and product versions to tune their attack against known vulnerabilities in these technologies.</p>
|
||||
<p>Exposing system data or debugging information may help a malicious user learn about the system and form an attack plan. An attacker can use error messages that reveal technologies, operating systems, and product versions to tune their attack against known vulnerabilities in the software.</p>
|
||||
|
||||
<p>This query finds locations where system configuration information might be revealed to a user.</p>
|
||||
<p>This query finds locations where system configuration information might be revealed to a remote user.</p>
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
<p>Do not expose system configuration information to users. Be wary of the difference between information that could be helpful to users, and unnecessary details that could be useful to an adversary.</p>
|
||||
<p>Do not expose system configuration information to remote users. Be wary of the difference between information that could be helpful to users, and unnecessary details that could be useful to a malicious user.</p>
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
<p>In this example the value of the <code>PATH</code> environment variable is revealed in full to the user when a particular error occurs. This might reveal information such as the software installed on your system to an adversary who does not have legitimate access to that information.</p>
|
||||
<p>In this example the value of the <code>PATH</code> environment variable is revealed in full to the user when a particular error occurs. This might reveal information such as the software installed on your system to a malicious user who does not have legitimate access to that information.</p>
|
||||
|
||||
<sample src="ExposedSystemDataIncorrect.cpp" />
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @name Exposure of system data to an unauthorized control sphere
|
||||
* @description Exposing system data or debugging information helps
|
||||
* an adversary learn about the system and form an
|
||||
* a malicious user learn about the system and form an
|
||||
* attack plan.
|
||||
* @kind path-problem
|
||||
* @problem.severity warning
|
||||
@@ -13,284 +13,15 @@
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.commons.Environment
|
||||
import semmle.code.cpp.ir.dataflow.TaintTracking
|
||||
import semmle.code.cpp.models.interfaces.FlowSource
|
||||
import DataFlow::PathGraph
|
||||
|
||||
/**
|
||||
* An element that should not be exposed to an adversary.
|
||||
*/
|
||||
abstract class SystemData extends Element {
|
||||
/**
|
||||
* Gets an expression that is part of this `SystemData`.
|
||||
*/
|
||||
abstract Expr getAnExpr();
|
||||
}
|
||||
|
||||
/**
|
||||
* Data originating from the environment.
|
||||
*/
|
||||
class EnvData extends SystemData {
|
||||
EnvData() {
|
||||
// identify risky looking environment variables only
|
||||
this.(EnvironmentRead)
|
||||
.getEnvironmentVariable()
|
||||
.toLowerCase()
|
||||
.regexpMatch(".*(user|host|admin|root|home|path|http|ssl|snmp|sock|port|proxy|pass|token|crypt|key).*")
|
||||
}
|
||||
|
||||
override Expr getAnExpr() { result = this }
|
||||
}
|
||||
|
||||
/**
|
||||
* Data originating from a call to `mysql_get_client_info()`.
|
||||
*/
|
||||
class SqlClientInfo extends SystemData {
|
||||
SqlClientInfo() { this.(FunctionCall).getTarget().hasName("mysql_get_client_info") }
|
||||
|
||||
override Expr getAnExpr() { result = this }
|
||||
}
|
||||
|
||||
private predicate sqlConnectInfo(FunctionCall source, VariableAccess use) {
|
||||
(
|
||||
source.getTarget().hasName("mysql_connect") or
|
||||
source.getTarget().hasName("mysql_real_connect")
|
||||
) and
|
||||
use = source.getAnArgument()
|
||||
}
|
||||
|
||||
/**
|
||||
* Data passed into an SQL connect function.
|
||||
*/
|
||||
class SqlConnectInfo extends SystemData {
|
||||
SqlConnectInfo() { sqlConnectInfo(this, _) }
|
||||
|
||||
override Expr getAnExpr() { sqlConnectInfo(this, result) }
|
||||
}
|
||||
|
||||
private predicate posixSystemInfo(FunctionCall source, Element use) {
|
||||
// size_t confstr(int name, char *buf, size_t len)
|
||||
// - various OS / system strings, such as the libc version
|
||||
// int statvfs(const char *__path, struct statvfs *__buf)
|
||||
// int fstatvfs(int __fd, struct statvfs *__buf)
|
||||
// - various filesystem parameters
|
||||
// int uname(struct utsname *buf)
|
||||
// - OS name and version
|
||||
source.getTarget().hasName(["confstr", "statvfs", "fstatvfs", "uname"]) and
|
||||
use = source.getArgument(1)
|
||||
}
|
||||
|
||||
/**
|
||||
* Data obtained from a POSIX system information call.
|
||||
*/
|
||||
class PosixSystemInfo extends SystemData {
|
||||
PosixSystemInfo() { posixSystemInfo(this, _) }
|
||||
|
||||
override Expr getAnExpr() { posixSystemInfo(this, result) }
|
||||
}
|
||||
|
||||
private predicate posixPWInfo(FunctionCall source, Element use) {
|
||||
// struct passwd *getpwnam(const char *name);
|
||||
// struct passwd *getpwuid(uid_t uid);
|
||||
// struct passwd *getpwent(void);
|
||||
// struct group *getgrnam(const char *name);
|
||||
// struct group *getgrgid(gid_t);
|
||||
// struct group *getgrent(void);
|
||||
source
|
||||
.getTarget()
|
||||
.hasName(["getpwnam", "getpwuid", "getpwent", "getgrnam", "getgrgid", "getgrent"]) and
|
||||
use = source
|
||||
or
|
||||
// int getpwnam_r(const char *name, struct passwd *pwd,
|
||||
// char *buf, size_t buflen, struct passwd **result);
|
||||
// int getpwuid_r(uid_t uid, struct passwd *pwd,
|
||||
// char *buf, size_t buflen, struct passwd **result);
|
||||
// int getgrgid_r(gid_t gid, struct group *grp,
|
||||
// char *buf, size_t buflen, struct group **result);
|
||||
// int getgrnam_r(const char *name, struct group *grp,
|
||||
// char *buf, size_t buflen, struct group **result);
|
||||
source.getTarget().hasName(["getpwnam_r", "getpwuid_r", "getgrgid_r", "getgrnam_r"]) and
|
||||
use = source.getArgument([1, 2, 4])
|
||||
or
|
||||
// int getpwent_r(struct passwd *pwd, char *buffer, size_t bufsize,
|
||||
// struct passwd **result);
|
||||
// int getgrent_r(struct group *gbuf, char *buf,
|
||||
// size_t buflen, struct group **gbufp);
|
||||
source.getTarget().hasName(["getpwent_r", "getgrent_r"]) and
|
||||
use = source.getArgument([0, 1, 3])
|
||||
}
|
||||
|
||||
/**
|
||||
* Data obtained from a POSIX user/password/group database information call.
|
||||
*/
|
||||
class PosixPWInfo extends SystemData {
|
||||
PosixPWInfo() { posixPWInfo(this, _) }
|
||||
|
||||
override Expr getAnExpr() { posixPWInfo(this, result) }
|
||||
}
|
||||
|
||||
private predicate windowsSystemInfo(FunctionCall source, Element use) {
|
||||
// DWORD WINAPI GetVersion(void);
|
||||
source.getTarget().hasGlobalName("GetVersion") and
|
||||
use = source
|
||||
or
|
||||
// BOOL WINAPI GetVersionEx(_Inout_ LPOSVERSIONINFO lpVersionInfo);
|
||||
// void WINAPI GetSystemInfo(_Out_ LPSYSTEM_INFO lpSystemInfo);
|
||||
// void WINAPI GetNativeSystemInfo(_Out_ LPSYSTEM_INFO lpSystemInfo);
|
||||
source
|
||||
.getTarget()
|
||||
.hasGlobalName([
|
||||
"GetVersionEx", "GetVersionExA", "GetVersionExW", "GetSystemInfo", "GetNativeSystemInfo"
|
||||
]) and
|
||||
use = source.getArgument(0)
|
||||
}
|
||||
|
||||
/**
|
||||
* Data obtained from a Windows system information call.
|
||||
*/
|
||||
class WindowsSystemInfo extends SystemData {
|
||||
WindowsSystemInfo() { windowsSystemInfo(this, _) }
|
||||
|
||||
override Expr getAnExpr() { windowsSystemInfo(this, result) }
|
||||
}
|
||||
|
||||
private predicate windowsFolderPath(FunctionCall source, Element use) {
|
||||
// BOOL SHGetSpecialFolderPath(
|
||||
// HWND hwndOwner,
|
||||
// _Out_ LPTSTR lpszPath,
|
||||
// _In_ int csidl,
|
||||
// _In_ BOOL fCreate
|
||||
// );
|
||||
source
|
||||
.getTarget()
|
||||
.hasGlobalName([
|
||||
"SHGetSpecialFolderPath", "SHGetSpecialFolderPathA", "SHGetSpecialFolderPathW"
|
||||
]) and
|
||||
use = source.getArgument(1)
|
||||
or
|
||||
// HRESULT SHGetKnownFolderPath(
|
||||
// _In_ REFKNOWNFOLDERID rfid,
|
||||
// _In_ DWORD dwFlags,
|
||||
// _In_opt_ HANDLE hToken,
|
||||
// _Out_ PWSTR *ppszPath
|
||||
// );
|
||||
source.getTarget().hasGlobalName("SHGetKnownFolderPath") and
|
||||
use = source.getArgument(3)
|
||||
or
|
||||
// HRESULT SHGetFolderPath(
|
||||
// _In_ HWND hwndOwner,
|
||||
// _In_ int nFolder,
|
||||
// _In_ HANDLE hToken,
|
||||
// _In_ DWORD dwFlags,
|
||||
// _Out_ LPTSTR pszPath
|
||||
// );
|
||||
source.getTarget().hasGlobalName(["SHGetFolderPath", "SHGetFolderPathA", "SHGetFolderPathW"]) and
|
||||
use = source.getArgument(4)
|
||||
or
|
||||
// HRESULT SHGetFolderPathAndSubDir(
|
||||
// _In_ HWND hwnd,
|
||||
// _In_ int csidl,
|
||||
// _In_ HANDLE hToken,
|
||||
// _In_ DWORD dwFlags,
|
||||
// _In_ LPCTSTR pszSubDir,
|
||||
// _Out_ LPTSTR pszPath
|
||||
// );
|
||||
source
|
||||
.getTarget()
|
||||
.hasGlobalName([
|
||||
"SHGetFolderPathAndSubDir", "SHGetFolderPathAndSubDirA", "SHGetFolderPathAndSubDirW"
|
||||
]) and
|
||||
use = source.getArgument(5)
|
||||
}
|
||||
|
||||
/**
|
||||
* Data obtained about Windows special paths (for example, the
|
||||
* location of `System32`).
|
||||
*/
|
||||
class WindowsFolderPath extends SystemData {
|
||||
WindowsFolderPath() { windowsFolderPath(this, _) }
|
||||
|
||||
override Expr getAnExpr() { windowsFolderPath(this, result) }
|
||||
}
|
||||
|
||||
private predicate logonUser(FunctionCall source, VariableAccess use) {
|
||||
source.getTarget().hasGlobalName(["LogonUser", "LogonUserW", "LogonUserA"]) and
|
||||
use = source.getAnArgument()
|
||||
}
|
||||
|
||||
/**
|
||||
* Data passed into a `LogonUser` (Windows) function.
|
||||
*/
|
||||
class LogonUser extends SystemData {
|
||||
LogonUser() { logonUser(this, _) }
|
||||
|
||||
override Expr getAnExpr() { logonUser(this, result) }
|
||||
}
|
||||
|
||||
private predicate regQuery(FunctionCall source, VariableAccess use) {
|
||||
// LONG WINAPI RegQueryValue(
|
||||
// _In_ HKEY hKey,
|
||||
// _In_opt_ LPCTSTR lpSubKey,
|
||||
// _Out_opt_ LPTSTR lpValue,
|
||||
// _Inout_opt_ PLONG lpcbValue
|
||||
// );
|
||||
source.getTarget().hasGlobalName(["RegQueryValue", "RegQueryValueA", "RegQueryValueW"]) and
|
||||
use = source.getArgument(2)
|
||||
or
|
||||
// LONG WINAPI RegQueryMultipleValues(
|
||||
// _In_ HKEY hKey,
|
||||
// _Out_ PVALENT val_list,
|
||||
// _In_ DWORD num_vals,
|
||||
// _Out_opt_ LPTSTR lpValueBuf,
|
||||
// _Inout_opt_ LPDWORD ldwTotsize
|
||||
// );
|
||||
source
|
||||
.getTarget()
|
||||
.hasGlobalName([
|
||||
"RegQueryMultipleValues", "RegQueryMultipleValuesA", "RegQueryMultipleValuesW"
|
||||
]) and
|
||||
use = source.getArgument(3)
|
||||
or
|
||||
// LONG WINAPI RegQueryValueEx(
|
||||
// _In_ HKEY hKey,
|
||||
// _In_opt_ LPCTSTR lpValueName,
|
||||
// _Reserved_ LPDWORD lpReserved,
|
||||
// _Out_opt_ LPDWORD lpType,
|
||||
// _Out_opt_ LPBYTE lpData,
|
||||
// _Inout_opt_ LPDWORD lpcbData
|
||||
// );
|
||||
source.getTarget().hasGlobalName(["RegQueryValueEx", "RegQueryValueExA", "RegQueryValueExW"]) and
|
||||
use = source.getArgument(4)
|
||||
or
|
||||
// LONG WINAPI RegGetValue(
|
||||
// _In_ HKEY hkey,
|
||||
// _In_opt_ LPCTSTR lpSubKey,
|
||||
// _In_opt_ LPCTSTR lpValue,
|
||||
// _In_opt_ DWORD dwFlags,
|
||||
// _Out_opt_ LPDWORD pdwType,
|
||||
// _Out_opt_ PVOID pvData,
|
||||
// _Inout_opt_ LPDWORD pcbData
|
||||
// );
|
||||
source.getTarget().hasGlobalName(["RegGetValue", "RegGetValueA", "RegGetValueW"]) and
|
||||
use = source.getArgument(5)
|
||||
}
|
||||
|
||||
/**
|
||||
* Data read from the Windows registry.
|
||||
*/
|
||||
class RegQuery extends SystemData {
|
||||
RegQuery() { regQuery(this, _) }
|
||||
|
||||
override Expr getAnExpr() { regQuery(this, result) }
|
||||
}
|
||||
import SystemData
|
||||
|
||||
class ExposedSystemDataConfiguration extends TaintTracking::Configuration {
|
||||
ExposedSystemDataConfiguration() { this = "ExposedSystemDataConfiguration" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
source.asConvertedExpr() = any(SystemData sd).getAnExpr()
|
||||
}
|
||||
override predicate isSource(DataFlow::Node source) { source = any(SystemData sd).getAnExpr() }
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
exists(FunctionCall fc, FunctionInput input, int arg |
|
||||
|
||||
@@ -2,6 +2,5 @@ char* path = getenv("PATH");
|
||||
|
||||
//...
|
||||
|
||||
fprintf(stderr, "A required executable file could not be found. " \
|
||||
"Please ensure that the software has been installed " \
|
||||
"correctly or contact a system administrator.\n");
|
||||
message = "An internal error has occurred. Please try again or contact a system administrator.\n";
|
||||
send(socket, message, strlen(message), 0);
|
||||
@@ -2,4 +2,5 @@ char* path = getenv("PATH");
|
||||
|
||||
//...
|
||||
|
||||
fprintf(stderr, "cannot find exe on path %s\n", path);
|
||||
sprintf(buffer, "Cannot find exe on path: %s", path);
|
||||
send(socket, buffer, strlen(buffer), 0);
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
<!DOCTYPE qhelp PUBLIC
|
||||
"-//Semmle//qhelp//EN"
|
||||
"qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p>Exposing system data or debugging information may help a malicious user learn about the system and form an attack plan. An attacker can use error messages that reveal technologies, operating systems, and product versions to tune their attack against known vulnerabilities in the software.</p>
|
||||
|
||||
<p>This query finds locations where system configuration information that is particularly sensitive might be revealed to a user.</p>
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
<p>Do not expose system configuration information to users. Be wary of the difference between information that could be helpful to users, and unnecessary details that could be useful to a malicious user.</p>
|
||||
</recommendation>
|
||||
|
||||
<example>
|
||||
<p>In this example the value of the <code>PATH</code> environment variable is revealed in full to the user when a particular error occurs. This might reveal information such as the software installed on your system to a malicious user who does not have legitimate access to that information.</p>
|
||||
|
||||
<sample src="PotentiallyExposedSystemDataIncorrect.cpp" />
|
||||
|
||||
<p>The message should be rephrased without this information, for example:</p>
|
||||
|
||||
<sample src="PotentiallyExposedSystemDataCorrect.cpp" />
|
||||
</example>
|
||||
|
||||
<references>
|
||||
</references>
|
||||
|
||||
</qhelp>
|
||||
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* @name Potential exposure of sensitive system data to an unauthorized control sphere
|
||||
* @description Exposing sensitive system data helps
|
||||
* a malicious user learn about the system and form an
|
||||
* attack plan.
|
||||
* @kind path-problem
|
||||
* @problem.severity warning
|
||||
* @security-severity 6.5
|
||||
* @precision medium
|
||||
* @id cpp/potential-system-data-exposure
|
||||
* @tags security
|
||||
* external/cwe/cwe-497
|
||||
*/
|
||||
|
||||
/*
|
||||
* These queries are closely related:
|
||||
* - `cpp/system-data-exposure`, which flags exposure of system information
|
||||
* to a remote sink (i.e. focusses on quality of the sink).
|
||||
* - `cpp/potential-system-data-exposure`, which flags on exposure of the most
|
||||
* sensitive information to a local sink (i.e. focusses on quality of the
|
||||
* sensitive information).
|
||||
*
|
||||
* This used to be a single query with neither focus, which was too noisy and
|
||||
* gave the user less control.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.ir.dataflow.TaintTracking
|
||||
import semmle.code.cpp.models.interfaces.FlowSource
|
||||
import semmle.code.cpp.security.OutputWrite
|
||||
import DataFlow::PathGraph
|
||||
import SystemData
|
||||
|
||||
class PotentiallyExposedSystemDataConfiguration extends TaintTracking::Configuration {
|
||||
PotentiallyExposedSystemDataConfiguration() { this = "PotentiallyExposedSystemDataConfiguration" }
|
||||
|
||||
override predicate isSource(DataFlow::Node source) {
|
||||
source = any(SystemData sd | sd.isSensitive()).getAnExpr()
|
||||
}
|
||||
|
||||
override predicate isSink(DataFlow::Node sink) {
|
||||
exists(OutputWrite ow | ow.getASource().getAChild*() = sink.asExpr())
|
||||
}
|
||||
}
|
||||
|
||||
from
|
||||
PotentiallyExposedSystemDataConfiguration config, DataFlow::PathNode source,
|
||||
DataFlow::PathNode sink
|
||||
where config.hasFlowPath(source, sink)
|
||||
select sink, source, sink, "This operation potentially exposes sensitive system data from $@.",
|
||||
source, source.getNode().toString()
|
||||
@@ -0,0 +1,5 @@
|
||||
char* key = getenv("APP_KEY");
|
||||
|
||||
//...
|
||||
|
||||
fprintf(stderr, "Application key not recognized. Please ensure the key is correct or contact a system administrator.\n", key);
|
||||
@@ -0,0 +1,5 @@
|
||||
char* key = getenv("APP_KEY");
|
||||
|
||||
//...
|
||||
|
||||
fprintf(stderr, "Key not recognized: %s\n", key);
|
||||
342
cpp/ql/src/Security/CWE/CWE-497/SystemData.qll
Normal file
342
cpp/ql/src/Security/CWE/CWE-497/SystemData.qll
Normal file
@@ -0,0 +1,342 @@
|
||||
/**
|
||||
* Classes for recognizing system data, used by the exposed system data queries.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.commons.Environment
|
||||
import semmle.code.cpp.ir.dataflow.TaintTracking
|
||||
|
||||
/**
|
||||
* An element that should not be exposed to a malicious user.
|
||||
*/
|
||||
abstract class SystemData extends Element {
|
||||
/**
|
||||
* Gets an expression that is part of this `SystemData`.
|
||||
*/
|
||||
abstract DataFlow::Node getAnExpr();
|
||||
|
||||
/**
|
||||
* Holds if this system data is considered especially sensitive (for example
|
||||
* a password or token).
|
||||
*/
|
||||
predicate isSensitive() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* Data originating from the environment.
|
||||
*/
|
||||
class EnvData extends SystemData {
|
||||
EnvData() {
|
||||
// identify risky looking environment variables only
|
||||
this.(EnvironmentRead)
|
||||
.getEnvironmentVariable()
|
||||
.toLowerCase()
|
||||
.regexpMatch(".*(user|host|admin|root|home|path|http|ssl|snmp|sock|port|proxy|pass|token|crypt|key).*")
|
||||
}
|
||||
|
||||
override DataFlow::Node getAnExpr() { result.asConvertedExpr() = this }
|
||||
|
||||
override predicate isSensitive() {
|
||||
this.(EnvironmentRead)
|
||||
.getEnvironmentVariable()
|
||||
.toLowerCase()
|
||||
.regexpMatch(".*(pass|token|key).*")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Data originating from a call to `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() }
|
||||
}
|
||||
|
||||
private predicate sqlConnectInfo(FunctionCall source, Expr use) {
|
||||
(
|
||||
source.getTarget().hasName("mysql_connect") or
|
||||
source.getTarget().hasName("mysql_real_connect")
|
||||
) and
|
||||
use = source.getAnArgument()
|
||||
}
|
||||
|
||||
/**
|
||||
* Data passed into an SQL connect function.
|
||||
*/
|
||||
class SQLConnectInfo extends SystemData {
|
||||
SQLConnectInfo() { sqlConnectInfo(this, _) }
|
||||
|
||||
override DataFlow::Node getAnExpr() { sqlConnectInfo(this, result.asConvertedExpr()) }
|
||||
|
||||
override predicate isSensitive() { any() }
|
||||
}
|
||||
|
||||
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
|
||||
// int statvfs(const char *__path, struct statvfs *__buf)
|
||||
// int fstatvfs(int __fd, struct statvfs *__buf)
|
||||
source.getTarget().hasName(["confstr", "statvfs", "fstatvfs"]) and
|
||||
use.asDefiningArgument() = source.getArgument(1)
|
||||
or
|
||||
// - various filesystem parameters
|
||||
// int uname(struct utsname *buf)
|
||||
// - OS name and version
|
||||
source.getTarget().hasName("uname") and
|
||||
use.asDefiningArgument() = source.getArgument(0)
|
||||
}
|
||||
|
||||
/**
|
||||
* Data obtained from a POSIX system information call.
|
||||
*/
|
||||
class PosixSystemInfo extends SystemData {
|
||||
PosixSystemInfo() { posixSystemInfo(this, _) }
|
||||
|
||||
override DataFlow::Node getAnExpr() { posixSystemInfo(this, result) }
|
||||
}
|
||||
|
||||
private predicate posixPWInfo(FunctionCall source, DataFlow::Node use) {
|
||||
// struct passwd *getpwnam(const char *name);
|
||||
// struct passwd *getpwuid(uid_t uid);
|
||||
// struct passwd *getpwent(void);
|
||||
// struct group *getgrnam(const char *name);
|
||||
// struct group *getgrgid(gid_t);
|
||||
// struct group *getgrent(void);
|
||||
source
|
||||
.getTarget()
|
||||
.hasName(["getpwnam", "getpwuid", "getpwent", "getgrnam", "getgrgid", "getgrent"]) and
|
||||
use.asConvertedExpr() = source
|
||||
or
|
||||
// int getpwnam_r(const char *name, struct passwd *pwd,
|
||||
// char *buf, size_t buflen, struct passwd **result);
|
||||
// int getpwuid_r(uid_t uid, struct passwd *pwd,
|
||||
// char *buf, size_t buflen, struct passwd **result);
|
||||
// int getgrgid_r(gid_t gid, struct group *grp,
|
||||
// char *buf, size_t buflen, struct group **result);
|
||||
// int getgrnam_r(const char *name, struct group *grp,
|
||||
// char *buf, size_t buflen, struct group **result);
|
||||
source.getTarget().hasName(["getpwnam_r", "getpwuid_r", "getgrgid_r", "getgrnam_r"]) and
|
||||
(
|
||||
use.asConvertedExpr() = source.getArgument([1, 2]) or
|
||||
use.asDefiningArgument() = source.getArgument(4)
|
||||
)
|
||||
or
|
||||
// int getpwent_r(struct passwd *pwd, char *buffer, size_t bufsize,
|
||||
// struct passwd **result);
|
||||
// int getgrent_r(struct group *gbuf, char *buf,
|
||||
// size_t buflen, struct group **gbufp);
|
||||
source.getTarget().hasName(["getpwent_r", "getgrent_r"]) and
|
||||
(
|
||||
use.asConvertedExpr() = source.getArgument([0, 1]) or
|
||||
use.asDefiningArgument() = source.getArgument(3)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Data obtained from a POSIX user/password/group database information call.
|
||||
*/
|
||||
class PosixPWInfo extends SystemData {
|
||||
PosixPWInfo() { posixPWInfo(this, _) }
|
||||
|
||||
override DataFlow::Node getAnExpr() { posixPWInfo(this, result) }
|
||||
|
||||
override predicate isSensitive() { any() }
|
||||
}
|
||||
|
||||
private predicate windowsSystemInfo(FunctionCall source, DataFlow::Node use) {
|
||||
// DWORD WINAPI GetVersion(void);
|
||||
source.getTarget().hasGlobalName("GetVersion") and
|
||||
use.asConvertedExpr() = source
|
||||
or
|
||||
// BOOL WINAPI GetVersionEx(_Inout_ LPOSVERSIONINFO lpVersionInfo);
|
||||
// void WINAPI GetSystemInfo(_Out_ LPSYSTEM_INFO lpSystemInfo);
|
||||
// void WINAPI GetNativeSystemInfo(_Out_ LPSYSTEM_INFO lpSystemInfo);
|
||||
source
|
||||
.getTarget()
|
||||
.hasGlobalName([
|
||||
"GetVersionEx", "GetVersionExA", "GetVersionExW", "GetSystemInfo", "GetNativeSystemInfo"
|
||||
]) and
|
||||
use.asDefiningArgument() = source.getArgument(0)
|
||||
}
|
||||
|
||||
/**
|
||||
* Data obtained from a Windows system information call.
|
||||
*/
|
||||
class WindowsSystemInfo extends SystemData {
|
||||
WindowsSystemInfo() { windowsSystemInfo(this, _) }
|
||||
|
||||
override DataFlow::Node getAnExpr() { windowsSystemInfo(this, result) }
|
||||
}
|
||||
|
||||
private predicate windowsFolderPath(FunctionCall source, Element use) {
|
||||
// BOOL SHGetSpecialFolderPath(
|
||||
// HWND hwndOwner,
|
||||
// _Out_ LPTSTR lpszPath,
|
||||
// _In_ int csidl,
|
||||
// _In_ BOOL fCreate
|
||||
// );
|
||||
source
|
||||
.getTarget()
|
||||
.hasGlobalName([
|
||||
"SHGetSpecialFolderPath", "SHGetSpecialFolderPathA", "SHGetSpecialFolderPathW"
|
||||
]) and
|
||||
use = source.getArgument(1)
|
||||
or
|
||||
// HRESULT SHGetKnownFolderPath(
|
||||
// _In_ REFKNOWNFOLDERID rfid,
|
||||
// _In_ DWORD dwFlags,
|
||||
// _In_opt_ HANDLE hToken,
|
||||
// _Out_ PWSTR *ppszPath
|
||||
// );
|
||||
source.getTarget().hasGlobalName("SHGetKnownFolderPath") and
|
||||
use = source.getArgument(3)
|
||||
or
|
||||
// HRESULT SHGetFolderPath(
|
||||
// _In_ HWND hwndOwner,
|
||||
// _In_ int nFolder,
|
||||
// _In_ HANDLE hToken,
|
||||
// _In_ DWORD dwFlags,
|
||||
// _Out_ LPTSTR pszPath
|
||||
// );
|
||||
source.getTarget().hasGlobalName(["SHGetFolderPath", "SHGetFolderPathA", "SHGetFolderPathW"]) and
|
||||
use = source.getArgument(4)
|
||||
or
|
||||
// HRESULT SHGetFolderPathAndSubDir(
|
||||
// _In_ HWND hwnd,
|
||||
// _In_ int csidl,
|
||||
// _In_ HANDLE hToken,
|
||||
// _In_ DWORD dwFlags,
|
||||
// _In_ LPCTSTR pszSubDir,
|
||||
// _Out_ LPTSTR pszPath
|
||||
// );
|
||||
source
|
||||
.getTarget()
|
||||
.hasGlobalName([
|
||||
"SHGetFolderPathAndSubDir", "SHGetFolderPathAndSubDirA", "SHGetFolderPathAndSubDirW"
|
||||
]) and
|
||||
use = source.getArgument(5)
|
||||
}
|
||||
|
||||
/**
|
||||
* Data obtained about Windows special paths (for example, the
|
||||
* location of `System32`).
|
||||
*/
|
||||
class WindowsFolderPath extends SystemData {
|
||||
WindowsFolderPath() { windowsFolderPath(this, _) }
|
||||
|
||||
override DataFlow::Node getAnExpr() { windowsFolderPath(this, result.asDefiningArgument()) }
|
||||
}
|
||||
|
||||
private predicate logonUser(FunctionCall source, VariableAccess use) {
|
||||
source.getTarget().hasGlobalName(["LogonUser", "LogonUserW", "LogonUserA"]) and
|
||||
use = source.getAnArgument()
|
||||
}
|
||||
|
||||
/**
|
||||
* Data passed into a `LogonUser` (Windows) function.
|
||||
*/
|
||||
class LogonUser extends SystemData {
|
||||
LogonUser() { logonUser(this, _) }
|
||||
|
||||
override DataFlow::Node getAnExpr() { logonUser(this, result.asConvertedExpr()) }
|
||||
|
||||
override predicate isSensitive() { any() }
|
||||
}
|
||||
|
||||
/**
|
||||
* The type of a registry query parameter, if it is of interest to us. This
|
||||
* is used to express information about registry query parameters in the
|
||||
* `regQuery` predicate concisely.
|
||||
*/
|
||||
private newtype TRegQueryParameter =
|
||||
TSubKeyName() or
|
||||
TValueName() or
|
||||
TReturnData()
|
||||
|
||||
/**
|
||||
* Registry query call (`source`) with information about parameters (`param`).
|
||||
*/
|
||||
private predicate regQuery(FunctionCall source, TRegQueryParameter paramType, Expr param) {
|
||||
// LONG WINAPI RegQueryValue(
|
||||
// _In_ HKEY hKey,
|
||||
// _In_opt_ LPCTSTR lpSubKey,
|
||||
// _Out_opt_ LPTSTR lpValue,
|
||||
// _Inout_opt_ PLONG lpcbValue
|
||||
// );
|
||||
source.getTarget().hasGlobalName(["RegQueryValue", "RegQueryValueA", "RegQueryValueW"]) and
|
||||
(
|
||||
paramType = TSubKeyName() and param = source.getArgument(1)
|
||||
or
|
||||
paramType = TReturnData() and param = source.getArgument(2)
|
||||
)
|
||||
or
|
||||
// LONG WINAPI RegQueryMultipleValues(
|
||||
// _In_ HKEY hKey,
|
||||
// _Out_ PVALENT val_list,
|
||||
// _In_ DWORD num_vals,
|
||||
// _Out_opt_ LPTSTR lpValueBuf,
|
||||
// _Inout_opt_ LPDWORD ldwTotsize
|
||||
// );
|
||||
source
|
||||
.getTarget()
|
||||
.hasGlobalName([
|
||||
"RegQueryMultipleValues", "RegQueryMultipleValuesA", "RegQueryMultipleValuesW"
|
||||
]) and
|
||||
paramType = TReturnData() and
|
||||
param = source.getArgument(3)
|
||||
or
|
||||
// LONG WINAPI RegQueryValueEx(
|
||||
// _In_ HKEY hKey,
|
||||
// _In_opt_ LPCTSTR lpValueName,
|
||||
// _Reserved_ LPDWORD lpReserved,
|
||||
// _Out_opt_ LPDWORD lpType,
|
||||
// _Out_opt_ LPBYTE lpData,
|
||||
// _Inout_opt_ LPDWORD lpcbData
|
||||
// );
|
||||
source.getTarget().hasGlobalName(["RegQueryValueEx", "RegQueryValueExA", "RegQueryValueExW"]) and
|
||||
(
|
||||
paramType = TValueName() and param = source.getArgument(1)
|
||||
or
|
||||
paramType = TReturnData() and param = source.getArgument(4)
|
||||
)
|
||||
or
|
||||
// LONG WINAPI RegGetValue(
|
||||
// _In_ HKEY hkey,
|
||||
// _In_opt_ LPCTSTR lpSubKey,
|
||||
// _In_opt_ LPCTSTR lpValue,
|
||||
// _In_opt_ DWORD dwFlags,
|
||||
// _Out_opt_ LPDWORD pdwType,
|
||||
// _Out_opt_ PVOID pvData,
|
||||
// _Inout_opt_ LPDWORD pcbData
|
||||
// );
|
||||
source.getTarget().hasGlobalName(["RegGetValue", "RegGetValueA", "RegGetValueW"]) and
|
||||
(
|
||||
paramType = TSubKeyName() and param = source.getArgument(1)
|
||||
or
|
||||
paramType = TValueName() and param = source.getArgument(2)
|
||||
or
|
||||
paramType = TReturnData() and param = source.getArgument(5)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Data read from the Windows registry.
|
||||
*/
|
||||
class RegQuery extends SystemData {
|
||||
RegQuery() { regQuery(this, _, _) }
|
||||
|
||||
override DataFlow::Node getAnExpr() { regQuery(this, TReturnData(), result.asDefiningArgument()) }
|
||||
|
||||
override predicate isSensitive() {
|
||||
exists(Expr e |
|
||||
(
|
||||
regQuery(this, TSubKeyName(), e) or
|
||||
regQuery(this, TValueName(), e)
|
||||
) and
|
||||
e.getValue().toLowerCase().regexpMatch(".*(pass|token|key).*")
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* A new query, "Potential exposure of sensitive system data to an unauthorized control sphere" (`cpp/potential-system-data-exposure`) has been added. This query is focused on exposure of information that is highly likely to be sensitive, whereas the similar query "Exposure of system data to an unauthorized control sphere" (`cpp/system-data-exposure`) is focused on exposure of information on a channel that is more likely to be intercepted by an attacker.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The `cpp/command-line-injection` query now takes into account calling contexts across string concatenations. This removes false positives due to mismatched calling contexts before and after string concatenations.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The `cpp/unused-local-variable` no longer ignores functions that include lambda expressions capturing trivially copyable objects.
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The `cpp/cleartext-transmission` query now recognizes additional sources, for sensitive private data such as e-mail addresses and credit card numbers.
|
||||
@@ -3,4 +3,3 @@
|
||||
- apply: code-scanning-selectors.yml
|
||||
from: codeql/suite-helpers
|
||||
- apply: codeql-suites/exclude-slow-queries.yml
|
||||
from: codeql/cpp-queries
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
- apply: lgtm-selectors.yml
|
||||
from: codeql/suite-helpers
|
||||
- apply: codeql-suites/exclude-slow-queries.yml
|
||||
from: codeql/cpp-queries
|
||||
# These are only for IDE use.
|
||||
- exclude:
|
||||
tags contain:
|
||||
|
||||
@@ -3,4 +3,3 @@
|
||||
- apply: security-and-quality-selectors.yml
|
||||
from: codeql/suite-helpers
|
||||
- apply: codeql-suites/exclude-slow-queries.yml
|
||||
from: codeql/cpp-queries
|
||||
|
||||
@@ -3,4 +3,3 @@
|
||||
- apply: security-extended-selectors.yml
|
||||
from: codeql/suite-helpers
|
||||
- apply: codeql-suites/exclude-slow-queries.yml
|
||||
from: codeql/cpp-queries
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
/**
|
||||
* @name Linux kernel no check before unsafe_put_user vulnerability detection
|
||||
* @description unsafe_put_user which is used to write data to user-mode
|
||||
* memory is widely used in Linux kernel codebase, but if
|
||||
* there is no security check for user-mode pointer used as
|
||||
* parameter of unsafe_put_user, attacker can exploit the issue
|
||||
* to obtain root privilege. CVE-2017-5123 is quite a good
|
||||
* example for your information.
|
||||
* @kind problem
|
||||
* @id cpp/linux-kernel-no-check-before-unsafe-put-user
|
||||
* @problem.severity warning
|
||||
* @security-severity 7.5
|
||||
* @tags security
|
||||
* external/cwe/cwe-020
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.dataflow.DataFlow
|
||||
|
||||
class WriteAccessCheckMacro extends Macro {
|
||||
VariableAccess va;
|
||||
|
||||
WriteAccessCheckMacro() {
|
||||
this.getName() = ["user_write_access_begin", "user_access_begin"] and
|
||||
va.getEnclosingElement() = this.getAnInvocation().getAnExpandedElement()
|
||||
}
|
||||
|
||||
VariableAccess getArgument() { result = va }
|
||||
}
|
||||
|
||||
class UnSafePutUserMacro extends Macro {
|
||||
PointerDereferenceExpr writeUserPtr;
|
||||
|
||||
UnSafePutUserMacro() {
|
||||
this.getName() = "unsafe_put_user" and
|
||||
writeUserPtr.getEnclosingElement() = this.getAnInvocation().getAnExpandedElement()
|
||||
}
|
||||
|
||||
Expr getUserModePtr() {
|
||||
result = writeUserPtr.getOperand().(AddressOfExpr).getOperand().(FieldAccess).getQualifier()
|
||||
}
|
||||
}
|
||||
|
||||
class ExploitableUserModePtrParam extends Parameter {
|
||||
ExploitableUserModePtrParam() {
|
||||
not exists(WriteAccessCheckMacro writeAccessCheck |
|
||||
DataFlow::localFlow(DataFlow::parameterNode(this),
|
||||
DataFlow::exprNode(writeAccessCheck.getArgument()))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
from ExploitableUserModePtrParam p, UnSafePutUserMacro unsafePutUser
|
||||
where
|
||||
DataFlow::localFlow(DataFlow::parameterNode(p), DataFlow::exprNode(unsafePutUser.getUserModePtr()))
|
||||
select p, "unsafe_put_user write user-mode pointer $@ without check.", p, p.toString()
|
||||
46
cpp/ql/src/experimental/Security/CWE/CWE-362/double-fetch.ql
Normal file
46
cpp/ql/src/experimental/Security/CWE/CWE-362/double-fetch.ql
Normal file
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* @name Linux kernel double-fetch vulnerability detection
|
||||
* @description Double-fetch is a very common vulnerability pattern
|
||||
* in linux kernel, attacker can exploit double-fetch
|
||||
* issues to obatain root privilege.
|
||||
* Double-fetch is caused by fetching data from user
|
||||
* mode by calling copy_from_user twice, CVE-2016-6480
|
||||
* is quite a good example for your information.
|
||||
* @kind problem
|
||||
* @id cpp/linux-kernel-double-fetch-vulnerability
|
||||
* @problem.severity warning
|
||||
* @security-severity 7.5
|
||||
* @tags security
|
||||
* external/cwe/cwe-362
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
|
||||
|
||||
class CopyFromUserFunctionCall extends FunctionCall {
|
||||
CopyFromUserFunctionCall() {
|
||||
this.getTarget().getName() = "copy_from_user" and
|
||||
not this.getArgument(1) instanceof AddressOfExpr
|
||||
}
|
||||
|
||||
//root cause of double-fetech issue is read from
|
||||
//the same user mode memory twice, so it makes
|
||||
//sense that only check user mode pointer
|
||||
predicate readFromSameUserModePointer(CopyFromUserFunctionCall another) {
|
||||
globalValueNumber(this.getArgument(1)) = globalValueNumber(another.getArgument(1))
|
||||
}
|
||||
}
|
||||
|
||||
from CopyFromUserFunctionCall p1, CopyFromUserFunctionCall p2
|
||||
where
|
||||
not p1 = p2 and
|
||||
p1.readFromSameUserModePointer(p2) and
|
||||
exists(IfStmt ifStmt |
|
||||
p1.getBasicBlock().getAFalseSuccessor*() = ifStmt.getBasicBlock() and
|
||||
ifStmt.getBasicBlock().getAFalseSuccessor*() = p2.getBasicBlock()
|
||||
) and
|
||||
not exists(AssignPointerAddExpr assignPtrAdd |
|
||||
globalValueNumber(p1.getArgument(1)) = globalValueNumber(assignPtrAdd.getLValue()) and
|
||||
p1.getBasicBlock().getAFalseSuccessor*() = assignPtrAdd.getBasicBlock()
|
||||
)
|
||||
select p2, "Double fetch vulnerability. First fetch was $@.", p1, p1.toString()
|
||||
@@ -208,11 +208,16 @@ postWithInFlow
|
||||
| lambdas.cpp:13:7:13:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| lambdas.cpp:13:10:17:2 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| lambdas.cpp:13:10:17:2 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| lambdas.cpp:13:11:13:11 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| lambdas.cpp:13:11:13:11 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| lambdas.cpp:16:3:16:11 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| lambdas.cpp:20:7:20:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| lambdas.cpp:20:10:24:2 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| lambdas.cpp:20:10:24:2 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| lambdas.cpp:20:10:24:2 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| lambdas.cpp:20:11:20:11 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| lambdas.cpp:20:11:20:11 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| lambdas.cpp:20:11:20:11 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| lambdas.cpp:23:3:23:3 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| lambdas.cpp:23:3:23:14 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| lambdas.cpp:23:3:23:14 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
@@ -220,6 +225,8 @@ postWithInFlow
|
||||
| lambdas.cpp:28:7:28:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| lambdas.cpp:28:10:31:2 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| lambdas.cpp:28:10:31:2 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| lambdas.cpp:28:11:28:11 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| lambdas.cpp:28:11:28:11 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| lambdas.cpp:34:7:34:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| lambdas.cpp:34:13:34:13 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| lambdas.cpp:40:7:40:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
|
||||
@@ -27,7 +27,8 @@
|
||||
| arrayassignment.cpp:29:8:29:13 | call to source | arrayassignment.cpp:29:2:29:15 | ... = ... | |
|
||||
| arrayassignment.cpp:29:8:29:13 | call to source | arrayassignment.cpp:33:7:33:9 | r_x | |
|
||||
| arrayassignment.cpp:32:8:32:10 | p_x | arrayassignment.cpp:32:7:32:10 | * ... | TAINT |
|
||||
| arrayassignment.cpp:37:7:37:7 | Unknown literal | arrayassignment.cpp:37:7:37:7 | constructor init of field i | TAINT |
|
||||
| arrayassignment.cpp:37:7:37:7 | i | arrayassignment.cpp:37:7:37:7 | constructor init of field i | TAINT |
|
||||
| arrayassignment.cpp:37:7:37:7 | i | arrayassignment.cpp:37:7:37:7 | i | |
|
||||
| arrayassignment.cpp:37:7:37:7 | this | arrayassignment.cpp:37:7:37:7 | constructor init of field i [pre-this] | |
|
||||
| arrayassignment.cpp:40:2:40:6 | this | arrayassignment.cpp:40:12:40:15 | constructor init of field i [pre-this] | |
|
||||
| arrayassignment.cpp:40:12:40:15 | 0 | arrayassignment.cpp:40:12:40:15 | constructor init of field i | TAINT |
|
||||
@@ -284,6 +285,7 @@
|
||||
| copyableclass_declonly.cpp:67:13:67:18 | call to source | copyableclass_declonly.cpp:67:13:67:20 | call to MyCopyableClassDeclOnly | TAINT |
|
||||
| copyableclass_declonly.cpp:67:13:67:20 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:67:8:67:9 | ref arg s3 | TAINT |
|
||||
| copyableclass_declonly.cpp:67:13:67:20 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:67:11:67:11 | call to operator= | TAINT |
|
||||
| file://:0:0:0:0 | (unnamed parameter 0) | arrayassignment.cpp:37:7:37:7 | (unnamed parameter 0) | |
|
||||
| file://:0:0:0:0 | (unnamed parameter 0) | file://:0:0:0:0 | (unnamed parameter 0) | |
|
||||
| file://:0:0:0:0 | (unnamed parameter 0) | file://:0:0:0:0 | (unnamed parameter 0) | |
|
||||
| file://:0:0:0:0 | (unnamed parameter 0) | file://:0:0:0:0 | (unnamed parameter 0) | |
|
||||
@@ -299,6 +301,27 @@
|
||||
| file://:0:0:0:0 | (unnamed parameter 0) | file://:0:0:0:0 | (unnamed parameter 0) | |
|
||||
| file://:0:0:0:0 | (unnamed parameter 0) | file://:0:0:0:0 | (unnamed parameter 0) | |
|
||||
| file://:0:0:0:0 | (unnamed parameter 0) | file://:0:0:0:0 | (unnamed parameter 0) | |
|
||||
| file://:0:0:0:0 | (unnamed parameter 0) | stl.h:75:8:75:8 | (unnamed parameter 0) | |
|
||||
| file://:0:0:0:0 | (unnamed parameter 0) | stl.h:75:8:75:8 | (unnamed parameter 0) | |
|
||||
| file://:0:0:0:0 | (unnamed parameter 0) | stl.h:389:9:389:9 | (unnamed parameter 0) | |
|
||||
| file://:0:0:0:0 | (unnamed parameter 0) | stl.h:389:9:389:9 | (unnamed parameter 0) | |
|
||||
| file://:0:0:0:0 | (unnamed parameter 0) | stl.h:389:9:389:9 | (unnamed parameter 0) | |
|
||||
| file://:0:0:0:0 | (unnamed parameter 0) | stl.h:389:9:389:9 | (unnamed parameter 0) | |
|
||||
| file://:0:0:0:0 | (unnamed parameter 0) | stl.h:389:9:389:9 | (unnamed parameter 0) | |
|
||||
| file://:0:0:0:0 | (unnamed parameter 0) | stl.h:389:9:389:9 | (unnamed parameter 0) | |
|
||||
| file://:0:0:0:0 | (unnamed parameter 0) | stl.h:389:9:389:9 | (unnamed parameter 0) | |
|
||||
| file://:0:0:0:0 | (unnamed parameter 0) | stl.h:389:9:389:9 | (unnamed parameter 0) | |
|
||||
| file://:0:0:0:0 | (unnamed parameter 0) | stl.h:389:9:389:9 | (unnamed parameter 0) | |
|
||||
| file://:0:0:0:0 | (unnamed parameter 0) | stl.h:389:9:389:9 | (unnamed parameter 0) | |
|
||||
| file://:0:0:0:0 | (unnamed parameter 0) | structlikeclass.cpp:5:7:5:7 | (unnamed parameter 0) | |
|
||||
| file://:0:0:0:0 | (unnamed parameter 0) | structlikeclass.cpp:5:7:5:7 | (unnamed parameter 0) | |
|
||||
| file://:0:0:0:0 | (unnamed parameter 0) | taint.cpp:228:11:228:11 | (unnamed parameter 0) | |
|
||||
| file://:0:0:0:0 | (unnamed parameter 0) | taint.cpp:228:11:228:11 | (unnamed parameter 0) | |
|
||||
| file://:0:0:0:0 | (unnamed parameter 0) | taint.cpp:235:11:235:11 | (unnamed parameter 0) | |
|
||||
| file://:0:0:0:0 | (unnamed parameter 0) | taint.cpp:235:11:235:11 | (unnamed parameter 0) | |
|
||||
| file://:0:0:0:0 | (unnamed parameter 0) | taint.cpp:235:11:235:11 | (unnamed parameter 0) | |
|
||||
| file://:0:0:0:0 | (unnamed parameter 0) | taint.cpp:243:11:243:11 | (unnamed parameter 0) | |
|
||||
| file://:0:0:0:0 | (unnamed parameter 0) | taint.cpp:243:11:243:11 | (unnamed parameter 0) | |
|
||||
| format.cpp:16:21:16:21 | s | format.cpp:16:21:16:21 | s | |
|
||||
| format.cpp:16:21:16:21 | s | format.cpp:22:22:22:22 | s | |
|
||||
| format.cpp:16:31:16:31 | n | format.cpp:22:25:22:25 | n | |
|
||||
@@ -3554,8 +3577,10 @@
|
||||
| standalone_iterators.cpp:120:2:120:3 | it | standalone_iterators.cpp:120:5:120:5 | call to operator+= | TAINT |
|
||||
| standalone_iterators.cpp:120:2:120:3 | ref arg it | standalone_iterators.cpp:121:7:121:8 | it | |
|
||||
| standalone_iterators.cpp:120:8:120:13 | call to source | standalone_iterators.cpp:120:2:120:3 | ref arg it | TAINT |
|
||||
| stl.h:75:8:75:8 | Unknown literal | stl.h:75:8:75:8 | constructor init of field container | TAINT |
|
||||
| stl.h:75:8:75:8 | Unknown literal | stl.h:75:8:75:8 | constructor init of field container | TAINT |
|
||||
| stl.h:75:8:75:8 | container | stl.h:75:8:75:8 | constructor init of field container | TAINT |
|
||||
| stl.h:75:8:75:8 | container | stl.h:75:8:75:8 | constructor init of field container | TAINT |
|
||||
| stl.h:75:8:75:8 | container | stl.h:75:8:75:8 | container | |
|
||||
| stl.h:75:8:75:8 | container | stl.h:75:8:75:8 | container | |
|
||||
| stl.h:75:8:75:8 | this | stl.h:75:8:75:8 | constructor init of field container [pre-this] | |
|
||||
| stl.h:75:8:75:8 | this | stl.h:75:8:75:8 | constructor init of field container [pre-this] | |
|
||||
| stl.h:95:69:95:69 | x | stl.h:95:69:95:69 | x | |
|
||||
@@ -3573,16 +3598,6 @@
|
||||
| stl.h:292:30:292:40 | call to allocator | stl.h:292:21:292:41 | noexcept(...) | TAINT |
|
||||
| stl.h:292:30:292:40 | call to allocator | stl.h:292:21:292:41 | noexcept(...) | TAINT |
|
||||
| stl.h:292:53:292:63 | 0 | stl.h:292:46:292:64 | (no string representation) | TAINT |
|
||||
| stl.h:389:9:389:9 | Unknown literal | stl.h:389:9:389:9 | constructor init of field first | TAINT |
|
||||
| stl.h:389:9:389:9 | Unknown literal | stl.h:389:9:389:9 | constructor init of field first | TAINT |
|
||||
| stl.h:389:9:389:9 | Unknown literal | stl.h:389:9:389:9 | constructor init of field first | TAINT |
|
||||
| stl.h:389:9:389:9 | Unknown literal | stl.h:389:9:389:9 | constructor init of field first | TAINT |
|
||||
| stl.h:389:9:389:9 | Unknown literal | stl.h:389:9:389:9 | constructor init of field first | TAINT |
|
||||
| stl.h:389:9:389:9 | Unknown literal | stl.h:389:9:389:9 | constructor init of field second | TAINT |
|
||||
| stl.h:389:9:389:9 | Unknown literal | stl.h:389:9:389:9 | constructor init of field second | TAINT |
|
||||
| stl.h:389:9:389:9 | Unknown literal | stl.h:389:9:389:9 | constructor init of field second | TAINT |
|
||||
| stl.h:389:9:389:9 | Unknown literal | stl.h:389:9:389:9 | constructor init of field second | TAINT |
|
||||
| stl.h:389:9:389:9 | Unknown literal | stl.h:389:9:389:9 | constructor init of field second | TAINT |
|
||||
| stl.h:389:9:389:9 | constructor init of field first [post-this] | stl.h:389:9:389:9 | constructor init of field second [pre-this] | |
|
||||
| stl.h:389:9:389:9 | constructor init of field first [post-this] | stl.h:389:9:389:9 | constructor init of field second [pre-this] | |
|
||||
| stl.h:389:9:389:9 | constructor init of field first [post-this] | stl.h:389:9:389:9 | constructor init of field second [pre-this] | |
|
||||
@@ -3593,6 +3608,26 @@
|
||||
| stl.h:389:9:389:9 | constructor init of field first [pre-this] | stl.h:389:9:389:9 | constructor init of field second [pre-this] | |
|
||||
| stl.h:389:9:389:9 | constructor init of field first [pre-this] | stl.h:389:9:389:9 | constructor init of field second [pre-this] | |
|
||||
| stl.h:389:9:389:9 | constructor init of field first [pre-this] | stl.h:389:9:389:9 | constructor init of field second [pre-this] | |
|
||||
| stl.h:389:9:389:9 | first | stl.h:389:9:389:9 | constructor init of field first | TAINT |
|
||||
| stl.h:389:9:389:9 | first | stl.h:389:9:389:9 | constructor init of field first | TAINT |
|
||||
| stl.h:389:9:389:9 | first | stl.h:389:9:389:9 | constructor init of field first | TAINT |
|
||||
| stl.h:389:9:389:9 | first | stl.h:389:9:389:9 | constructor init of field first | TAINT |
|
||||
| stl.h:389:9:389:9 | first | stl.h:389:9:389:9 | constructor init of field first | TAINT |
|
||||
| stl.h:389:9:389:9 | first | stl.h:389:9:389:9 | first | |
|
||||
| stl.h:389:9:389:9 | first | stl.h:389:9:389:9 | first | |
|
||||
| stl.h:389:9:389:9 | first | stl.h:389:9:389:9 | first | |
|
||||
| stl.h:389:9:389:9 | first | stl.h:389:9:389:9 | first | |
|
||||
| stl.h:389:9:389:9 | first | stl.h:389:9:389:9 | first | |
|
||||
| stl.h:389:9:389:9 | second | stl.h:389:9:389:9 | constructor init of field second | TAINT |
|
||||
| stl.h:389:9:389:9 | second | stl.h:389:9:389:9 | constructor init of field second | TAINT |
|
||||
| stl.h:389:9:389:9 | second | stl.h:389:9:389:9 | constructor init of field second | TAINT |
|
||||
| stl.h:389:9:389:9 | second | stl.h:389:9:389:9 | constructor init of field second | TAINT |
|
||||
| stl.h:389:9:389:9 | second | stl.h:389:9:389:9 | constructor init of field second | TAINT |
|
||||
| stl.h:389:9:389:9 | second | stl.h:389:9:389:9 | second | |
|
||||
| stl.h:389:9:389:9 | second | stl.h:389:9:389:9 | second | |
|
||||
| stl.h:389:9:389:9 | second | stl.h:389:9:389:9 | second | |
|
||||
| stl.h:389:9:389:9 | second | stl.h:389:9:389:9 | second | |
|
||||
| stl.h:389:9:389:9 | second | stl.h:389:9:389:9 | second | |
|
||||
| stl.h:389:9:389:9 | this | stl.h:389:9:389:9 | constructor init of field first [pre-this] | |
|
||||
| stl.h:389:9:389:9 | this | stl.h:389:9:389:9 | constructor init of field first [pre-this] | |
|
||||
| stl.h:389:9:389:9 | this | stl.h:389:9:389:9 | constructor init of field first [pre-this] | |
|
||||
@@ -5354,10 +5389,12 @@
|
||||
| stringstream.cpp:266:54:266:58 | ref arg call to flush | stringstream.cpp:266:35:266:39 | ref arg call to write | TAINT |
|
||||
| stringstream.cpp:266:68:266:72 | xyz | stringstream.cpp:266:54:266:58 | ref arg call to flush | TAINT |
|
||||
| stringstream.cpp:266:68:266:72 | xyz | stringstream.cpp:266:62:266:66 | call to write | TAINT |
|
||||
| structlikeclass.cpp:5:7:5:7 | Unknown literal | structlikeclass.cpp:5:7:5:7 | constructor init of field v | TAINT |
|
||||
| structlikeclass.cpp:5:7:5:7 | Unknown literal | structlikeclass.cpp:5:7:5:7 | constructor init of field v | TAINT |
|
||||
| structlikeclass.cpp:5:7:5:7 | this | structlikeclass.cpp:5:7:5:7 | constructor init of field v [pre-this] | |
|
||||
| structlikeclass.cpp:5:7:5:7 | this | structlikeclass.cpp:5:7:5:7 | constructor init of field v [pre-this] | |
|
||||
| structlikeclass.cpp:5:7:5:7 | v | structlikeclass.cpp:5:7:5:7 | constructor init of field v | TAINT |
|
||||
| structlikeclass.cpp:5:7:5:7 | v | structlikeclass.cpp:5:7:5:7 | constructor init of field v | TAINT |
|
||||
| structlikeclass.cpp:5:7:5:7 | v | structlikeclass.cpp:5:7:5:7 | v | |
|
||||
| structlikeclass.cpp:5:7:5:7 | v | structlikeclass.cpp:5:7:5:7 | v | |
|
||||
| structlikeclass.cpp:8:2:8:16 | this | structlikeclass.cpp:8:28:8:32 | constructor init of field v [pre-this] | |
|
||||
| structlikeclass.cpp:8:22:8:23 | _v | structlikeclass.cpp:8:30:8:31 | _v | |
|
||||
| structlikeclass.cpp:8:30:8:31 | _v | structlikeclass.cpp:8:28:8:32 | constructor init of field v | TAINT |
|
||||
@@ -5973,24 +6010,29 @@
|
||||
| taint.cpp:226:9:226:10 | 0 | taint.cpp:261:7:261:7 | w | |
|
||||
| taint.cpp:228:10:232:2 | [...](...){...} | taint.cpp:233:7:233:7 | a | |
|
||||
| taint.cpp:228:10:232:2 | {...} | taint.cpp:228:10:232:2 | [...](...){...} | |
|
||||
| taint.cpp:228:11:228:11 | Unknown literal | taint.cpp:228:11:228:11 | constructor init of field t | TAINT |
|
||||
| taint.cpp:228:11:228:11 | Unknown literal | taint.cpp:228:11:228:11 | constructor init of field u | TAINT |
|
||||
| taint.cpp:228:11:228:11 | constructor init of field t [post-this] | taint.cpp:228:11:228:11 | constructor init of field u [pre-this] | |
|
||||
| taint.cpp:228:11:228:11 | constructor init of field t [pre-this] | taint.cpp:228:11:228:11 | constructor init of field u [pre-this] | |
|
||||
| taint.cpp:228:11:228:11 | t | taint.cpp:228:11:228:11 | constructor init of field t | TAINT |
|
||||
| taint.cpp:228:11:228:11 | t | taint.cpp:228:11:228:11 | t | |
|
||||
| taint.cpp:228:11:228:11 | this | taint.cpp:228:11:228:11 | constructor init of field t [pre-this] | |
|
||||
| taint.cpp:228:11:228:11 | u | taint.cpp:228:11:228:11 | constructor init of field u | TAINT |
|
||||
| taint.cpp:228:11:228:11 | u | taint.cpp:228:11:228:11 | u | |
|
||||
| taint.cpp:228:17:228:17 | this | taint.cpp:229:3:229:6 | this | |
|
||||
| taint.cpp:229:3:229:6 | this | taint.cpp:230:3:230:6 | this | |
|
||||
| taint.cpp:230:3:230:6 | this | file://:0:0:0:0 | this | |
|
||||
| taint.cpp:235:10:239:2 | [...](...){...} | taint.cpp:240:2:240:2 | b | |
|
||||
| taint.cpp:235:10:239:2 | {...} | taint.cpp:235:10:239:2 | [...](...){...} | |
|
||||
| taint.cpp:235:11:235:11 | Unknown literal | taint.cpp:235:11:235:11 | constructor init of field t | TAINT |
|
||||
| taint.cpp:235:11:235:11 | Unknown literal | taint.cpp:235:11:235:11 | constructor init of field u | TAINT |
|
||||
| taint.cpp:235:11:235:11 | Unknown literal | taint.cpp:235:11:235:11 | constructor init of field v | TAINT |
|
||||
| taint.cpp:235:11:235:11 | constructor init of field t [post-this] | taint.cpp:235:11:235:11 | constructor init of field u [pre-this] | |
|
||||
| taint.cpp:235:11:235:11 | constructor init of field t [pre-this] | taint.cpp:235:11:235:11 | constructor init of field u [pre-this] | |
|
||||
| taint.cpp:235:11:235:11 | constructor init of field u [post-this] | taint.cpp:235:11:235:11 | constructor init of field v [pre-this] | |
|
||||
| taint.cpp:235:11:235:11 | constructor init of field u [pre-this] | taint.cpp:235:11:235:11 | constructor init of field v [pre-this] | |
|
||||
| taint.cpp:235:11:235:11 | t | taint.cpp:235:11:235:11 | constructor init of field t | TAINT |
|
||||
| taint.cpp:235:11:235:11 | t | taint.cpp:235:11:235:11 | t | |
|
||||
| taint.cpp:235:11:235:11 | this | taint.cpp:235:11:235:11 | constructor init of field t [pre-this] | |
|
||||
| taint.cpp:235:11:235:11 | u | taint.cpp:235:11:235:11 | constructor init of field u | TAINT |
|
||||
| taint.cpp:235:11:235:11 | u | taint.cpp:235:11:235:11 | u | |
|
||||
| taint.cpp:235:11:235:11 | v | taint.cpp:235:11:235:11 | constructor init of field v | TAINT |
|
||||
| taint.cpp:235:11:235:11 | v | taint.cpp:235:11:235:11 | v | |
|
||||
| taint.cpp:235:15:235:15 | this | taint.cpp:236:3:236:6 | this | |
|
||||
| taint.cpp:236:3:236:6 | this | taint.cpp:237:3:237:6 | this | |
|
||||
| taint.cpp:237:3:237:6 | this | taint.cpp:238:3:238:14 | this | |
|
||||
@@ -5998,11 +6040,13 @@
|
||||
| taint.cpp:238:7:238:12 | call to source | taint.cpp:238:3:238:14 | ... = ... | |
|
||||
| taint.cpp:243:10:246:2 | [...](...){...} | taint.cpp:247:2:247:2 | c | |
|
||||
| taint.cpp:243:10:246:2 | {...} | taint.cpp:243:10:246:2 | [...](...){...} | |
|
||||
| taint.cpp:243:11:243:11 | Unknown literal | taint.cpp:243:11:243:11 | constructor init of field t | TAINT |
|
||||
| taint.cpp:243:11:243:11 | Unknown literal | taint.cpp:243:11:243:11 | constructor init of field u | TAINT |
|
||||
| taint.cpp:243:11:243:11 | constructor init of field t [post-this] | taint.cpp:243:11:243:11 | constructor init of field u [pre-this] | |
|
||||
| taint.cpp:243:11:243:11 | constructor init of field t [pre-this] | taint.cpp:243:11:243:11 | constructor init of field u [pre-this] | |
|
||||
| taint.cpp:243:11:243:11 | t | taint.cpp:243:11:243:11 | constructor init of field t | TAINT |
|
||||
| taint.cpp:243:11:243:11 | t | taint.cpp:243:11:243:11 | t | |
|
||||
| taint.cpp:243:11:243:11 | this | taint.cpp:243:11:243:11 | constructor init of field t [pre-this] | |
|
||||
| taint.cpp:243:11:243:11 | u | taint.cpp:243:11:243:11 | constructor init of field u | TAINT |
|
||||
| taint.cpp:243:11:243:11 | u | taint.cpp:243:11:243:11 | u | |
|
||||
| taint.cpp:243:15:243:15 | this | taint.cpp:244:3:244:6 | this | |
|
||||
| taint.cpp:244:3:244:6 | this | taint.cpp:245:3:245:6 | this | |
|
||||
| taint.cpp:249:11:252:2 | [...](...){...} | taint.cpp:253:2:253:2 | d | |
|
||||
|
||||
@@ -12,8 +12,12 @@
|
||||
| addressOf.cpp:40:15:40:15 | i | non-const address |
|
||||
| addressOf.cpp:42:19:42:22 | iref | non-const address |
|
||||
| addressOf.cpp:47:12:47:31 | captured | non-const address |
|
||||
| addressOf.cpp:47:13:47:13 | (unnamed parameter 0) | |
|
||||
| addressOf.cpp:47:13:47:13 | captured | |
|
||||
| addressOf.cpp:47:19:47:28 | captured | |
|
||||
| addressOf.cpp:48:3:48:4 | f1 | const address |
|
||||
| addressOf.cpp:49:13:49:13 | (unnamed parameter 0) | |
|
||||
| addressOf.cpp:49:13:49:13 | captured | |
|
||||
| addressOf.cpp:49:15:49:22 | captured | non-const address |
|
||||
| addressOf.cpp:49:27:49:36 | captured | |
|
||||
| addressOf.cpp:50:3:50:4 | f2 | const address |
|
||||
@@ -245,6 +249,10 @@
|
||||
| test.cpp:173:19:173:19 | x | const address |
|
||||
| test.cpp:174:20:174:20 | x | const address |
|
||||
| test.cpp:175:7:175:7 | x | |
|
||||
| test.cpp:178:8:178:8 | (unnamed parameter 0) | |
|
||||
| test.cpp:178:8:178:8 | (unnamed parameter 0) | |
|
||||
| test.cpp:178:8:178:8 | nested | |
|
||||
| test.cpp:178:8:178:8 | x_ | |
|
||||
| test.cpp:183:38:183:41 | yptr | |
|
||||
| test.cpp:183:48:183:48 | z | |
|
||||
| test.cpp:184:28:184:35 | static_y | non-const address |
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
| addressOf.cpp:61:33:61:35 | ref | addressOf.cpp:63:24:63:26 | ref |
|
||||
| addressOf.cpp:70:29:70:31 | obj | addressOf.cpp:71:32:71:34 | obj |
|
||||
| addressOf.cpp:70:29:70:31 | obj | addressOf.cpp:71:32:71:34 | obj |
|
||||
| file://:0:0:0:0 | (unnamed parameter 0) | addressOf.cpp:47:13:47:13 | (unnamed parameter 0) |
|
||||
| file://:0:0:0:0 | (unnamed parameter 0) | addressOf.cpp:49:13:49:13 | (unnamed parameter 0) |
|
||||
| file://:0:0:0:0 | (unnamed parameter 0) | test.cpp:178:8:178:8 | (unnamed parameter 0) |
|
||||
| file://:0:0:0:0 | (unnamed parameter 0) | test.cpp:178:8:178:8 | (unnamed parameter 0) |
|
||||
| indirect_use.cpp:19:31:19:32 | ip | indirect_use.cpp:20:14:20:15 | ip |
|
||||
| indirect_use.cpp:24:31:24:32 | ip | indirect_use.cpp:25:14:25:15 | ip |
|
||||
| indirect_use.cpp:30:28:30:30 | ppp | indirect_use.cpp:31:19:31:21 | ppp |
|
||||
|
||||
@@ -26,6 +26,10 @@
|
||||
| addressOf.cpp:70:29:70:31 | obj | addressOf.cpp:71:32:71:34 | obj |
|
||||
| addressOf.cpp:76:7:76:7 | x | addressOf.cpp:77:27:77:27 | x |
|
||||
| addressOf.cpp:76:7:76:7 | x | addressOf.cpp:77:48:77:48 | x |
|
||||
| file://:0:0:0:0 | (unnamed parameter 0) | addressOf.cpp:47:13:47:13 | (unnamed parameter 0) |
|
||||
| file://:0:0:0:0 | (unnamed parameter 0) | addressOf.cpp:49:13:49:13 | (unnamed parameter 0) |
|
||||
| file://:0:0:0:0 | (unnamed parameter 0) | test.cpp:178:8:178:8 | (unnamed parameter 0) |
|
||||
| file://:0:0:0:0 | (unnamed parameter 0) | test.cpp:178:8:178:8 | (unnamed parameter 0) |
|
||||
| indirect_use.cpp:19:31:19:32 | ip | indirect_use.cpp:20:14:20:15 | ip |
|
||||
| indirect_use.cpp:20:10:20:10 | p | indirect_use.cpp:21:17:21:17 | p |
|
||||
| indirect_use.cpp:24:31:24:32 | ip | indirect_use.cpp:25:14:25:15 | ip |
|
||||
|
||||
@@ -12,6 +12,10 @@
|
||||
| addressOf.cpp:61:23:61:25 | ptr | addressOf.cpp:63:19:63:21 | ptr |
|
||||
| addressOf.cpp:70:29:70:31 | obj | addressOf.cpp:71:32:71:34 | obj |
|
||||
| addressOf.cpp:76:7:76:7 | x | addressOf.cpp:77:48:77:48 | x |
|
||||
| file://:0:0:0:0 | (unnamed parameter 0) | addressOf.cpp:47:13:47:13 | (unnamed parameter 0) |
|
||||
| file://:0:0:0:0 | (unnamed parameter 0) | addressOf.cpp:49:13:49:13 | (unnamed parameter 0) |
|
||||
| file://:0:0:0:0 | (unnamed parameter 0) | test.cpp:178:8:178:8 | (unnamed parameter 0) |
|
||||
| file://:0:0:0:0 | (unnamed parameter 0) | test.cpp:178:8:178:8 | (unnamed parameter 0) |
|
||||
| indirect_use.cpp:19:31:19:32 | ip | indirect_use.cpp:20:14:20:15 | ip |
|
||||
| indirect_use.cpp:20:10:20:10 | p | indirect_use.cpp:21:17:21:17 | p |
|
||||
| indirect_use.cpp:24:31:24:32 | ip | indirect_use.cpp:25:14:25:15 | ip |
|
||||
|
||||
@@ -155,15 +155,27 @@ bad_asts.cpp:
|
||||
# 19| getInitializer(0): [ConstructorFieldInit] constructor init of field x
|
||||
# 19| Type = [IntType] int
|
||||
# 19| ValueCategory = prvalue
|
||||
# 19| getExpr(): [Literal] Unknown literal
|
||||
# 19| getExpr(): [ReferenceFieldAccess] x
|
||||
# 19| Type = [IntType] int
|
||||
# 19| ValueCategory = prvalue
|
||||
# 19| ValueCategory = prvalue(load)
|
||||
# 19| getQualifier(): [VariableAccess] (unnamed parameter 0)
|
||||
# 19| Type = [LValueReferenceType] const Point &
|
||||
# 19| ValueCategory = prvalue(load)
|
||||
# 19| getQualifier().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
|
||||
# 19| Type = [SpecifiedType] const Point
|
||||
# 19| ValueCategory = lvalue
|
||||
# 19| getInitializer(1): [ConstructorFieldInit] constructor init of field y
|
||||
# 19| Type = [IntType] int
|
||||
# 19| ValueCategory = prvalue
|
||||
# 19| getExpr(): [Literal] Unknown literal
|
||||
# 19| getExpr(): [ReferenceFieldAccess] y
|
||||
# 19| Type = [IntType] int
|
||||
# 19| ValueCategory = prvalue
|
||||
# 19| ValueCategory = prvalue(load)
|
||||
# 19| getQualifier(): [VariableAccess] (unnamed parameter 0)
|
||||
# 19| Type = [LValueReferenceType] const Point &
|
||||
# 19| ValueCategory = prvalue(load)
|
||||
# 19| getQualifier().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
|
||||
# 19| Type = [SpecifiedType] const Point
|
||||
# 19| ValueCategory = lvalue
|
||||
# 19| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 19| getStmt(0): [ReturnStmt] return ...
|
||||
# 19| [MoveConstructor] void Bad::Point::Point(Bad::Point&&)
|
||||
@@ -11645,51 +11657,99 @@ ir.cpp:
|
||||
# 1486| getInitializer(0): [ConstructorFieldInit] constructor init of field i
|
||||
# 1486| Type = [IntType] int
|
||||
# 1486| ValueCategory = prvalue
|
||||
# 1486| getExpr(): [Literal] Unknown literal
|
||||
# 1486| getExpr(): [ReferenceFieldAccess] i
|
||||
# 1486| Type = [IntType] int
|
||||
# 1486| ValueCategory = prvalue
|
||||
# 1486| ValueCategory = prvalue(load)
|
||||
# 1486| getQualifier(): [VariableAccess] (unnamed parameter 0)
|
||||
# 1486| Type = [LValueReferenceType] const StructuredBindingDataMemberStruct &
|
||||
# 1486| ValueCategory = prvalue(load)
|
||||
# 1486| getQualifier().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
|
||||
# 1486| Type = [SpecifiedType] const StructuredBindingDataMemberStruct
|
||||
# 1486| ValueCategory = lvalue
|
||||
# 1486| getInitializer(1): [ConstructorFieldInit] constructor init of field d
|
||||
# 1486| Type = [DoubleType] double
|
||||
# 1486| ValueCategory = prvalue
|
||||
# 1486| getExpr(): [Literal] Unknown literal
|
||||
# 1486| getExpr(): [ReferenceFieldAccess] d
|
||||
# 1486| Type = [DoubleType] double
|
||||
# 1486| ValueCategory = prvalue
|
||||
# 1486| ValueCategory = prvalue(load)
|
||||
# 1486| getQualifier(): [VariableAccess] (unnamed parameter 0)
|
||||
# 1486| Type = [LValueReferenceType] const StructuredBindingDataMemberStruct &
|
||||
# 1486| ValueCategory = prvalue(load)
|
||||
# 1486| getQualifier().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
|
||||
# 1486| Type = [SpecifiedType] const StructuredBindingDataMemberStruct
|
||||
# 1486| ValueCategory = lvalue
|
||||
# 1486| getInitializer(2): [ConstructorFieldInit] constructor init of field b
|
||||
# 1486| Type = [IntType] unsigned int
|
||||
# 1486| ValueCategory = prvalue
|
||||
# 1486| getExpr(): [Literal] Unknown literal
|
||||
# 1486| getExpr(): [ReferenceFieldAccess] b
|
||||
# 1486| Type = [IntType] unsigned int
|
||||
# 1486| ValueCategory = prvalue
|
||||
# 1486| ValueCategory = prvalue(load)
|
||||
# 1486| getQualifier(): [VariableAccess] (unnamed parameter 0)
|
||||
# 1486| Type = [LValueReferenceType] const StructuredBindingDataMemberStruct &
|
||||
# 1486| ValueCategory = prvalue(load)
|
||||
# 1486| getQualifier().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
|
||||
# 1486| Type = [SpecifiedType] const StructuredBindingDataMemberStruct
|
||||
# 1486| ValueCategory = lvalue
|
||||
# 1486| getInitializer(3): [ConstructorFieldInit] constructor init of field r
|
||||
# 1486| Type = [LValueReferenceType] int &
|
||||
# 1486| ValueCategory = prvalue
|
||||
# 1486| getExpr(): [Literal] Unknown literal
|
||||
# 1486| getExpr(): [ReferenceFieldAccess] r
|
||||
# 1486| Type = [LValueReferenceType] int &
|
||||
# 1486| ValueCategory = prvalue
|
||||
# 1486| ValueCategory = prvalue(load)
|
||||
# 1486| getQualifier(): [VariableAccess] (unnamed parameter 0)
|
||||
# 1486| Type = [LValueReferenceType] const StructuredBindingDataMemberStruct &
|
||||
# 1486| ValueCategory = prvalue(load)
|
||||
# 1486| getQualifier().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
|
||||
# 1486| Type = [SpecifiedType] const StructuredBindingDataMemberStruct
|
||||
# 1486| ValueCategory = lvalue
|
||||
# 1486| getInitializer(4): [ConstructorFieldInit] constructor init of field p
|
||||
# 1486| Type = [IntPointerType] int *
|
||||
# 1486| ValueCategory = prvalue
|
||||
# 1486| getExpr(): [Literal] Unknown literal
|
||||
# 1486| getExpr(): [ReferenceFieldAccess] p
|
||||
# 1486| Type = [IntPointerType] int *
|
||||
# 1486| ValueCategory = prvalue
|
||||
# 1486| ValueCategory = prvalue(load)
|
||||
# 1486| getQualifier(): [VariableAccess] (unnamed parameter 0)
|
||||
# 1486| Type = [LValueReferenceType] const StructuredBindingDataMemberStruct &
|
||||
# 1486| ValueCategory = prvalue(load)
|
||||
# 1486| getQualifier().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
|
||||
# 1486| Type = [SpecifiedType] const StructuredBindingDataMemberStruct
|
||||
# 1486| ValueCategory = lvalue
|
||||
# 1486| getInitializer(5): [ConstructorFieldInit] constructor init of field xs
|
||||
# 1486| Type = [CTypedefType,NestedTypedefType] ArrayType
|
||||
# 1486| ValueCategory = prvalue
|
||||
# 1486| getExpr(): [Literal] Unknown literal
|
||||
# 1486| getExpr(): [ReferenceFieldAccess] xs
|
||||
# 1486| Type = [CTypedefType,NestedTypedefType] ArrayType
|
||||
# 1486| ValueCategory = prvalue
|
||||
# 1486| ValueCategory = prvalue(load)
|
||||
# 1486| getQualifier(): [VariableAccess] (unnamed parameter 0)
|
||||
# 1486| Type = [LValueReferenceType] const StructuredBindingDataMemberStruct &
|
||||
# 1486| ValueCategory = prvalue(load)
|
||||
# 1486| getQualifier().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
|
||||
# 1486| Type = [SpecifiedType] const StructuredBindingDataMemberStruct
|
||||
# 1486| ValueCategory = lvalue
|
||||
# 1486| getInitializer(6): [ConstructorFieldInit] constructor init of field r_alt
|
||||
# 1486| Type = [CTypedefType,NestedTypedefType] RefType
|
||||
# 1486| ValueCategory = prvalue
|
||||
# 1486| getExpr(): [Literal] Unknown literal
|
||||
# 1486| getExpr(): [ReferenceFieldAccess] r_alt
|
||||
# 1486| Type = [CTypedefType,NestedTypedefType] RefType
|
||||
# 1486| ValueCategory = prvalue
|
||||
# 1486| ValueCategory = prvalue(load)
|
||||
# 1486| getQualifier(): [VariableAccess] (unnamed parameter 0)
|
||||
# 1486| Type = [LValueReferenceType] const StructuredBindingDataMemberStruct &
|
||||
# 1486| ValueCategory = prvalue(load)
|
||||
# 1486| getQualifier().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
|
||||
# 1486| Type = [SpecifiedType] const StructuredBindingDataMemberStruct
|
||||
# 1486| ValueCategory = lvalue
|
||||
# 1486| getInitializer(7): [ConstructorFieldInit] constructor init of field m
|
||||
# 1486| Type = [Struct] StructuredBindingDataMemberMemberStruct
|
||||
# 1486| ValueCategory = prvalue
|
||||
# 1486| getExpr(): [Literal] Unknown literal
|
||||
# 1486| getExpr(): [ReferenceFieldAccess] m
|
||||
# 1486| Type = [Struct] StructuredBindingDataMemberMemberStruct
|
||||
# 1486| ValueCategory = prvalue
|
||||
# 1486| ValueCategory = prvalue(load)
|
||||
# 1486| getQualifier(): [VariableAccess] (unnamed parameter 0)
|
||||
# 1486| Type = [LValueReferenceType] const StructuredBindingDataMemberStruct &
|
||||
# 1486| ValueCategory = prvalue(load)
|
||||
# 1486| getQualifier().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
|
||||
# 1486| Type = [SpecifiedType] const StructuredBindingDataMemberStruct
|
||||
# 1486| ValueCategory = lvalue
|
||||
# 1486| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 1486| getStmt(0): [ReturnStmt] return ...
|
||||
# 1486| [MoveConstructor] void StructuredBindingDataMemberStruct::StructuredBindingDataMemberStruct(StructuredBindingDataMemberStruct&&)
|
||||
@@ -12066,21 +12126,39 @@ ir.cpp:
|
||||
# 1539| getInitializer(0): [ConstructorFieldInit] constructor init of field i
|
||||
# 1539| Type = [IntType] int
|
||||
# 1539| ValueCategory = prvalue
|
||||
# 1539| getExpr(): [Literal] Unknown literal
|
||||
# 1539| getExpr(): [ReferenceFieldAccess] i
|
||||
# 1539| Type = [IntType] int
|
||||
# 1539| ValueCategory = prvalue
|
||||
# 1539| ValueCategory = prvalue(load)
|
||||
# 1539| getQualifier(): [VariableAccess] (unnamed parameter 0)
|
||||
# 1539| Type = [LValueReferenceType] const StructuredBindingTupleRefGet &
|
||||
# 1539| ValueCategory = prvalue(load)
|
||||
# 1539| getQualifier().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
|
||||
# 1539| Type = [SpecifiedType] const StructuredBindingTupleRefGet
|
||||
# 1539| ValueCategory = lvalue
|
||||
# 1539| getInitializer(1): [ConstructorFieldInit] constructor init of field d
|
||||
# 1539| Type = [DoubleType] double
|
||||
# 1539| ValueCategory = prvalue
|
||||
# 1539| getExpr(): [Literal] Unknown literal
|
||||
# 1539| getExpr(): [ReferenceFieldAccess] d
|
||||
# 1539| Type = [DoubleType] double
|
||||
# 1539| ValueCategory = prvalue
|
||||
# 1539| ValueCategory = prvalue(load)
|
||||
# 1539| getQualifier(): [VariableAccess] (unnamed parameter 0)
|
||||
# 1539| Type = [LValueReferenceType] const StructuredBindingTupleRefGet &
|
||||
# 1539| ValueCategory = prvalue(load)
|
||||
# 1539| getQualifier().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
|
||||
# 1539| Type = [SpecifiedType] const StructuredBindingTupleRefGet
|
||||
# 1539| ValueCategory = lvalue
|
||||
# 1539| getInitializer(2): [ConstructorFieldInit] constructor init of field r
|
||||
# 1539| Type = [LValueReferenceType] int &
|
||||
# 1539| ValueCategory = prvalue
|
||||
# 1539| getExpr(): [Literal] Unknown literal
|
||||
# 1539| getExpr(): [ReferenceFieldAccess] r
|
||||
# 1539| Type = [LValueReferenceType] int &
|
||||
# 1539| ValueCategory = prvalue
|
||||
# 1539| ValueCategory = prvalue(load)
|
||||
# 1539| getQualifier(): [VariableAccess] (unnamed parameter 0)
|
||||
# 1539| Type = [LValueReferenceType] const StructuredBindingTupleRefGet &
|
||||
# 1539| ValueCategory = prvalue(load)
|
||||
# 1539| getQualifier().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
|
||||
# 1539| Type = [SpecifiedType] const StructuredBindingTupleRefGet
|
||||
# 1539| ValueCategory = lvalue
|
||||
# 1539| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 1539| getStmt(0): [ReturnStmt] return ...
|
||||
# 1539| [MoveConstructor] void StructuredBindingTupleRefGet::StructuredBindingTupleRefGet(StructuredBindingTupleRefGet&&)
|
||||
@@ -12942,12 +13020,12 @@ ir.cpp:
|
||||
# 1688| getInitializer(): [ClassAggregateLiteral] {...}
|
||||
# 1688| Type = [Closure,LocalClass] decltype([...](...){...})
|
||||
# 1688| ValueCategory = prvalue
|
||||
# 1688| getFieldExpr(obj1): [Literal] Unknown literal
|
||||
# 1688| Type = [SpecifiedType] const CapturedLambdaMyObj
|
||||
# 1688| ValueCategory = prvalue
|
||||
# 1688| getFieldExpr(obj2): [Literal] Unknown literal
|
||||
# 1688| getFieldExpr(obj1): [VariableAccess] obj1
|
||||
# 1688| Type = [LValueReferenceType] const CapturedLambdaMyObj &
|
||||
# 1688| ValueCategory = prvalue(load)
|
||||
# 1688| getFieldExpr(obj2): [VariableAccess] obj2
|
||||
# 1688| Type = [Class] CapturedLambdaMyObj
|
||||
# 1688| ValueCategory = prvalue
|
||||
# 1688| ValueCategory = prvalue(load)
|
||||
# 1688| getFieldExpr(x): [VariableAccess] x
|
||||
# 1688| Type = [IntType] int
|
||||
# 1688| ValueCategory = prvalue(load)
|
||||
@@ -12957,6 +13035,9 @@ ir.cpp:
|
||||
# 1688| getFieldExpr(z): [VariableAccess] z
|
||||
# 1688| Type = [RValueReferenceType] int &&
|
||||
# 1688| ValueCategory = prvalue(load)
|
||||
#-----| getFieldExpr(obj1).getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
|
||||
#-----| Type = [SpecifiedType] const CapturedLambdaMyObj
|
||||
#-----| ValueCategory = prvalue(load)
|
||||
# 1690| getFieldExpr(y).getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
|
||||
# 1690| Type = [IntType] int
|
||||
# 1690| ValueCategory = prvalue(load)
|
||||
@@ -12991,12 +13072,18 @@ ir.cpp:
|
||||
# 1689| getInitializer(): [ClassAggregateLiteral] {...}
|
||||
# 1689| Type = [Closure,LocalClass] decltype([...](...){...})
|
||||
# 1689| ValueCategory = prvalue
|
||||
# 1689| getFieldExpr(obj1): [Literal] Unknown literal
|
||||
# 1689| getFieldExpr(obj1): [PointerFieldAccess] obj1
|
||||
# 1689| Type = [SpecifiedType] const CapturedLambdaMyObj
|
||||
# 1689| ValueCategory = prvalue
|
||||
# 1689| getFieldExpr(obj2): [Literal] Unknown literal
|
||||
# 1689| ValueCategory = prvalue(load)
|
||||
# 1689| getQualifier(): [ThisExpr] this
|
||||
# 1689| Type = [PointerType] lambda [] type at line 1689, col. 29 *
|
||||
# 1689| ValueCategory = prvalue(load)
|
||||
# 1689| getFieldExpr(obj2): [PointerFieldAccess] obj2
|
||||
# 1689| Type = [Class] CapturedLambdaMyObj
|
||||
# 1689| ValueCategory = prvalue
|
||||
# 1689| ValueCategory = prvalue(load)
|
||||
# 1689| getQualifier(): [ThisExpr] this
|
||||
# 1689| Type = [PointerType] lambda [] type at line 1689, col. 29 *
|
||||
# 1689| ValueCategory = prvalue(load)
|
||||
# 1689| getFieldExpr(x): [PointerFieldAccess] x
|
||||
# 1689| Type = [IntType] int
|
||||
# 1689| ValueCategory = prvalue(load)
|
||||
@@ -13035,6 +13122,443 @@ ir.cpp:
|
||||
# 1689| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 1689| getStmt(0): [EmptyStmt] ;
|
||||
# 1689| getStmt(1): [ReturnStmt] return ...
|
||||
# 1693| [TopLevelFunction] int goto_on_same_line()
|
||||
# 1693| <params>:
|
||||
# 1693| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 1694| getStmt(0): [DeclStmt] declaration
|
||||
# 1694| getDeclarationEntry(0): [VariableDeclarationEntry] definition of x
|
||||
# 1694| Type = [IntType] int
|
||||
# 1694| getVariable().getInitializer(): [Initializer] initializer for x
|
||||
# 1694| getExpr(): [Literal] 42
|
||||
# 1694| Type = [IntType] int
|
||||
# 1694| Value = [Literal] 42
|
||||
# 1694| ValueCategory = prvalue
|
||||
# 1695| getStmt(1): [GotoStmt] goto ...
|
||||
# 1695| getStmt(2): [LabelStmt] label ...:
|
||||
# 1696| getStmt(3): [ReturnStmt] return ...
|
||||
# 1696| getExpr(): [VariableAccess] x
|
||||
# 1696| Type = [IntType] int
|
||||
# 1696| ValueCategory = prvalue(load)
|
||||
# 1699| [CopyAssignmentOperator] TrivialLambdaClass& TrivialLambdaClass::operator=(TrivialLambdaClass const&)
|
||||
# 1699| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [LValueReferenceType] const TrivialLambdaClass &
|
||||
# 1699| [MoveAssignmentOperator] TrivialLambdaClass& TrivialLambdaClass::operator=(TrivialLambdaClass&&)
|
||||
# 1699| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [RValueReferenceType] TrivialLambdaClass &&
|
||||
# 1701| [ConstMemberFunction] void TrivialLambdaClass::m() const
|
||||
# 1701| <params>:
|
||||
# 1701| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 1702| getStmt(0): [DeclStmt] declaration
|
||||
# 1702| getDeclarationEntry(0): [VariableDeclarationEntry] definition of l_m_outer
|
||||
# 1702| Type = [Closure,LocalClass] decltype([...](...){...})
|
||||
# 1702| getVariable().getInitializer(): [Initializer] initializer for l_m_outer
|
||||
# 1702| getExpr(): [LambdaExpression] [...](...){...}
|
||||
# 1702| Type = [Closure,LocalClass] decltype([...](...){...})
|
||||
# 1702| ValueCategory = prvalue
|
||||
# 1702| getInitializer(): [ClassAggregateLiteral] {...}
|
||||
# 1702| Type = [Closure,LocalClass] decltype([...](...){...})
|
||||
# 1702| ValueCategory = prvalue
|
||||
# 1702| getFieldExpr((captured this)): [PointerDereferenceExpr] * ...
|
||||
# 1702| Type = [SpecifiedType] const TrivialLambdaClass
|
||||
# 1702| ValueCategory = prvalue(load)
|
||||
# 1702| getOperand(): [ThisExpr] this
|
||||
# 1702| Type = [SpecifiedType] const TrivialLambdaClass *const
|
||||
# 1702| ValueCategory = prvalue(load)
|
||||
# 1709| getStmt(1): [ReturnStmt] return ...
|
||||
# 1702| [CopyAssignmentOperator] (void TrivialLambdaClass::m() const)::(lambda [] type at line 1702, col. 26)& (void TrivialLambdaClass::m() const)::(lambda [] type at line 1702, col. 26)::operator=((void TrivialLambdaClass::m() const)::(lambda [] type at line 1702, col. 26) const&)
|
||||
# 1702| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [LValueReferenceType] const lambda [] type at line 1702, col. 26 &
|
||||
# 1702| [CopyConstructor] void (void TrivialLambdaClass::m() const)::(lambda [] type at line 1702, col. 26)::(unnamed constructor)((void TrivialLambdaClass::m() const)::(lambda [] type at line 1702, col. 26) const&)
|
||||
# 1702| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [LValueReferenceType] const lambda [] type at line 1702, col. 26 &
|
||||
# 1702| [MoveConstructor] void (void TrivialLambdaClass::m() const)::(lambda [] type at line 1702, col. 26)::(unnamed constructor)((void TrivialLambdaClass::m() const)::(lambda [] type at line 1702, col. 26)&&)
|
||||
# 1702| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [RValueReferenceType] lambda [] type at line 1702, col. 26 &&
|
||||
# 1702| [Constructor] void (void TrivialLambdaClass::m() const)::(lambda [] type at line 1702, col. 26)::(unnamed constructor)()
|
||||
# 1702| <params>:
|
||||
# 1702| [ConstMemberFunction] void (void TrivialLambdaClass::m() const)::(lambda [] type at line 1702, col. 26)::operator()() const
|
||||
# 1702| <params>:
|
||||
# 1702| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 1703| getStmt(0): [ExprStmt] ExprStmt
|
||||
# 1703| getExpr(): [FunctionCall] call to m
|
||||
# 1703| Type = [VoidType] void
|
||||
# 1703| ValueCategory = prvalue
|
||||
# 1703| getQualifier(): [AddressOfExpr] & ...
|
||||
# 1703| Type = [PointerType] const TrivialLambdaClass *
|
||||
# 1703| ValueCategory = prvalue
|
||||
# 1703| getOperand(): [PointerFieldAccess] (captured this)
|
||||
# 1703| Type = [SpecifiedType] const TrivialLambdaClass
|
||||
# 1703| ValueCategory = lvalue
|
||||
# 1703| getQualifier(): [ThisExpr] this
|
||||
# 1703| Type = [PointerType] const lambda [] type at line 1702, col. 26 *
|
||||
# 1703| ValueCategory = prvalue(load)
|
||||
# 1705| getStmt(1): [DeclStmt] declaration
|
||||
# 1705| getDeclarationEntry(0): [VariableDeclarationEntry] definition of l_m_inner
|
||||
# 1705| Type = [Closure,LocalClass] decltype([...](...){...})
|
||||
# 1705| getVariable().getInitializer(): [Initializer] initializer for l_m_inner
|
||||
# 1705| getExpr(): [LambdaExpression] [...](...){...}
|
||||
# 1705| Type = [Closure,LocalClass] decltype([...](...){...})
|
||||
# 1705| ValueCategory = prvalue
|
||||
# 1705| getInitializer(): [ClassAggregateLiteral] {...}
|
||||
# 1705| Type = [Closure,LocalClass] decltype([...](...){...})
|
||||
# 1705| ValueCategory = prvalue
|
||||
# 1705| getFieldExpr((captured this)): [PointerFieldAccess] (captured this)
|
||||
# 1705| Type = [SpecifiedType] const TrivialLambdaClass
|
||||
# 1705| ValueCategory = prvalue(load)
|
||||
# 1705| getQualifier(): [ThisExpr] this
|
||||
# 1705| Type = [PointerType] lambda [] type at line 1705, col. 30 *
|
||||
# 1705| ValueCategory = prvalue(load)
|
||||
# 1708| getStmt(2): [ReturnStmt] return ...
|
||||
# 1705| [CopyAssignmentOperator] (void (void TrivialLambdaClass::m() const)::(lambda [] type at line 1702, col. 26)::operator()() const)::(lambda [] type at line 1705, col. 30)& (void (void TrivialLambdaClass::m() const)::(lambda [] type at line 1702, col. 26)::operator()() const)::(lambda [] type at line 1705, col. 30)::operator=((void (void TrivialLambdaClass::m() const)::(lambda [] type at line 1702, col. 26)::operator()() const)::(lambda [] type at line 1705, col. 30) const&)
|
||||
# 1705| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [LValueReferenceType] const lambda [] type at line 1705, col. 30 &
|
||||
# 1705| [CopyConstructor] void (void (void TrivialLambdaClass::m() const)::(lambda [] type at line 1702, col. 26)::operator()() const)::(lambda [] type at line 1705, col. 30)::(unnamed constructor)((void (void TrivialLambdaClass::m() const)::(lambda [] type at line 1702, col. 26)::operator()() const)::(lambda [] type at line 1705, col. 30) const&)
|
||||
# 1705| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [LValueReferenceType] const lambda [] type at line 1705, col. 30 &
|
||||
# 1705| [MoveConstructor] void (void (void TrivialLambdaClass::m() const)::(lambda [] type at line 1702, col. 26)::operator()() const)::(lambda [] type at line 1705, col. 30)::(unnamed constructor)((void (void TrivialLambdaClass::m() const)::(lambda [] type at line 1702, col. 26)::operator()() const)::(lambda [] type at line 1705, col. 30)&&)
|
||||
# 1705| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [RValueReferenceType] lambda [] type at line 1705, col. 30 &&
|
||||
# 1705| [Constructor] void (void (void TrivialLambdaClass::m() const)::(lambda [] type at line 1702, col. 26)::operator()() const)::(lambda [] type at line 1705, col. 30)::(unnamed constructor)()
|
||||
# 1705| <params>:
|
||||
# 1705| [ConstMemberFunction] void (void (void TrivialLambdaClass::m() const)::(lambda [] type at line 1702, col. 26)::operator()() const)::(lambda [] type at line 1705, col. 30)::operator()() const
|
||||
# 1705| <params>:
|
||||
# 1705| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 1706| getStmt(0): [ExprStmt] ExprStmt
|
||||
# 1706| getExpr(): [FunctionCall] call to m
|
||||
# 1706| Type = [VoidType] void
|
||||
# 1706| ValueCategory = prvalue
|
||||
# 1706| getQualifier(): [AddressOfExpr] & ...
|
||||
# 1706| Type = [PointerType] const TrivialLambdaClass *
|
||||
# 1706| ValueCategory = prvalue
|
||||
# 1706| getOperand(): [PointerFieldAccess] (captured this)
|
||||
# 1706| Type = [SpecifiedType] const TrivialLambdaClass
|
||||
# 1706| ValueCategory = lvalue
|
||||
# 1706| getQualifier(): [ThisExpr] this
|
||||
# 1706| Type = [PointerType] const lambda [] type at line 1705, col. 30 *
|
||||
# 1706| ValueCategory = prvalue(load)
|
||||
# 1707| getStmt(1): [ReturnStmt] return ...
|
||||
# 1712| [TopLevelFunction] void captured_lambda2(TrivialLambdaClass, TrivialLambdaClass&, TrivialLambdaClass&&)
|
||||
# 1712| <params>:
|
||||
# 1712| getParameter(0): [Parameter] p1
|
||||
# 1712| Type = [Class] TrivialLambdaClass
|
||||
# 1712| getParameter(1): [Parameter] p2
|
||||
# 1712| Type = [LValueReferenceType] TrivialLambdaClass &
|
||||
# 1712| getParameter(2): [Parameter] p3
|
||||
# 1712| Type = [RValueReferenceType] TrivialLambdaClass &&
|
||||
# 1712| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 1713| getStmt(0): [DeclStmt] declaration
|
||||
# 1713| getDeclarationEntry(0): [VariableDeclarationEntry] definition of l1
|
||||
# 1713| Type = [SpecifiedType] const TrivialLambdaClass
|
||||
# 1714| getStmt(1): [DeclStmt] declaration
|
||||
# 1714| getDeclarationEntry(0): [VariableDeclarationEntry] definition of l2
|
||||
# 1714| Type = [LValueReferenceType] const TrivialLambdaClass &
|
||||
# 1714| getVariable().getInitializer(): [Initializer] initializer for l2
|
||||
# 1714| getExpr(): [Literal] 0
|
||||
# 1714| Type = [Class] TrivialLambdaClass
|
||||
# 1714| Value = [Literal] 0
|
||||
# 1714| ValueCategory = prvalue
|
||||
# 1714| getExpr().getFullyConverted(): [ReferenceToExpr] (reference to)
|
||||
# 1714| Type = [LValueReferenceType] const TrivialLambdaClass &
|
||||
# 1714| ValueCategory = prvalue
|
||||
# 1714| getExpr(): [CStyleCast] (const TrivialLambdaClass)...
|
||||
# 1714| Conversion = [GlvalueConversion] glvalue conversion
|
||||
# 1714| Type = [SpecifiedType] const TrivialLambdaClass
|
||||
# 1714| ValueCategory = lvalue
|
||||
# 1714| getExpr(): [TemporaryObjectExpr] temporary object
|
||||
# 1714| Type = [Class] TrivialLambdaClass
|
||||
# 1714| ValueCategory = lvalue
|
||||
# 1714| getExpr(): [TemporaryObjectExpr] temporary object
|
||||
# 1714| Type = [Class] TrivialLambdaClass
|
||||
# 1714| ValueCategory = prvalue(load)
|
||||
# 1716| getStmt(2): [DeclStmt] declaration
|
||||
# 1716| getDeclarationEntry(0): [VariableDeclarationEntry] definition of l_outer1
|
||||
# 1716| Type = [Closure,LocalClass] decltype([...](...){...})
|
||||
# 1716| getVariable().getInitializer(): [Initializer] initializer for l_outer1
|
||||
# 1716| getExpr(): [LambdaExpression] [...](...){...}
|
||||
# 1716| Type = [Closure,LocalClass] decltype([...](...){...})
|
||||
# 1716| ValueCategory = prvalue
|
||||
# 1716| getInitializer(): [ClassAggregateLiteral] {...}
|
||||
# 1716| Type = [Closure,LocalClass] decltype([...](...){...})
|
||||
# 1716| ValueCategory = prvalue
|
||||
# 1716| getFieldExpr(p1): [VariableAccess] p1
|
||||
# 1716| Type = [Class] TrivialLambdaClass
|
||||
# 1716| ValueCategory = prvalue(load)
|
||||
# 1716| getFieldExpr(p2): [VariableAccess] p2
|
||||
# 1716| Type = [LValueReferenceType] TrivialLambdaClass &
|
||||
# 1716| ValueCategory = prvalue(load)
|
||||
# 1716| getFieldExpr(p3): [VariableAccess] p3
|
||||
# 1716| Type = [RValueReferenceType] TrivialLambdaClass &&
|
||||
# 1716| ValueCategory = prvalue(load)
|
||||
# 1716| getFieldExpr(l1): [VariableAccess] l1
|
||||
# 1716| Type = [SpecifiedType] const TrivialLambdaClass
|
||||
# 1716| ValueCategory = prvalue(load)
|
||||
# 1716| getFieldExpr(l2): [VariableAccess] l2
|
||||
# 1716| Type = [LValueReferenceType] const TrivialLambdaClass &
|
||||
# 1716| ValueCategory = prvalue(load)
|
||||
#-----| getFieldExpr(p2).getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
|
||||
#-----| Type = [Class] TrivialLambdaClass
|
||||
#-----| ValueCategory = prvalue(load)
|
||||
#-----| getFieldExpr(p3).getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
|
||||
#-----| Type = [Class] TrivialLambdaClass
|
||||
#-----| ValueCategory = prvalue(load)
|
||||
#-----| getFieldExpr(l2).getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
|
||||
#-----| Type = [SpecifiedType] const TrivialLambdaClass
|
||||
#-----| ValueCategory = prvalue(load)
|
||||
# 1719| getStmt(3): [ReturnStmt] return ...
|
||||
# 1716| [CopyAssignmentOperator] (void captured_lambda2(TrivialLambdaClass, TrivialLambdaClass&, TrivialLambdaClass&&))::(lambda [] type at line 1716, col. 21)& (void captured_lambda2(TrivialLambdaClass, TrivialLambdaClass&, TrivialLambdaClass&&))::(lambda [] type at line 1716, col. 21)::operator=((void captured_lambda2(TrivialLambdaClass, TrivialLambdaClass&, TrivialLambdaClass&&))::(lambda [] type at line 1716, col. 21) const&)
|
||||
# 1716| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [LValueReferenceType] const lambda [] type at line 1716, col. 21 &
|
||||
# 1716| [CopyConstructor] void (void captured_lambda2(TrivialLambdaClass, TrivialLambdaClass&, TrivialLambdaClass&&))::(lambda [] type at line 1716, col. 21)::(unnamed constructor)((void captured_lambda2(TrivialLambdaClass, TrivialLambdaClass&, TrivialLambdaClass&&))::(lambda [] type at line 1716, col. 21) const&)
|
||||
# 1716| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [LValueReferenceType] const lambda [] type at line 1716, col. 21 &
|
||||
# 1716| [MoveConstructor] void (void captured_lambda2(TrivialLambdaClass, TrivialLambdaClass&, TrivialLambdaClass&&))::(lambda [] type at line 1716, col. 21)::(unnamed constructor)((void captured_lambda2(TrivialLambdaClass, TrivialLambdaClass&, TrivialLambdaClass&&))::(lambda [] type at line 1716, col. 21)&&)
|
||||
# 1716| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [RValueReferenceType] lambda [] type at line 1716, col. 21 &&
|
||||
# 1716| [Constructor] void (void captured_lambda2(TrivialLambdaClass, TrivialLambdaClass&, TrivialLambdaClass&&))::(lambda [] type at line 1716, col. 21)::(unnamed constructor)()
|
||||
# 1716| <params>:
|
||||
# 1716| [ConstMemberFunction] void (void captured_lambda2(TrivialLambdaClass, TrivialLambdaClass&, TrivialLambdaClass&&))::(lambda [] type at line 1716, col. 21)::operator()() const
|
||||
# 1716| <params>:
|
||||
# 1716| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 1717| getStmt(0): [DeclStmt] declaration
|
||||
# 1717| getDeclarationEntry(0): [VariableDeclarationEntry] definition of l_inner1
|
||||
# 1717| Type = [Closure,LocalClass] decltype([...](...){...})
|
||||
# 1717| getVariable().getInitializer(): [Initializer] initializer for l_inner1
|
||||
# 1717| getExpr(): [LambdaExpression] [...](...){...}
|
||||
# 1717| Type = [Closure,LocalClass] decltype([...](...){...})
|
||||
# 1717| ValueCategory = prvalue
|
||||
# 1717| getInitializer(): [ClassAggregateLiteral] {...}
|
||||
# 1717| Type = [Closure,LocalClass] decltype([...](...){...})
|
||||
# 1717| ValueCategory = prvalue
|
||||
# 1717| getFieldExpr(p1): [PointerFieldAccess] p1
|
||||
# 1717| Type = [Class] TrivialLambdaClass
|
||||
# 1717| ValueCategory = prvalue(load)
|
||||
# 1717| getQualifier(): [ThisExpr] this
|
||||
# 1717| Type = [PointerType] lambda [] type at line 1717, col. 25 *
|
||||
# 1717| ValueCategory = prvalue(load)
|
||||
# 1718| getStmt(1): [ReturnStmt] return ...
|
||||
# 1717| [CopyAssignmentOperator] (void (void captured_lambda2(TrivialLambdaClass, TrivialLambdaClass&, TrivialLambdaClass&&))::(lambda [] type at line 1716, col. 21)::operator()() const)::(lambda [] type at line 1717, col. 25)& (void (void captured_lambda2(TrivialLambdaClass, TrivialLambdaClass&, TrivialLambdaClass&&))::(lambda [] type at line 1716, col. 21)::operator()() const)::(lambda [] type at line 1717, col. 25)::operator=((void (void captured_lambda2(TrivialLambdaClass, TrivialLambdaClass&, TrivialLambdaClass&&))::(lambda [] type at line 1716, col. 21)::operator()() const)::(lambda [] type at line 1717, col. 25) const&)
|
||||
# 1717| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [LValueReferenceType] const lambda [] type at line 1717, col. 25 &
|
||||
# 1717| [CopyConstructor] void (void (void captured_lambda2(TrivialLambdaClass, TrivialLambdaClass&, TrivialLambdaClass&&))::(lambda [] type at line 1716, col. 21)::operator()() const)::(lambda [] type at line 1717, col. 25)::(unnamed constructor)((void (void captured_lambda2(TrivialLambdaClass, TrivialLambdaClass&, TrivialLambdaClass&&))::(lambda [] type at line 1716, col. 21)::operator()() const)::(lambda [] type at line 1717, col. 25) const&)
|
||||
# 1717| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [LValueReferenceType] const lambda [] type at line 1717, col. 25 &
|
||||
# 1717| [MoveConstructor] void (void (void captured_lambda2(TrivialLambdaClass, TrivialLambdaClass&, TrivialLambdaClass&&))::(lambda [] type at line 1716, col. 21)::operator()() const)::(lambda [] type at line 1717, col. 25)::(unnamed constructor)((void (void captured_lambda2(TrivialLambdaClass, TrivialLambdaClass&, TrivialLambdaClass&&))::(lambda [] type at line 1716, col. 21)::operator()() const)::(lambda [] type at line 1717, col. 25)&&)
|
||||
# 1717| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [RValueReferenceType] lambda [] type at line 1717, col. 25 &&
|
||||
# 1717| [Constructor] void (void (void captured_lambda2(TrivialLambdaClass, TrivialLambdaClass&, TrivialLambdaClass&&))::(lambda [] type at line 1716, col. 21)::operator()() const)::(lambda [] type at line 1717, col. 25)::(unnamed constructor)()
|
||||
# 1717| <params>:
|
||||
# 1717| [ConstMemberFunction] void (void (void captured_lambda2(TrivialLambdaClass, TrivialLambdaClass&, TrivialLambdaClass&&))::(lambda [] type at line 1716, col. 21)::operator()() const)::(lambda [] type at line 1717, col. 25)::operator()() const
|
||||
# 1717| <params>:
|
||||
# 1717| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 1717| getStmt(0): [ReturnStmt] return ...
|
||||
# 1721| [CopyAssignmentOperator] CopyConstructorWithImplicitArgumentClass& CopyConstructorWithImplicitArgumentClass::operator=(CopyConstructorWithImplicitArgumentClass const&)
|
||||
# 1721| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [LValueReferenceType] const CopyConstructorWithImplicitArgumentClass &
|
||||
# 1724| [Constructor] void CopyConstructorWithImplicitArgumentClass::CopyConstructorWithImplicitArgumentClass()
|
||||
# 1724| <params>:
|
||||
# 1724| <initializations>:
|
||||
# 1724| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 1724| getStmt(0): [ReturnStmt] return ...
|
||||
# 1725| [CopyConstructor] void CopyConstructorWithImplicitArgumentClass::CopyConstructorWithImplicitArgumentClass(CopyConstructorWithImplicitArgumentClass const&)
|
||||
# 1725| <params>:
|
||||
# 1725| getParameter(0): [Parameter] c
|
||||
# 1725| Type = [LValueReferenceType] const CopyConstructorWithImplicitArgumentClass &
|
||||
# 1725| <initializations>:
|
||||
# 1725| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 1726| getStmt(0): [ExprStmt] ExprStmt
|
||||
# 1726| getExpr(): [AssignExpr] ... = ...
|
||||
# 1726| Type = [IntType] int
|
||||
# 1726| ValueCategory = lvalue
|
||||
# 1726| getLValue(): [PointerFieldAccess] x
|
||||
# 1726| Type = [IntType] int
|
||||
# 1726| ValueCategory = lvalue
|
||||
# 1726| getQualifier(): [ThisExpr] this
|
||||
# 1726| Type = [PointerType] CopyConstructorWithImplicitArgumentClass *
|
||||
# 1726| ValueCategory = prvalue(load)
|
||||
# 1726| getRValue(): [ReferenceFieldAccess] x
|
||||
# 1726| Type = [IntType] int
|
||||
# 1726| ValueCategory = prvalue(load)
|
||||
# 1726| getQualifier(): [VariableAccess] c
|
||||
# 1726| Type = [LValueReferenceType] const CopyConstructorWithImplicitArgumentClass &
|
||||
# 1726| ValueCategory = prvalue(load)
|
||||
# 1726| getQualifier().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
|
||||
# 1726| Type = [SpecifiedType] const CopyConstructorWithImplicitArgumentClass
|
||||
# 1726| ValueCategory = lvalue
|
||||
# 1727| getStmt(1): [ReturnStmt] return ...
|
||||
# 1730| [CopyAssignmentOperator] CopyConstructorWithBitwiseCopyClass& CopyConstructorWithBitwiseCopyClass::operator=(CopyConstructorWithBitwiseCopyClass const&)
|
||||
# 1730| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [LValueReferenceType] const CopyConstructorWithBitwiseCopyClass &
|
||||
# 1730| [MoveAssignmentOperator] CopyConstructorWithBitwiseCopyClass& CopyConstructorWithBitwiseCopyClass::operator=(CopyConstructorWithBitwiseCopyClass&&)
|
||||
# 1730| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [RValueReferenceType] CopyConstructorWithBitwiseCopyClass &&
|
||||
# 1730| [CopyConstructor] void CopyConstructorWithBitwiseCopyClass::CopyConstructorWithBitwiseCopyClass(CopyConstructorWithBitwiseCopyClass const&)
|
||||
# 1730| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [LValueReferenceType] const CopyConstructorWithBitwiseCopyClass &
|
||||
# 1730| [MoveConstructor] void CopyConstructorWithBitwiseCopyClass::CopyConstructorWithBitwiseCopyClass(CopyConstructorWithBitwiseCopyClass&&)
|
||||
# 1730| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [RValueReferenceType] CopyConstructorWithBitwiseCopyClass &&
|
||||
# 1733| [Constructor] void CopyConstructorWithBitwiseCopyClass::CopyConstructorWithBitwiseCopyClass()
|
||||
# 1733| <params>:
|
||||
# 1733| <initializations>:
|
||||
# 1733| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 1733| getStmt(0): [ReturnStmt] return ...
|
||||
# 1736| [CopyAssignmentOperator] CopyConstructorTestNonVirtualClass& CopyConstructorTestNonVirtualClass::operator=(CopyConstructorTestNonVirtualClass const&)
|
||||
# 1736| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [LValueReferenceType] const CopyConstructorTestNonVirtualClass &
|
||||
# 1736| [MoveAssignmentOperator] CopyConstructorTestNonVirtualClass& CopyConstructorTestNonVirtualClass::operator=(CopyConstructorTestNonVirtualClass&&)
|
||||
# 1736| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [RValueReferenceType] CopyConstructorTestNonVirtualClass &&
|
||||
# 1736| [CopyConstructor] void CopyConstructorTestNonVirtualClass::CopyConstructorTestNonVirtualClass(CopyConstructorTestNonVirtualClass const&)
|
||||
# 1736| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [LValueReferenceType] const CopyConstructorTestNonVirtualClass &
|
||||
# 1736| <initializations>:
|
||||
# 1736| getInitializer(0): [ConstructorDirectInit] call to CopyConstructorWithImplicitArgumentClass
|
||||
# 1736| Type = [VoidType] void
|
||||
# 1736| ValueCategory = prvalue
|
||||
# 1736| getArgument(0): [VariableAccess] (unnamed parameter 0)
|
||||
# 1736| Type = [LValueReferenceType] const CopyConstructorTestNonVirtualClass &
|
||||
# 1736| ValueCategory = prvalue(load)
|
||||
# 1736| getArgument(0).getFullyConverted(): [ReferenceToExpr] (reference to)
|
||||
# 1736| Type = [LValueReferenceType] const CopyConstructorWithImplicitArgumentClass &
|
||||
# 1736| ValueCategory = prvalue
|
||||
# 1736| getExpr(): [CStyleCast] (const CopyConstructorWithImplicitArgumentClass)...
|
||||
# 1736| Conversion = [BaseClassConversion] base class conversion
|
||||
# 1736| Type = [SpecifiedType] const CopyConstructorWithImplicitArgumentClass
|
||||
# 1736| ValueCategory = lvalue
|
||||
# 1736| getExpr(): [ReferenceDereferenceExpr] (reference dereference)
|
||||
# 1736| Type = [SpecifiedType] const CopyConstructorTestNonVirtualClass
|
||||
# 1736| ValueCategory = lvalue
|
||||
# 1736| getInitializer(1): (no string representation)
|
||||
# 1736| Type = [VirtualBaseClass] CopyConstructorWithBitwiseCopyClass
|
||||
# 1736| ValueCategory = prvalue
|
||||
# 1736| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 1736| getStmt(0): [ReturnStmt] return ...
|
||||
# 1736| [MoveConstructor] void CopyConstructorTestNonVirtualClass::CopyConstructorTestNonVirtualClass(CopyConstructorTestNonVirtualClass&&)
|
||||
# 1736| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [RValueReferenceType] CopyConstructorTestNonVirtualClass &&
|
||||
# 1740| [Constructor] void CopyConstructorTestNonVirtualClass::CopyConstructorTestNonVirtualClass()
|
||||
# 1740| <params>:
|
||||
# 1740| <initializations>:
|
||||
# 1740| getInitializer(0): [ConstructorDirectInit] call to CopyConstructorWithImplicitArgumentClass
|
||||
# 1740| Type = [VoidType] void
|
||||
# 1740| ValueCategory = prvalue
|
||||
# 1740| getInitializer(1): [ConstructorDirectInit] call to CopyConstructorWithBitwiseCopyClass
|
||||
# 1740| Type = [VoidType] void
|
||||
# 1740| ValueCategory = prvalue
|
||||
# 1740| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 1740| getStmt(0): [ReturnStmt] return ...
|
||||
# 1743| [CopyAssignmentOperator] CopyConstructorTestVirtualClass& CopyConstructorTestVirtualClass::operator=(CopyConstructorTestVirtualClass const&)
|
||||
# 1743| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [LValueReferenceType] const CopyConstructorTestVirtualClass &
|
||||
# 1743| [MoveAssignmentOperator] CopyConstructorTestVirtualClass& CopyConstructorTestVirtualClass::operator=(CopyConstructorTestVirtualClass&&)
|
||||
# 1743| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [RValueReferenceType] CopyConstructorTestVirtualClass &&
|
||||
# 1743| [CopyConstructor] void CopyConstructorTestVirtualClass::CopyConstructorTestVirtualClass(CopyConstructorTestVirtualClass const&)
|
||||
# 1743| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [LValueReferenceType] const CopyConstructorTestVirtualClass &
|
||||
# 1743| <initializations>:
|
||||
# 1743| getInitializer(0): [ConstructorVirtualInit] call to CopyConstructorWithImplicitArgumentClass
|
||||
# 1743| Type = [VoidType] void
|
||||
# 1743| ValueCategory = prvalue
|
||||
# 1743| getArgument(0): [VariableAccess] (unnamed parameter 0)
|
||||
# 1743| Type = [LValueReferenceType] const CopyConstructorTestVirtualClass &
|
||||
# 1743| ValueCategory = prvalue(load)
|
||||
# 1743| getArgument(0).getFullyConverted(): [ReferenceToExpr] (reference to)
|
||||
# 1743| Type = [LValueReferenceType] const CopyConstructorWithImplicitArgumentClass &
|
||||
# 1743| ValueCategory = prvalue
|
||||
# 1743| getExpr(): [CStyleCast] (const CopyConstructorWithImplicitArgumentClass)...
|
||||
# 1743| Conversion = [BaseClassConversion] base class conversion
|
||||
# 1743| Type = [SpecifiedType] const CopyConstructorWithImplicitArgumentClass
|
||||
# 1743| ValueCategory = lvalue
|
||||
# 1743| getExpr(): [ReferenceDereferenceExpr] (reference dereference)
|
||||
# 1743| Type = [SpecifiedType] const CopyConstructorTestVirtualClass
|
||||
# 1743| ValueCategory = lvalue
|
||||
# 1743| getInitializer(1): (no string representation)
|
||||
# 1743| Type = [VirtualBaseClass] CopyConstructorWithBitwiseCopyClass
|
||||
# 1743| ValueCategory = prvalue
|
||||
# 1743| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 1743| getStmt(0): [ReturnStmt] return ...
|
||||
# 1743| [MoveConstructor] void CopyConstructorTestVirtualClass::CopyConstructorTestVirtualClass(CopyConstructorTestVirtualClass&&)
|
||||
# 1743| <params>:
|
||||
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
|
||||
#-----| Type = [RValueReferenceType] CopyConstructorTestVirtualClass &&
|
||||
# 1747| [Constructor] void CopyConstructorTestVirtualClass::CopyConstructorTestVirtualClass()
|
||||
# 1747| <params>:
|
||||
# 1747| <initializations>:
|
||||
# 1747| getInitializer(0): [ConstructorVirtualInit] call to CopyConstructorWithImplicitArgumentClass
|
||||
# 1747| Type = [VoidType] void
|
||||
# 1747| ValueCategory = prvalue
|
||||
# 1747| getInitializer(1): [ConstructorVirtualInit] call to CopyConstructorWithBitwiseCopyClass
|
||||
# 1747| Type = [VoidType] void
|
||||
# 1747| ValueCategory = prvalue
|
||||
# 1747| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 1747| getStmt(0): [ReturnStmt] return ...
|
||||
# 1750| [TopLevelFunction] int implicit_copy_constructor_test(CopyConstructorTestNonVirtualClass const&, CopyConstructorTestVirtualClass const&)
|
||||
# 1750| <params>:
|
||||
# 1751| getParameter(0): [Parameter] x
|
||||
# 1751| Type = [LValueReferenceType] const CopyConstructorTestNonVirtualClass &
|
||||
# 1752| getParameter(1): [Parameter] y
|
||||
# 1752| Type = [LValueReferenceType] const CopyConstructorTestVirtualClass &
|
||||
# 1752| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 1753| getStmt(0): [DeclStmt] declaration
|
||||
# 1753| getDeclarationEntry(0): [VariableDeclarationEntry] definition of cx
|
||||
# 1753| Type = [Class] CopyConstructorTestNonVirtualClass
|
||||
# 1753| getVariable().getInitializer(): [Initializer] initializer for cx
|
||||
# 1753| getExpr(): [ConstructorCall] call to CopyConstructorTestNonVirtualClass
|
||||
# 1753| Type = [VoidType] void
|
||||
# 1753| ValueCategory = prvalue
|
||||
# 1753| getArgument(0): [VariableAccess] x
|
||||
# 1753| Type = [LValueReferenceType] const CopyConstructorTestNonVirtualClass &
|
||||
# 1753| ValueCategory = prvalue(load)
|
||||
# 1753| getArgument(0).getFullyConverted(): [ReferenceToExpr] (reference to)
|
||||
# 1753| Type = [LValueReferenceType] const CopyConstructorTestNonVirtualClass &
|
||||
# 1753| ValueCategory = prvalue
|
||||
# 1753| getExpr(): [ReferenceDereferenceExpr] (reference dereference)
|
||||
# 1753| Type = [SpecifiedType] const CopyConstructorTestNonVirtualClass
|
||||
# 1753| ValueCategory = lvalue
|
||||
# 1754| getStmt(1): [DeclStmt] declaration
|
||||
# 1754| getDeclarationEntry(0): [VariableDeclarationEntry] definition of cy
|
||||
# 1754| Type = [Class] CopyConstructorTestVirtualClass
|
||||
# 1754| getVariable().getInitializer(): [Initializer] initializer for cy
|
||||
# 1754| getExpr(): [ConstructorCall] call to CopyConstructorTestVirtualClass
|
||||
# 1754| Type = [VoidType] void
|
||||
# 1754| ValueCategory = prvalue
|
||||
# 1754| getArgument(0): [VariableAccess] y
|
||||
# 1754| Type = [LValueReferenceType] const CopyConstructorTestVirtualClass &
|
||||
# 1754| ValueCategory = prvalue(load)
|
||||
# 1754| getArgument(0).getFullyConverted(): [ReferenceToExpr] (reference to)
|
||||
# 1754| Type = [LValueReferenceType] const CopyConstructorTestVirtualClass &
|
||||
# 1754| ValueCategory = prvalue
|
||||
# 1754| getExpr(): [ReferenceDereferenceExpr] (reference dereference)
|
||||
# 1754| Type = [SpecifiedType] const CopyConstructorTestVirtualClass
|
||||
# 1754| ValueCategory = lvalue
|
||||
# 1755| getStmt(2): [ReturnStmt] return ...
|
||||
perf-regression.cpp:
|
||||
# 4| [CopyAssignmentOperator] Big& Big::operator=(Big const&)
|
||||
# 4| <params>:
|
||||
|
||||
@@ -6,8 +6,6 @@ missingOperandType
|
||||
duplicateChiOperand
|
||||
sideEffectWithoutPrimary
|
||||
instructionWithoutSuccessor
|
||||
| ir.cpp:1688:24:1690:5 | FieldAddress: {...} | Instruction 'FieldAddress: {...}' has no successors in function '$@'. | ir.cpp:1683:6:1683:20 | void captured_lambda(int, int&, int&&) | void captured_lambda(int, int&, int&&) |
|
||||
| ir.cpp:1689:28:1689:54 | FieldAddress: {...} | Instruction 'FieldAddress: {...}' has no successors in function '$@'. | ir.cpp:1688:46:1688:46 | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const |
|
||||
ambiguousSuccessors
|
||||
unexplainedLoop
|
||||
unnecessaryPhiInstruction
|
||||
|
||||
@@ -6,8 +6,6 @@ missingOperandType
|
||||
duplicateChiOperand
|
||||
sideEffectWithoutPrimary
|
||||
instructionWithoutSuccessor
|
||||
| ir.cpp:1688:24:1690:5 | FieldAddress: {...} | Instruction 'FieldAddress: {...}' has no successors in function '$@'. | ir.cpp:1683:6:1683:20 | void captured_lambda(int, int&, int&&) | void captured_lambda(int, int&, int&&) |
|
||||
| ir.cpp:1689:28:1689:54 | FieldAddress: {...} | Instruction 'FieldAddress: {...}' has no successors in function '$@'. | ir.cpp:1688:46:1688:46 | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const |
|
||||
ambiguousSuccessors
|
||||
unexplainedLoop
|
||||
unnecessaryPhiInstruction
|
||||
|
||||
@@ -1690,4 +1690,68 @@ void captured_lambda(int x, int &y, int &&z)
|
||||
};
|
||||
}
|
||||
|
||||
int goto_on_same_line() {
|
||||
int x = 42;
|
||||
goto next; next:
|
||||
return x;
|
||||
}
|
||||
|
||||
class TrivialLambdaClass {
|
||||
public:
|
||||
void m() const {
|
||||
auto l_m_outer = [*this] {
|
||||
m();
|
||||
|
||||
auto l_m_inner = [*this] {
|
||||
m();
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
void captured_lambda2(TrivialLambdaClass p1, TrivialLambdaClass &p2, TrivialLambdaClass &&p3) {
|
||||
const TrivialLambdaClass l1;
|
||||
const TrivialLambdaClass &l2 = TrivialLambdaClass();
|
||||
|
||||
auto l_outer1 = [p1, p2, p3, l1, l2] {
|
||||
auto l_inner1 = [p1] {};
|
||||
};
|
||||
}
|
||||
|
||||
class CopyConstructorWithImplicitArgumentClass {
|
||||
int x;
|
||||
public:
|
||||
CopyConstructorWithImplicitArgumentClass() {}
|
||||
CopyConstructorWithImplicitArgumentClass(const CopyConstructorWithImplicitArgumentClass &c) {
|
||||
x = c.x;
|
||||
}
|
||||
};
|
||||
|
||||
class CopyConstructorWithBitwiseCopyClass {
|
||||
int y;
|
||||
public:
|
||||
CopyConstructorWithBitwiseCopyClass() {}
|
||||
};
|
||||
|
||||
class CopyConstructorTestNonVirtualClass :
|
||||
public CopyConstructorWithImplicitArgumentClass,
|
||||
public CopyConstructorWithBitwiseCopyClass {
|
||||
public:
|
||||
CopyConstructorTestNonVirtualClass() {}
|
||||
};
|
||||
|
||||
class CopyConstructorTestVirtualClass :
|
||||
public virtual CopyConstructorWithImplicitArgumentClass,
|
||||
public virtual CopyConstructorWithBitwiseCopyClass {
|
||||
public:
|
||||
CopyConstructorTestVirtualClass() {}
|
||||
};
|
||||
|
||||
int implicit_copy_constructor_test(
|
||||
const CopyConstructorTestNonVirtualClass &x,
|
||||
const CopyConstructorTestVirtualClass &y) {
|
||||
CopyConstructorTestNonVirtualClass cx = x;
|
||||
CopyConstructorTestVirtualClass cy = y;
|
||||
}
|
||||
|
||||
// semmle-extractor-options: -std=c++17 --clang
|
||||
|
||||
@@ -41,6 +41,37 @@
|
||||
| bad_asts.cpp:16:7:16:23 | ChiTotal | total:m14_4 |
|
||||
| bad_asts.cpp:16:7:16:23 | SideEffect | ~m14_4 |
|
||||
| bad_asts.cpp:16:25:16:25 | Arg(0) | 0:r16_3 |
|
||||
| bad_asts.cpp:19:10:19:10 | Address | &:r19_5 |
|
||||
| bad_asts.cpp:19:10:19:10 | Address | &:r19_5 |
|
||||
| bad_asts.cpp:19:10:19:10 | Address | &:r19_7 |
|
||||
| bad_asts.cpp:19:10:19:10 | Address | &:r19_7 |
|
||||
| bad_asts.cpp:19:10:19:10 | Address | &:r19_9 |
|
||||
| bad_asts.cpp:19:10:19:10 | Address | &:r19_10 |
|
||||
| bad_asts.cpp:19:10:19:10 | Address | &:r19_13 |
|
||||
| bad_asts.cpp:19:10:19:10 | Address | &:r19_17 |
|
||||
| bad_asts.cpp:19:10:19:10 | Address | &:r19_18 |
|
||||
| bad_asts.cpp:19:10:19:10 | Address | &:r19_21 |
|
||||
| bad_asts.cpp:19:10:19:10 | ChiPartial | partial:m19_3 |
|
||||
| bad_asts.cpp:19:10:19:10 | ChiPartial | partial:m19_15 |
|
||||
| bad_asts.cpp:19:10:19:10 | ChiPartial | partial:m19_23 |
|
||||
| bad_asts.cpp:19:10:19:10 | ChiTotal | total:m19_2 |
|
||||
| bad_asts.cpp:19:10:19:10 | ChiTotal | total:m19_8 |
|
||||
| bad_asts.cpp:19:10:19:10 | ChiTotal | total:m19_16 |
|
||||
| bad_asts.cpp:19:10:19:10 | Load | m0_2 |
|
||||
| bad_asts.cpp:19:10:19:10 | Load | m0_2 |
|
||||
| bad_asts.cpp:19:10:19:10 | Load | m19_6 |
|
||||
| bad_asts.cpp:19:10:19:10 | Load | ~m0_4 |
|
||||
| bad_asts.cpp:19:10:19:10 | Load | ~m0_4 |
|
||||
| bad_asts.cpp:19:10:19:10 | SideEffect | m19_3 |
|
||||
| bad_asts.cpp:19:10:19:10 | SideEffect | m19_24 |
|
||||
| bad_asts.cpp:19:10:19:10 | StoreValue | r19_14 |
|
||||
| bad_asts.cpp:19:10:19:10 | StoreValue | r19_22 |
|
||||
| bad_asts.cpp:19:10:19:10 | Unary | m19_6 |
|
||||
| bad_asts.cpp:19:10:19:10 | Unary | m19_6 |
|
||||
| bad_asts.cpp:19:10:19:10 | Unary | r19_11 |
|
||||
| bad_asts.cpp:19:10:19:10 | Unary | r19_12 |
|
||||
| bad_asts.cpp:19:10:19:10 | Unary | r19_19 |
|
||||
| bad_asts.cpp:19:10:19:10 | Unary | r19_20 |
|
||||
| bad_asts.cpp:22:5:22:9 | Address | &:r22_5 |
|
||||
| bad_asts.cpp:22:5:22:9 | Address | &:r22_5 |
|
||||
| bad_asts.cpp:22:5:22:9 | Address | &:r22_7 |
|
||||
@@ -633,6 +664,16 @@
|
||||
| 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_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 |
|
||||
@@ -643,6 +684,16 @@
|
||||
| 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_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 |
|
||||
@@ -675,15 +726,23 @@
|
||||
| file://:0:0:0:0 | Arg(0) | 0:r0_15 |
|
||||
| file://:0:0:0:0 | CallTarget | func:r0_1 |
|
||||
| file://:0:0:0:0 | ChiPartial | partial:m0_2 |
|
||||
| file://:0:0:0:0 | ChiPartial | partial:m0_2 |
|
||||
| file://:0:0:0:0 | ChiPartial | partial:m0_2 |
|
||||
| file://:0:0:0:0 | ChiPartial | partial:m0_3 |
|
||||
| file://:0:0:0:0 | ChiPartial | partial:m0_5 |
|
||||
| file://:0:0:0:0 | ChiPartial | partial:m0_5 |
|
||||
| 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 | ChiTotal | total:m0_3 |
|
||||
| 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 |
|
||||
| file://:0:0:0:0 | ChiTotal | total:m1240_4 |
|
||||
| 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 | Left | r0_2 |
|
||||
| file://:0:0:0:0 | Left | r0_4 |
|
||||
| file://:0:0:0:0 | Left | r0_7 |
|
||||
@@ -692,12 +751,21 @@
|
||||
| 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 | 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 |
|
||||
| file://:0:0:0:0 | Load | m1466_4 |
|
||||
| file://:0:0:0:0 | Load | m1466_4 |
|
||||
| file://:0:0:0:0 | Load | m1685_9 |
|
||||
| file://:0:0:0:0 | Load | m1714_7 |
|
||||
| file://:0:0:0:0 | Load | ~m1444_6 |
|
||||
| file://:0:0:0:0 | Load | ~m1712_10 |
|
||||
| file://:0:0:0:0 | Load | ~m1712_14 |
|
||||
| file://:0:0:0:0 | Right | r0_3 |
|
||||
| file://:0:0:0:0 | Right | r0_5 |
|
||||
| file://:0:0:0:0 | Right | r0_8 |
|
||||
@@ -706,6 +774,11 @@
|
||||
| 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_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 | m1078_23 |
|
||||
| file://:0:0:0:0 | SideEffect | m1078_23 |
|
||||
| file://:0:0:0:0 | SideEffect | m1084_23 |
|
||||
@@ -729,9 +802,13 @@
|
||||
| file://:0:0:0:0 | StoreValue | r0_1 |
|
||||
| file://:0:0:0:0 | StoreValue | r0_1 |
|
||||
| file://:0:0:0:0 | StoreValue | r0_1 |
|
||||
| file://:0:0:0:0 | StoreValue | r0_1 |
|
||||
| file://:0:0:0:0 | StoreValue | r0_1 |
|
||||
| file://:0:0:0:0 | StoreValue | r0_3 |
|
||||
| file://:0:0:0:0 | StoreValue | r0_4 |
|
||||
| file://:0:0:0:0 | StoreValue | r0_4 |
|
||||
| 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_13 |
|
||||
| file://:0:0:0:0 | StoreValue | r0_13 |
|
||||
@@ -6769,13 +6846,110 @@
|
||||
| ir.cpp:1482:8:1482:8 | SideEffect | m1482_8 |
|
||||
| ir.cpp:1486:8:1486:8 | Address | &:r1486_5 |
|
||||
| ir.cpp:1486:8:1486:8 | Address | &:r1486_5 |
|
||||
| ir.cpp:1486:8:1486:8 | Address | &:r1486_5 |
|
||||
| ir.cpp:1486:8:1486:8 | Address | &:r1486_5 |
|
||||
| ir.cpp:1486:8:1486:8 | Address | &:r1486_7 |
|
||||
| ir.cpp:1486:8:1486:8 | Address | &:r1486_7 |
|
||||
| ir.cpp:1486:8:1486:8 | Address | &:r1486_7 |
|
||||
| ir.cpp:1486:8:1486:8 | Address | &:r1486_7 |
|
||||
| ir.cpp:1486:8:1486:8 | Address | &:r1486_9 |
|
||||
| ir.cpp:1486:8:1486:8 | Address | &:r1486_10 |
|
||||
| ir.cpp:1486:8:1486:8 | Address | &:r1486_13 |
|
||||
| ir.cpp:1486:8:1486:8 | Address | &:r1486_17 |
|
||||
| ir.cpp:1486:8:1486:8 | Address | &:r1486_18 |
|
||||
| ir.cpp:1486:8:1486:8 | Address | &:r1486_21 |
|
||||
| ir.cpp:1486:8:1486:8 | Address | &:r1486_25 |
|
||||
| ir.cpp:1486:8:1486:8 | Address | &:r1486_26 |
|
||||
| ir.cpp:1486:8:1486:8 | Address | &:r1486_29 |
|
||||
| ir.cpp:1486:8:1486:8 | Address | &:r1486_33 |
|
||||
| ir.cpp:1486:8:1486:8 | Address | &:r1486_34 |
|
||||
| ir.cpp:1486:8:1486:8 | Address | &:r1486_37 |
|
||||
| ir.cpp:1486:8:1486:8 | Address | &:r1486_41 |
|
||||
| ir.cpp:1486:8:1486:8 | Address | &:r1486_42 |
|
||||
| ir.cpp:1486:8:1486:8 | Address | &:r1486_45 |
|
||||
| ir.cpp:1486:8:1486:8 | Address | &:r1486_49 |
|
||||
| ir.cpp:1486:8:1486:8 | Address | &:r1486_50 |
|
||||
| ir.cpp:1486:8:1486:8 | Address | &:r1486_53 |
|
||||
| ir.cpp:1486:8:1486:8 | Address | &:r1486_57 |
|
||||
| ir.cpp:1486:8:1486:8 | Address | &:r1486_58 |
|
||||
| ir.cpp:1486:8:1486:8 | Address | &:r1486_61 |
|
||||
| ir.cpp:1486:8:1486:8 | Address | &:r1486_65 |
|
||||
| ir.cpp:1486:8:1486:8 | Address | &:r1486_66 |
|
||||
| ir.cpp:1486:8:1486:8 | Address | &:r1486_69 |
|
||||
| ir.cpp:1486:8:1486:8 | ChiPartial | partial:m1486_3 |
|
||||
| ir.cpp:1486:8:1486:8 | ChiPartial | partial:m1486_3 |
|
||||
| ir.cpp:1486:8:1486:8 | ChiPartial | partial:m1486_15 |
|
||||
| ir.cpp:1486:8:1486:8 | ChiPartial | partial:m1486_23 |
|
||||
| ir.cpp:1486:8:1486:8 | ChiPartial | partial:m1486_31 |
|
||||
| ir.cpp:1486:8:1486:8 | ChiPartial | partial:m1486_39 |
|
||||
| ir.cpp:1486:8:1486:8 | ChiPartial | partial:m1486_47 |
|
||||
| ir.cpp:1486:8:1486:8 | ChiPartial | partial:m1486_55 |
|
||||
| ir.cpp:1486:8:1486:8 | ChiPartial | partial:m1486_63 |
|
||||
| ir.cpp:1486:8:1486:8 | ChiPartial | partial:m1486_71 |
|
||||
| ir.cpp:1486:8:1486:8 | ChiTotal | total:m1486_2 |
|
||||
| ir.cpp:1486:8:1486:8 | ChiTotal | total:m1486_2 |
|
||||
| ir.cpp:1486:8:1486:8 | ChiTotal | total:m1486_8 |
|
||||
| ir.cpp:1486:8:1486:8 | ChiTotal | total:m1486_16 |
|
||||
| ir.cpp:1486:8:1486:8 | ChiTotal | total:m1486_24 |
|
||||
| ir.cpp:1486:8:1486:8 | ChiTotal | total:m1486_32 |
|
||||
| ir.cpp:1486:8:1486:8 | ChiTotal | total:m1486_40 |
|
||||
| ir.cpp:1486:8:1486:8 | ChiTotal | total:m1486_48 |
|
||||
| ir.cpp:1486:8:1486:8 | ChiTotal | total:m1486_56 |
|
||||
| ir.cpp:1486:8:1486:8 | ChiTotal | total:m1486_64 |
|
||||
| ir.cpp:1486:8:1486:8 | Load | m0_2 |
|
||||
| ir.cpp:1486:8:1486:8 | Load | m0_2 |
|
||||
| ir.cpp:1486:8:1486:8 | Load | m0_2 |
|
||||
| ir.cpp:1486:8:1486:8 | Load | m0_2 |
|
||||
| ir.cpp:1486:8:1486:8 | Load | m0_2 |
|
||||
| ir.cpp:1486:8:1486:8 | Load | m0_2 |
|
||||
| ir.cpp:1486:8:1486:8 | Load | m0_2 |
|
||||
| ir.cpp:1486:8:1486:8 | Load | m0_2 |
|
||||
| ir.cpp:1486:8:1486:8 | Load | m1486_6 |
|
||||
| ir.cpp:1486:8:1486:8 | Load | m1486_6 |
|
||||
| ir.cpp:1486:8:1486:8 | Load | ~m0_4 |
|
||||
| ir.cpp:1486:8:1486:8 | Load | ~m0_4 |
|
||||
| ir.cpp:1486:8:1486:8 | Load | ~m0_4 |
|
||||
| ir.cpp:1486:8:1486:8 | Load | ~m0_4 |
|
||||
| ir.cpp:1486:8:1486:8 | Load | ~m0_4 |
|
||||
| ir.cpp:1486:8:1486:8 | Load | ~m0_4 |
|
||||
| ir.cpp:1486:8:1486:8 | Load | ~m0_4 |
|
||||
| ir.cpp:1486:8:1486:8 | Load | ~m0_4 |
|
||||
| ir.cpp:1486:8:1486:8 | SideEffect | m1486_3 |
|
||||
| ir.cpp:1486:8:1486:8 | SideEffect | m1486_3 |
|
||||
| ir.cpp:1486:8:1486:8 | SideEffect | m1486_8 |
|
||||
| ir.cpp:1486:8:1486:8 | SideEffect | m1486_72 |
|
||||
| ir.cpp:1486:8:1486:8 | StoreValue | r1486_14 |
|
||||
| ir.cpp:1486:8:1486:8 | StoreValue | r1486_22 |
|
||||
| ir.cpp:1486:8:1486:8 | StoreValue | r1486_30 |
|
||||
| ir.cpp:1486:8:1486:8 | StoreValue | r1486_38 |
|
||||
| ir.cpp:1486:8:1486:8 | StoreValue | r1486_46 |
|
||||
| ir.cpp:1486:8:1486:8 | StoreValue | r1486_54 |
|
||||
| ir.cpp:1486:8:1486:8 | StoreValue | r1486_62 |
|
||||
| ir.cpp:1486:8:1486:8 | StoreValue | r1486_70 |
|
||||
| ir.cpp:1486:8:1486:8 | Unary | m1486_6 |
|
||||
| ir.cpp:1486:8:1486:8 | Unary | m1486_6 |
|
||||
| ir.cpp:1486:8:1486:8 | Unary | m1486_6 |
|
||||
| ir.cpp:1486:8:1486:8 | Unary | m1486_6 |
|
||||
| ir.cpp:1486:8:1486:8 | Unary | m1486_6 |
|
||||
| ir.cpp:1486:8:1486:8 | Unary | m1486_6 |
|
||||
| ir.cpp:1486:8:1486:8 | Unary | m1486_6 |
|
||||
| ir.cpp:1486:8:1486:8 | Unary | m1486_6 |
|
||||
| ir.cpp:1486:8:1486:8 | Unary | r1486_11 |
|
||||
| ir.cpp:1486:8:1486:8 | Unary | r1486_12 |
|
||||
| ir.cpp:1486:8:1486:8 | Unary | r1486_19 |
|
||||
| ir.cpp:1486:8:1486:8 | Unary | r1486_20 |
|
||||
| ir.cpp:1486:8:1486:8 | Unary | r1486_27 |
|
||||
| ir.cpp:1486:8:1486:8 | Unary | r1486_28 |
|
||||
| ir.cpp:1486:8:1486:8 | Unary | r1486_35 |
|
||||
| ir.cpp:1486:8:1486:8 | Unary | r1486_36 |
|
||||
| ir.cpp:1486:8:1486:8 | Unary | r1486_43 |
|
||||
| ir.cpp:1486:8:1486:8 | Unary | r1486_44 |
|
||||
| ir.cpp:1486:8:1486:8 | Unary | r1486_51 |
|
||||
| ir.cpp:1486:8:1486:8 | Unary | r1486_52 |
|
||||
| ir.cpp:1486:8:1486:8 | Unary | r1486_59 |
|
||||
| ir.cpp:1486:8:1486:8 | Unary | r1486_60 |
|
||||
| ir.cpp:1486:8:1486:8 | Unary | r1486_67 |
|
||||
| ir.cpp:1486:8:1486:8 | Unary | r1486_68 |
|
||||
| ir.cpp:1499:6:1499:35 | ChiPartial | partial:m1499_3 |
|
||||
| ir.cpp:1499:6:1499:35 | ChiTotal | total:m1499_2 |
|
||||
| ir.cpp:1499:6:1499:35 | SideEffect | ~m1525_7 |
|
||||
@@ -6948,13 +7122,55 @@
|
||||
| ir.cpp:1528:17:1528:17 | StoreValue | r1528_4 |
|
||||
| ir.cpp:1539:8:1539:8 | Address | &:r1539_5 |
|
||||
| ir.cpp:1539:8:1539:8 | Address | &:r1539_5 |
|
||||
| ir.cpp:1539:8:1539:8 | Address | &:r1539_5 |
|
||||
| ir.cpp:1539:8:1539:8 | Address | &:r1539_5 |
|
||||
| ir.cpp:1539:8:1539:8 | Address | &:r1539_7 |
|
||||
| ir.cpp:1539:8:1539:8 | Address | &:r1539_7 |
|
||||
| ir.cpp:1539:8:1539:8 | Address | &:r1539_7 |
|
||||
| ir.cpp:1539:8:1539:8 | Address | &:r1539_7 |
|
||||
| ir.cpp:1539:8:1539:8 | Address | &:r1539_9 |
|
||||
| ir.cpp:1539:8:1539:8 | Address | &:r1539_10 |
|
||||
| ir.cpp:1539:8:1539:8 | Address | &:r1539_13 |
|
||||
| ir.cpp:1539:8:1539:8 | Address | &:r1539_17 |
|
||||
| ir.cpp:1539:8:1539:8 | Address | &:r1539_18 |
|
||||
| ir.cpp:1539:8:1539:8 | Address | &:r1539_21 |
|
||||
| ir.cpp:1539:8:1539:8 | Address | &:r1539_25 |
|
||||
| ir.cpp:1539:8:1539:8 | Address | &:r1539_26 |
|
||||
| ir.cpp:1539:8:1539:8 | Address | &:r1539_29 |
|
||||
| ir.cpp:1539:8:1539:8 | ChiPartial | partial:m1539_3 |
|
||||
| ir.cpp:1539:8:1539:8 | ChiPartial | partial:m1539_3 |
|
||||
| ir.cpp:1539:8:1539:8 | ChiPartial | partial:m1539_15 |
|
||||
| ir.cpp:1539:8:1539:8 | ChiPartial | partial:m1539_23 |
|
||||
| ir.cpp:1539:8:1539:8 | ChiPartial | partial:m1539_31 |
|
||||
| ir.cpp:1539:8:1539:8 | ChiTotal | total:m1539_2 |
|
||||
| ir.cpp:1539:8:1539:8 | ChiTotal | total:m1539_2 |
|
||||
| ir.cpp:1539:8:1539:8 | ChiTotal | total:m1539_8 |
|
||||
| ir.cpp:1539:8:1539:8 | ChiTotal | total:m1539_16 |
|
||||
| ir.cpp:1539:8:1539:8 | ChiTotal | total:m1539_24 |
|
||||
| ir.cpp:1539:8:1539:8 | Load | m0_2 |
|
||||
| ir.cpp:1539:8:1539:8 | Load | m0_2 |
|
||||
| ir.cpp:1539:8:1539:8 | Load | m0_2 |
|
||||
| ir.cpp:1539:8:1539:8 | Load | m1539_6 |
|
||||
| ir.cpp:1539:8:1539:8 | Load | m1539_6 |
|
||||
| ir.cpp:1539:8:1539:8 | Load | ~m0_4 |
|
||||
| ir.cpp:1539:8:1539:8 | Load | ~m0_4 |
|
||||
| ir.cpp:1539:8:1539:8 | Load | ~m0_4 |
|
||||
| ir.cpp:1539:8:1539:8 | SideEffect | m1539_3 |
|
||||
| ir.cpp:1539:8:1539:8 | SideEffect | m1539_3 |
|
||||
| ir.cpp:1539:8:1539:8 | SideEffect | m1539_8 |
|
||||
| ir.cpp:1539:8:1539:8 | SideEffect | m1539_32 |
|
||||
| ir.cpp:1539:8:1539:8 | StoreValue | r1539_14 |
|
||||
| ir.cpp:1539:8:1539:8 | StoreValue | r1539_22 |
|
||||
| ir.cpp:1539:8:1539:8 | StoreValue | r1539_30 |
|
||||
| ir.cpp:1539:8:1539:8 | Unary | m1539_6 |
|
||||
| ir.cpp:1539:8:1539:8 | Unary | m1539_6 |
|
||||
| ir.cpp:1539:8:1539:8 | Unary | m1539_6 |
|
||||
| ir.cpp:1539:8:1539:8 | Unary | r1539_11 |
|
||||
| ir.cpp:1539:8:1539:8 | Unary | r1539_12 |
|
||||
| ir.cpp:1539:8:1539:8 | Unary | r1539_19 |
|
||||
| ir.cpp:1539:8:1539:8 | Unary | r1539_20 |
|
||||
| ir.cpp:1539:8:1539:8 | Unary | r1539_27 |
|
||||
| ir.cpp:1539:8:1539:8 | Unary | r1539_28 |
|
||||
| ir.cpp:1567:60:1567:95 | Address | &:r1567_5 |
|
||||
| ir.cpp:1567:60:1567:95 | Address | &:r1567_5 |
|
||||
| ir.cpp:1567:60:1567:95 | Address | &:r1567_7 |
|
||||
@@ -7477,15 +7693,20 @@
|
||||
| ir.cpp:1680:5:1680:23 | SideEffect | m1680_8 |
|
||||
| ir.cpp:1683:6:1683:20 | ChiPartial | partial:m1683_3 |
|
||||
| ir.cpp:1683:6:1683:20 | ChiTotal | total:m1683_2 |
|
||||
| ir.cpp:1683:6:1683:20 | SideEffect | ~m1686_6 |
|
||||
| ir.cpp:1683:26:1683:26 | Address | &:r1683_5 |
|
||||
| ir.cpp:1683:34:1683:34 | Address | &:r1683_7 |
|
||||
| ir.cpp:1683:34:1683:34 | Address | &:r1683_7 |
|
||||
| ir.cpp:1683:34:1683:34 | Address | &:r1683_9 |
|
||||
| ir.cpp:1683:34:1683:34 | Address | &:r1683_9 |
|
||||
| ir.cpp:1683:34:1683:34 | Load | m1683_8 |
|
||||
| ir.cpp:1683:34:1683:34 | SideEffect | m1683_10 |
|
||||
| ir.cpp:1683:43:1683:43 | Address | &:r1683_11 |
|
||||
| ir.cpp:1683:43:1683:43 | Address | &:r1683_11 |
|
||||
| ir.cpp:1683:43:1683:43 | Address | &:r1683_13 |
|
||||
| ir.cpp:1683:43:1683:43 | Address | &:r1683_13 |
|
||||
| ir.cpp:1683:43:1683:43 | Load | m1683_12 |
|
||||
| ir.cpp:1683:43:1683:43 | SideEffect | m1683_14 |
|
||||
| ir.cpp:1685:17:1685:20 | Address | &:r1685_1 |
|
||||
| ir.cpp:1685:24:1685:44 | Address | &:r1685_2 |
|
||||
| ir.cpp:1685:24:1685:44 | Address | &:r1685_2 |
|
||||
@@ -7508,16 +7729,104 @@
|
||||
| ir.cpp:1686:16:1686:37 | ChiTotal | total:m1685_7 |
|
||||
| ir.cpp:1686:16:1686:37 | ChiTotal | total:m1686_2 |
|
||||
| ir.cpp:1686:16:1686:37 | SideEffect | ~m1685_7 |
|
||||
| ir.cpp:1688:10:1688:21 | Address | &:r1688_1 |
|
||||
| ir.cpp:1688:24:1690:5 | Address | &:r1688_2 |
|
||||
| ir.cpp:1688:24:1690:5 | Address | &:r1688_2 |
|
||||
| ir.cpp:1688:24:1690:5 | Address | &:r1688_4 |
|
||||
| ir.cpp:1688:24:1690:5 | Address | &:r1688_5 |
|
||||
| ir.cpp:1688:24:1690:5 | Address | &:r1688_6 |
|
||||
| ir.cpp:1688:24:1690:5 | Address | &:r1688_7 |
|
||||
| ir.cpp:1688:24:1690:5 | Address | &:r1688_8 |
|
||||
| ir.cpp:1688:24:1690:5 | Address | &:r1688_12 |
|
||||
| ir.cpp:1688:24:1690:5 | Address | &:r1688_17 |
|
||||
| ir.cpp:1688:24:1690:5 | Address | &:r1688_20 |
|
||||
| ir.cpp:1688:24:1690:5 | ChiPartial | partial:m1688_10 |
|
||||
| ir.cpp:1688:24:1690:5 | ChiTotal | total:m0_3 |
|
||||
| ir.cpp:1688:24:1690:5 | Load | m1685_12 |
|
||||
| ir.cpp:1688:24:1690:5 | Load | m1686_8 |
|
||||
| ir.cpp:1688:24:1690:5 | Load | m1690_6 |
|
||||
| ir.cpp:1688:24:1690:5 | StoreValue | r1688_9 |
|
||||
| ir.cpp:1688:24:1690:5 | StoreValue | r1688_23 |
|
||||
| ir.cpp:1688:24:1690:5 | Unary | r1688_2 |
|
||||
| ir.cpp:1688:24:1690:5 | Unary | r1688_2 |
|
||||
| ir.cpp:1688:24:1690:5 | Unary | r1688_2 |
|
||||
| ir.cpp:1688:24:1690:5 | Unary | r1688_2 |
|
||||
| ir.cpp:1688:24:1690:5 | Unary | r1688_2 |
|
||||
| ir.cpp:1688:38:1688:38 | Address | &:r1688_13 |
|
||||
| ir.cpp:1688:38:1688:38 | ChiPartial | partial:m1688_15 |
|
||||
| ir.cpp:1688:38:1688:38 | ChiTotal | total:m1688_11 |
|
||||
| ir.cpp:1688:38:1688:38 | Load | m1683_6 |
|
||||
| ir.cpp:1688:38:1688:38 | StoreValue | r1688_14 |
|
||||
| ir.cpp:1688:41:1688:41 | Address | &:r1688_18 |
|
||||
| ir.cpp:1688:41:1688:41 | Address | &:r1688_19 |
|
||||
| ir.cpp:1688:41:1688:41 | Load | m1683_8 |
|
||||
| ir.cpp:1688:44:1688:44 | Address | &:r1688_21 |
|
||||
| ir.cpp:1688:44:1688:44 | Address | &:r1688_22 |
|
||||
| ir.cpp:1688:44:1688:44 | Load | m1683_12 |
|
||||
| ir.cpp:1688:46:1688:46 | Address | &:r1688_5 |
|
||||
| ir.cpp:1688:46:1688:46 | Address | &:r1688_5 |
|
||||
| ir.cpp:1688:46:1688:46 | Address | &:r1688_7 |
|
||||
| ir.cpp:1688:46:1688:46 | Address | &:r1688_7 |
|
||||
| ir.cpp:1688:46:1688:46 | ChiPartial | partial:m1688_3 |
|
||||
| ir.cpp:1688:46:1688:46 | ChiTotal | total:m1688_2 |
|
||||
| ir.cpp:1688:46:1688:46 | Load | m1688_6 |
|
||||
| ir.cpp:1688:46:1688:46 | SideEffect | m1688_3 |
|
||||
| ir.cpp:1688:46:1688:46 | SideEffect | m1688_8 |
|
||||
| ir.cpp:1689:14:1689:25 | Address | &:r1689_1 |
|
||||
| ir.cpp:1689:28:1689:54 | Address | &:r1689_2 |
|
||||
| ir.cpp:1689:28:1689:54 | Address | &:r1689_2 |
|
||||
| ir.cpp:1689:28:1689:54 | Address | &:r1689_4 |
|
||||
| ir.cpp:1689:28:1689:54 | Address | &:r1689_5 |
|
||||
| ir.cpp:1689:28:1689:54 | Address | &:r1689_7 |
|
||||
| ir.cpp:1689:28:1689:54 | Address | &:r1689_11 |
|
||||
| ir.cpp:1689:28:1689:54 | Address | &:r1689_12 |
|
||||
| ir.cpp:1689:28:1689:54 | Address | &:r1689_14 |
|
||||
| ir.cpp:1689:28:1689:54 | Address | &:r1689_18 |
|
||||
| ir.cpp:1689:28:1689:54 | Address | &:r1689_19 |
|
||||
| ir.cpp:1689:28:1689:54 | Address | &:r1689_21 |
|
||||
| ir.cpp:1689:28:1689:54 | Address | &:r1689_25 |
|
||||
| ir.cpp:1689:28:1689:54 | Address | &:r1689_26 |
|
||||
| ir.cpp:1689:28:1689:54 | Address | &:r1689_28 |
|
||||
| ir.cpp:1689:28:1689:54 | Address | &:r1689_32 |
|
||||
| ir.cpp:1689:28:1689:54 | Address | &:r1689_33 |
|
||||
| ir.cpp:1689:28:1689:54 | Address | &:r1689_35 |
|
||||
| ir.cpp:1689:28:1689:54 | ChiPartial | partial:m1689_9 |
|
||||
| ir.cpp:1689:28:1689:54 | ChiPartial | partial:m1689_16 |
|
||||
| ir.cpp:1689:28:1689:54 | ChiPartial | partial:m1689_23 |
|
||||
| ir.cpp:1689:28:1689:54 | ChiPartial | partial:m1689_30 |
|
||||
| ir.cpp:1689:28:1689:54 | ChiPartial | partial:m1689_37 |
|
||||
| ir.cpp:1689:28:1689:54 | ChiTotal | total:m1689_3 |
|
||||
| ir.cpp:1689:28:1689:54 | ChiTotal | total:m1689_10 |
|
||||
| ir.cpp:1689:28:1689:54 | ChiTotal | total:m1689_17 |
|
||||
| ir.cpp:1689:28:1689:54 | ChiTotal | total:m1689_24 |
|
||||
| ir.cpp:1689:28:1689:54 | ChiTotal | total:m1689_31 |
|
||||
| ir.cpp:1689:28:1689:54 | Load | m1688_6 |
|
||||
| ir.cpp:1689:28:1689:54 | Load | m1688_6 |
|
||||
| ir.cpp:1689:28:1689:54 | Load | m1688_6 |
|
||||
| ir.cpp:1689:28:1689:54 | Load | m1688_6 |
|
||||
| ir.cpp:1689:28:1689:54 | Load | m1688_6 |
|
||||
| ir.cpp:1689:28:1689:54 | Load | m1689_38 |
|
||||
| ir.cpp:1689:28:1689:54 | Load | ~m1688_8 |
|
||||
| ir.cpp:1689:28:1689:54 | Load | ~m1688_8 |
|
||||
| ir.cpp:1689:28:1689:54 | Load | ~m1688_8 |
|
||||
| ir.cpp:1689:28:1689:54 | Load | ~m1688_8 |
|
||||
| ir.cpp:1689:28:1689:54 | Load | ~m1688_8 |
|
||||
| ir.cpp:1689:28:1689:54 | StoreValue | r1689_8 |
|
||||
| ir.cpp:1689:28:1689:54 | StoreValue | r1689_15 |
|
||||
| ir.cpp:1689:28:1689:54 | StoreValue | r1689_22 |
|
||||
| ir.cpp:1689:28:1689:54 | StoreValue | r1689_29 |
|
||||
| ir.cpp:1689:28:1689:54 | StoreValue | r1689_36 |
|
||||
| ir.cpp:1689:28:1689:54 | StoreValue | r1689_39 |
|
||||
| ir.cpp:1689:28:1689:54 | Unary | r1689_2 |
|
||||
| ir.cpp:1689:28:1689:54 | Unary | r1689_2 |
|
||||
| ir.cpp:1689:28:1689:54 | Unary | r1689_2 |
|
||||
| ir.cpp:1689:28:1689:54 | Unary | r1689_2 |
|
||||
| ir.cpp:1689:28:1689:54 | Unary | r1689_2 |
|
||||
| ir.cpp:1689:28:1689:54 | Unary | r1689_6 |
|
||||
| ir.cpp:1689:28:1689:54 | Unary | r1689_13 |
|
||||
| ir.cpp:1689:28:1689:54 | Unary | r1689_20 |
|
||||
| ir.cpp:1689:28:1689:54 | Unary | r1689_27 |
|
||||
| ir.cpp:1689:28:1689:54 | Unary | r1689_34 |
|
||||
| ir.cpp:1689:50:1689:50 | Address | &:r1689_5 |
|
||||
| ir.cpp:1689:50:1689:50 | Address | &:r1689_5 |
|
||||
| ir.cpp:1689:50:1689:50 | Address | &:r1689_7 |
|
||||
@@ -7527,6 +7836,385 @@
|
||||
| ir.cpp:1689:50:1689:50 | Load | m1689_6 |
|
||||
| ir.cpp:1689:50:1689:50 | SideEffect | m1689_3 |
|
||||
| ir.cpp:1689:50:1689:50 | SideEffect | m1689_8 |
|
||||
| ir.cpp:1690:6:1690:6 | ChiPartial | partial:m1690_2 |
|
||||
| ir.cpp:1690:6:1690:6 | ChiPartial | partial:m1690_5 |
|
||||
| ir.cpp:1690:6:1690:6 | ChiTotal | total:m1688_16 |
|
||||
| ir.cpp:1690:6:1690:6 | ChiTotal | total:m1690_3 |
|
||||
| ir.cpp:1690:6:1690:6 | Load | ~m1683_10 |
|
||||
| ir.cpp:1690:6:1690:6 | Load | ~m1683_14 |
|
||||
| ir.cpp:1690:6:1690:6 | StoreValue | r1690_1 |
|
||||
| ir.cpp:1690:6:1690:6 | StoreValue | r1690_4 |
|
||||
| ir.cpp:1693:5:1693:21 | Address | &:r1693_5 |
|
||||
| ir.cpp:1693:5:1693:21 | ChiPartial | partial:m1693_3 |
|
||||
| ir.cpp:1693:5:1693:21 | ChiTotal | total:m1693_2 |
|
||||
| ir.cpp:1693:5:1693:21 | Load | m1696_4 |
|
||||
| ir.cpp:1693:5:1693:21 | SideEffect | m1693_3 |
|
||||
| ir.cpp:1694:7:1694:7 | Address | &:r1694_1 |
|
||||
| ir.cpp:1694:10:1694:12 | StoreValue | r1694_2 |
|
||||
| ir.cpp:1696:3:1696:11 | Address | &:r1696_1 |
|
||||
| ir.cpp:1696:10:1696:10 | Address | &:r1696_2 |
|
||||
| ir.cpp:1696:10:1696:10 | Load | m1694_3 |
|
||||
| ir.cpp:1696:10:1696:10 | StoreValue | r1696_3 |
|
||||
| ir.cpp:1701:10:1701:10 | Address | &:r1701_5 |
|
||||
| ir.cpp:1701:10:1701:10 | Address | &:r1701_5 |
|
||||
| ir.cpp:1701:10:1701:10 | Address | &:r1701_7 |
|
||||
| ir.cpp:1701:10:1701:10 | Address | &:r1701_7 |
|
||||
| ir.cpp:1701:10:1701:10 | ChiPartial | partial:m1701_3 |
|
||||
| ir.cpp:1701:10:1701:10 | ChiTotal | total:m1701_2 |
|
||||
| ir.cpp:1701:10:1701:10 | Load | m1701_6 |
|
||||
| ir.cpp:1701:10:1701:10 | SideEffect | m1701_3 |
|
||||
| ir.cpp:1701:10:1701:10 | SideEffect | m1701_8 |
|
||||
| ir.cpp:1702:14:1702:22 | Address | &:r1702_1 |
|
||||
| ir.cpp:1702:25:1708:9 | Address | &:r1702_2 |
|
||||
| ir.cpp:1702:25:1708:9 | Address | &:r1702_2 |
|
||||
| ir.cpp:1702:25:1708:9 | Address | &:r1702_4 |
|
||||
| ir.cpp:1702:25:1708:9 | Address | &:r1702_5 |
|
||||
| ir.cpp:1702:25:1708:9 | Address | &:r1702_6 |
|
||||
| ir.cpp:1702:25:1708:9 | Load | m1701_6 |
|
||||
| ir.cpp:1702:25:1708:9 | Load | ~m1701_8 |
|
||||
| ir.cpp:1702:25:1708:9 | Load | ~m1702_8 |
|
||||
| ir.cpp:1702:25:1708:9 | StoreValue | r1702_7 |
|
||||
| ir.cpp:1702:25:1708:9 | StoreValue | r1702_9 |
|
||||
| ir.cpp:1702:25:1708:9 | Unary | r1702_2 |
|
||||
| ir.cpp:1702:34:1702:34 | Address | &:r1702_5 |
|
||||
| ir.cpp:1702:34:1702:34 | Address | &:r1702_5 |
|
||||
| ir.cpp:1702:34:1702:34 | Address | &:r1702_7 |
|
||||
| ir.cpp:1702:34:1702:34 | Address | &:r1702_7 |
|
||||
| ir.cpp:1702:34:1702:34 | ChiPartial | partial:m1702_3 |
|
||||
| ir.cpp:1702:34:1702:34 | ChiTotal | total:m1702_2 |
|
||||
| ir.cpp:1702:34:1702:34 | Load | m1702_6 |
|
||||
| ir.cpp:1702:34:1702:34 | SideEffect | m1702_8 |
|
||||
| ir.cpp:1702:34:1702:34 | SideEffect | ~m1703_8 |
|
||||
| ir.cpp:1703:13:1703:13 | Address | &:r1703_1 |
|
||||
| ir.cpp:1703:13:1703:13 | Address | &:r1703_4 |
|
||||
| ir.cpp:1703:13:1703:13 | Arg(this) | this:r1703_4 |
|
||||
| ir.cpp:1703:13:1703:13 | CallTarget | func:r1703_5 |
|
||||
| ir.cpp:1703:13:1703:13 | ChiPartial | partial:m1703_7 |
|
||||
| ir.cpp:1703:13:1703:13 | ChiTotal | total:m1702_4 |
|
||||
| ir.cpp:1703:13:1703:13 | Load | m1702_6 |
|
||||
| ir.cpp:1703:13:1703:13 | SideEffect | ~m1702_4 |
|
||||
| ir.cpp:1703:13:1703:13 | SideEffect | ~m1702_8 |
|
||||
| ir.cpp:1703:13:1703:13 | Unary | r1703_2 |
|
||||
| ir.cpp:1703:13:1703:13 | Unary | r1703_3 |
|
||||
| ir.cpp:1705:18:1705:26 | Address | &:r1705_1 |
|
||||
| ir.cpp:1705:29:1707:13 | Address | &:r1705_2 |
|
||||
| ir.cpp:1705:29:1707:13 | Address | &:r1705_2 |
|
||||
| ir.cpp:1705:29:1707:13 | Address | &:r1705_4 |
|
||||
| ir.cpp:1705:29:1707:13 | Address | &:r1705_5 |
|
||||
| ir.cpp:1705:29:1707:13 | Address | &:r1705_7 |
|
||||
| ir.cpp:1705:29:1707:13 | Load | m1702_6 |
|
||||
| ir.cpp:1705:29:1707:13 | Load | ~m1702_8 |
|
||||
| ir.cpp:1705:29:1707:13 | Load | ~m1705_9 |
|
||||
| ir.cpp:1705:29:1707:13 | StoreValue | r1705_8 |
|
||||
| ir.cpp:1705:29:1707:13 | StoreValue | r1705_10 |
|
||||
| ir.cpp:1705:29:1707:13 | Unary | r1705_2 |
|
||||
| ir.cpp:1705:29:1707:13 | Unary | r1705_6 |
|
||||
| ir.cpp:1705:38:1705:38 | Address | &:r1705_5 |
|
||||
| ir.cpp:1705:38:1705:38 | Address | &:r1705_5 |
|
||||
| ir.cpp:1705:38:1705:38 | Address | &:r1705_7 |
|
||||
| ir.cpp:1705:38:1705:38 | Address | &:r1705_7 |
|
||||
| ir.cpp:1705:38:1705:38 | ChiPartial | partial:m1705_3 |
|
||||
| ir.cpp:1705:38:1705:38 | ChiTotal | total:m1705_2 |
|
||||
| ir.cpp:1705:38:1705:38 | Load | m1705_6 |
|
||||
| ir.cpp:1705:38:1705:38 | SideEffect | m1705_8 |
|
||||
| ir.cpp:1705:38:1705:38 | SideEffect | ~m1706_8 |
|
||||
| ir.cpp:1706:17:1706:17 | Address | &:r1706_1 |
|
||||
| ir.cpp:1706:17:1706:17 | Address | &:r1706_4 |
|
||||
| ir.cpp:1706:17:1706:17 | Arg(this) | this:r1706_4 |
|
||||
| ir.cpp:1706:17:1706:17 | CallTarget | func:r1706_5 |
|
||||
| ir.cpp:1706:17:1706:17 | ChiPartial | partial:m1706_7 |
|
||||
| ir.cpp:1706:17:1706:17 | ChiTotal | total:m1705_4 |
|
||||
| ir.cpp:1706:17:1706:17 | Load | m1705_6 |
|
||||
| ir.cpp:1706:17:1706:17 | SideEffect | ~m1705_4 |
|
||||
| ir.cpp:1706:17:1706:17 | SideEffect | ~m1705_8 |
|
||||
| ir.cpp:1706:17:1706:17 | Unary | r1706_2 |
|
||||
| ir.cpp:1706:17:1706:17 | Unary | r1706_3 |
|
||||
| ir.cpp:1712:6:1712:21 | ChiPartial | partial:m1712_3 |
|
||||
| ir.cpp:1712:6:1712:21 | ChiTotal | total:m1712_2 |
|
||||
| ir.cpp:1712:6:1712:21 | SideEffect | m1712_3 |
|
||||
| ir.cpp:1712:42:1712:43 | Address | &:r1712_5 |
|
||||
| ir.cpp:1712:66:1712:67 | Address | &:r1712_7 |
|
||||
| ir.cpp:1712:66:1712:67 | Address | &:r1712_7 |
|
||||
| ir.cpp:1712:66:1712:67 | Address | &:r1712_9 |
|
||||
| ir.cpp:1712:66:1712:67 | Address | &:r1712_9 |
|
||||
| ir.cpp:1712:66:1712:67 | Load | m1712_8 |
|
||||
| ir.cpp:1712:66:1712:67 | SideEffect | m1712_10 |
|
||||
| ir.cpp:1712:91:1712:92 | Address | &:r1712_11 |
|
||||
| ir.cpp:1712:91:1712:92 | Address | &:r1712_11 |
|
||||
| ir.cpp:1712:91:1712:92 | Address | &:r1712_13 |
|
||||
| ir.cpp:1712:91:1712:92 | Address | &:r1712_13 |
|
||||
| ir.cpp:1712:91:1712:92 | Load | m1712_12 |
|
||||
| ir.cpp:1712:91:1712:92 | SideEffect | m1712_14 |
|
||||
| ir.cpp:1713:30:1713:31 | Address | &:r1713_1 |
|
||||
| ir.cpp:1714:31:1714:32 | Address | &:r1714_1 |
|
||||
| ir.cpp:1714:36:1714:55 | Address | &:r1714_2 |
|
||||
| ir.cpp:1714:36:1714:55 | Address | &:r1714_3 |
|
||||
| ir.cpp:1714:36:1714:55 | Address | &:r1714_3 |
|
||||
| ir.cpp:1714:36:1714:55 | Load | m1714_5 |
|
||||
| ir.cpp:1714:36:1714:55 | StoreValue | r1714_4 |
|
||||
| ir.cpp:1714:36:1714:55 | StoreValue | r1714_6 |
|
||||
| ir.cpp:1714:36:1714:55 | StoreValue | r1714_9 |
|
||||
| ir.cpp:1714:36:1714:55 | Unary | r1714_2 |
|
||||
| ir.cpp:1714:36:1714:55 | Unary | r1714_8 |
|
||||
| ir.cpp:1716:10:1716:17 | Address | &:r1716_1 |
|
||||
| ir.cpp:1716:20:1718:5 | Address | &:r1716_2 |
|
||||
| ir.cpp:1716:20:1718:5 | Address | &:r1716_2 |
|
||||
| ir.cpp:1716:20:1718:5 | Address | &:r1716_4 |
|
||||
| ir.cpp:1716:20:1718:5 | Address | &:r1716_5 |
|
||||
| ir.cpp:1716:20:1718:5 | Address | &:r1716_9 |
|
||||
| ir.cpp:1716:20:1718:5 | Address | &:r1716_10 |
|
||||
| ir.cpp:1716:20:1718:5 | Address | &:r1716_11 |
|
||||
| ir.cpp:1716:20:1718:5 | Address | &:r1716_12 |
|
||||
| ir.cpp:1716:20:1718:5 | Address | &:r1716_13 |
|
||||
| ir.cpp:1716:20:1718:5 | Address | &:r1716_14 |
|
||||
| ir.cpp:1716:20:1718:5 | Address | &:r1716_15 |
|
||||
| ir.cpp:1716:20:1718:5 | Address | &:r1716_16 |
|
||||
| ir.cpp:1716:20:1718:5 | Address | &:r1716_20 |
|
||||
| ir.cpp:1716:20:1718:5 | Address | &:r1716_21 |
|
||||
| ir.cpp:1716:20:1718:5 | Address | &:r1716_22 |
|
||||
| ir.cpp:1716:20:1718:5 | ChiPartial | partial:m1716_7 |
|
||||
| ir.cpp:1716:20:1718:5 | ChiPartial | partial:m1716_18 |
|
||||
| ir.cpp:1716:20:1718:5 | ChiTotal | total:m0_6 |
|
||||
| ir.cpp:1716:20:1718:5 | ChiTotal | total:m1716_3 |
|
||||
| ir.cpp:1716:20:1718:5 | Load | m0_9 |
|
||||
| ir.cpp:1716:20:1718:5 | Load | m1712_6 |
|
||||
| ir.cpp:1716:20:1718:5 | Load | m1712_8 |
|
||||
| ir.cpp:1716:20:1718:5 | Load | m1712_12 |
|
||||
| ir.cpp:1716:20:1718:5 | Load | m1713_2 |
|
||||
| ir.cpp:1716:20:1718:5 | Load | m1714_10 |
|
||||
| ir.cpp:1716:20:1718:5 | StoreValue | r1716_6 |
|
||||
| ir.cpp:1716:20:1718:5 | StoreValue | r1716_17 |
|
||||
| ir.cpp:1716:20:1718:5 | StoreValue | r1716_23 |
|
||||
| ir.cpp:1716:20:1718:5 | Unary | r1716_2 |
|
||||
| ir.cpp:1716:20:1718:5 | Unary | r1716_2 |
|
||||
| ir.cpp:1716:20:1718:5 | Unary | r1716_2 |
|
||||
| ir.cpp:1716:20:1718:5 | Unary | r1716_2 |
|
||||
| ir.cpp:1716:20:1718:5 | Unary | r1716_2 |
|
||||
| ir.cpp:1716:42:1716:42 | Address | &:r1716_5 |
|
||||
| ir.cpp:1716:42:1716:42 | Address | &:r1716_5 |
|
||||
| ir.cpp:1716:42:1716:42 | Address | &:r1716_7 |
|
||||
| ir.cpp:1716:42:1716:42 | Address | &:r1716_7 |
|
||||
| ir.cpp:1716:42:1716:42 | ChiPartial | partial:m1716_3 |
|
||||
| ir.cpp:1716:42:1716:42 | ChiTotal | total:m1716_2 |
|
||||
| ir.cpp:1716:42:1716:42 | Load | m1716_6 |
|
||||
| ir.cpp:1716:42:1716:42 | SideEffect | m1716_3 |
|
||||
| ir.cpp:1716:42:1716:42 | SideEffect | m1716_8 |
|
||||
| ir.cpp:1717:14:1717:21 | Address | &:r1717_1 |
|
||||
| ir.cpp:1717:24:1717:31 | Address | &:r1717_2 |
|
||||
| ir.cpp:1717:24:1717:31 | Address | &:r1717_2 |
|
||||
| ir.cpp:1717:24:1717:31 | Address | &:r1717_4 |
|
||||
| ir.cpp:1717:24:1717:31 | Address | &:r1717_5 |
|
||||
| ir.cpp:1717:24:1717:31 | Address | &:r1717_7 |
|
||||
| ir.cpp:1717:24:1717:31 | Load | m1716_6 |
|
||||
| ir.cpp:1717:24:1717:31 | Load | ~m1716_8 |
|
||||
| ir.cpp:1717:24:1717:31 | Load | ~m1717_9 |
|
||||
| ir.cpp:1717:24:1717:31 | StoreValue | r1717_8 |
|
||||
| ir.cpp:1717:24:1717:31 | StoreValue | r1717_10 |
|
||||
| ir.cpp:1717:24:1717:31 | Unary | r1717_2 |
|
||||
| ir.cpp:1717:24:1717:31 | Unary | r1717_6 |
|
||||
| ir.cpp:1717:30:1717:30 | Address | &:r1717_5 |
|
||||
| ir.cpp:1717:30:1717:30 | Address | &:r1717_5 |
|
||||
| ir.cpp:1717:30:1717:30 | Address | &:r1717_7 |
|
||||
| ir.cpp:1717:30:1717:30 | Address | &:r1717_7 |
|
||||
| ir.cpp:1717:30:1717:30 | ChiPartial | partial:m1717_3 |
|
||||
| ir.cpp:1717:30:1717:30 | ChiTotal | total:m1717_2 |
|
||||
| ir.cpp:1717:30:1717:30 | Load | m1717_6 |
|
||||
| ir.cpp:1717:30:1717:30 | SideEffect | m1717_3 |
|
||||
| ir.cpp:1717:30:1717:30 | SideEffect | m1717_8 |
|
||||
| ir.cpp:1724:5:1724:44 | Address | &:r1724_5 |
|
||||
| ir.cpp:1724:5:1724:44 | Address | &:r1724_5 |
|
||||
| ir.cpp:1724:5:1724:44 | Address | &:r1724_7 |
|
||||
| ir.cpp:1724:5:1724:44 | Address | &:r1724_7 |
|
||||
| ir.cpp:1724:5:1724:44 | ChiPartial | partial:m1724_3 |
|
||||
| ir.cpp:1724:5:1724:44 | ChiTotal | total:m1724_2 |
|
||||
| ir.cpp:1724:5:1724:44 | Load | m1724_6 |
|
||||
| ir.cpp:1724:5:1724:44 | SideEffect | m1724_3 |
|
||||
| ir.cpp:1724:5:1724:44 | SideEffect | m1724_8 |
|
||||
| ir.cpp:1725:5:1725:44 | Address | &:r1725_5 |
|
||||
| ir.cpp:1725:5:1725:44 | Address | &:r1725_5 |
|
||||
| ir.cpp:1725:5:1725:44 | Address | &:r1725_7 |
|
||||
| ir.cpp:1725:5:1725:44 | Address | &:r1725_7 |
|
||||
| ir.cpp:1725:5:1725:44 | ChiPartial | partial:m1725_3 |
|
||||
| ir.cpp:1725:5:1725:44 | ChiTotal | total:m1725_2 |
|
||||
| ir.cpp:1725:5:1725:44 | Load | m1725_6 |
|
||||
| ir.cpp:1725:5:1725:44 | SideEffect | m1725_3 |
|
||||
| ir.cpp:1725:5:1725:44 | SideEffect | m1726_10 |
|
||||
| ir.cpp:1725:94:1725:94 | Address | &:r1725_9 |
|
||||
| ir.cpp:1725:94:1725:94 | Address | &:r1725_9 |
|
||||
| ir.cpp:1725:94:1725:94 | Address | &:r1725_11 |
|
||||
| ir.cpp:1725:94:1725:94 | Address | &:r1725_11 |
|
||||
| ir.cpp:1725:94:1725:94 | Load | m1725_10 |
|
||||
| ir.cpp:1725:94:1725:94 | SideEffect | m1725_12 |
|
||||
| ir.cpp:1726:9:1726:9 | Address | &:r1726_6 |
|
||||
| ir.cpp:1726:9:1726:9 | Address | &:r1726_8 |
|
||||
| ir.cpp:1726:9:1726:9 | Load | m1725_6 |
|
||||
| ir.cpp:1726:9:1726:9 | Unary | r1726_7 |
|
||||
| ir.cpp:1726:9:1726:15 | ChiPartial | partial:m1726_9 |
|
||||
| ir.cpp:1726:9:1726:15 | ChiTotal | total:m1725_8 |
|
||||
| ir.cpp:1726:13:1726:13 | Address | &:r1726_1 |
|
||||
| ir.cpp:1726:13:1726:13 | Load | m1725_10 |
|
||||
| ir.cpp:1726:13:1726:13 | Unary | r1726_2 |
|
||||
| ir.cpp:1726:13:1726:13 | Unary | r1726_3 |
|
||||
| ir.cpp:1726:15:1726:15 | Address | &:r1726_4 |
|
||||
| ir.cpp:1726:15:1726:15 | Load | ~m1725_12 |
|
||||
| ir.cpp:1726:15:1726:15 | StoreValue | r1726_5 |
|
||||
| ir.cpp:1733:5:1733:39 | Address | &:r1733_5 |
|
||||
| ir.cpp:1733:5:1733:39 | Address | &:r1733_5 |
|
||||
| ir.cpp:1733:5:1733:39 | Address | &:r1733_7 |
|
||||
| ir.cpp:1733:5:1733:39 | Address | &:r1733_7 |
|
||||
| ir.cpp:1733:5:1733:39 | ChiPartial | partial:m1733_3 |
|
||||
| ir.cpp:1733:5:1733:39 | ChiTotal | total:m1733_2 |
|
||||
| ir.cpp:1733:5:1733:39 | Load | m1733_6 |
|
||||
| ir.cpp:1733:5:1733:39 | SideEffect | m1733_3 |
|
||||
| ir.cpp:1733:5:1733:39 | SideEffect | m1733_8 |
|
||||
| ir.cpp:1736:7:1736:7 | Address | &:r1736_5 |
|
||||
| ir.cpp:1736:7:1736:7 | Address | &:r1736_5 |
|
||||
| ir.cpp:1736:7:1736:7 | Address | &:r1736_7 |
|
||||
| ir.cpp:1736:7:1736:7 | Address | &:r1736_7 |
|
||||
| ir.cpp:1736:7:1736:7 | Address | &:r1736_9 |
|
||||
| ir.cpp:1736:7:1736:7 | Address | &:r1736_11 |
|
||||
| ir.cpp:1736:7:1736:7 | Address | &:r1736_15 |
|
||||
| ir.cpp:1736:7:1736:7 | Arg(0) | 0:r1736_15 |
|
||||
| ir.cpp:1736:7:1736:7 | Arg(this) | this:r1736_9 |
|
||||
| ir.cpp:1736:7:1736:7 | CallTarget | func:r1736_10 |
|
||||
| ir.cpp:1736:7:1736:7 | ChiPartial | partial:m1736_3 |
|
||||
| ir.cpp:1736:7:1736:7 | ChiPartial | partial:m1736_17 |
|
||||
| ir.cpp:1736:7:1736:7 | ChiPartial | partial:m1736_20 |
|
||||
| ir.cpp:1736:7:1736:7 | ChiTotal | total:m1736_2 |
|
||||
| ir.cpp:1736:7:1736:7 | ChiTotal | total:m1736_4 |
|
||||
| ir.cpp:1736:7:1736:7 | ChiTotal | total:m1736_8 |
|
||||
| ir.cpp:1736:7:1736:7 | Load | m0_2 |
|
||||
| ir.cpp:1736:7:1736:7 | Load | m1736_6 |
|
||||
| ir.cpp:1736:7:1736:7 | SideEffect | m1736_21 |
|
||||
| ir.cpp:1736:7:1736:7 | SideEffect | ~m0_4 |
|
||||
| ir.cpp:1736:7:1736:7 | SideEffect | ~m1736_4 |
|
||||
| ir.cpp:1736:7:1736:7 | SideEffect | ~m1736_18 |
|
||||
| ir.cpp:1736:7:1736:7 | Unary | m1736_6 |
|
||||
| ir.cpp:1736:7:1736:7 | Unary | r1736_12 |
|
||||
| ir.cpp:1736:7:1736:7 | Unary | r1736_13 |
|
||||
| ir.cpp:1736:7:1736:7 | Unary | r1736_14 |
|
||||
| ir.cpp:1740:5:1740:38 | Address | &:r1740_5 |
|
||||
| ir.cpp:1740:5:1740:38 | Address | &:r1740_5 |
|
||||
| ir.cpp:1740:5:1740:38 | Address | &:r1740_7 |
|
||||
| ir.cpp:1740:5:1740:38 | Address | &:r1740_7 |
|
||||
| ir.cpp:1740:5:1740:38 | ChiPartial | partial:m1740_3 |
|
||||
| ir.cpp:1740:5:1740:38 | ChiTotal | total:m1740_2 |
|
||||
| ir.cpp:1740:5:1740:38 | Load | m1740_6 |
|
||||
| ir.cpp:1740:5:1740:38 | SideEffect | m1740_22 |
|
||||
| ir.cpp:1740:5:1740:38 | SideEffect | ~m1740_20 |
|
||||
| ir.cpp:1740:5:1740:38 | Unary | m1740_6 |
|
||||
| ir.cpp:1740:5:1740:38 | Unary | m1740_6 |
|
||||
| ir.cpp:1740:42:1740:42 | Address | &:r1740_9 |
|
||||
| ir.cpp:1740:42:1740:42 | Address | &:r1740_16 |
|
||||
| ir.cpp:1740:42:1740:42 | Arg(this) | this:r1740_9 |
|
||||
| ir.cpp:1740:42:1740:42 | Arg(this) | this:r1740_16 |
|
||||
| ir.cpp:1740:42:1740:42 | CallTarget | func:r1740_10 |
|
||||
| ir.cpp:1740:42:1740:42 | CallTarget | func:r1740_17 |
|
||||
| ir.cpp:1740:42:1740:42 | ChiPartial | partial:m1740_12 |
|
||||
| ir.cpp:1740:42:1740:42 | ChiPartial | partial:m1740_14 |
|
||||
| ir.cpp:1740:42:1740:42 | ChiPartial | partial:m1740_19 |
|
||||
| ir.cpp:1740:42:1740:42 | ChiPartial | partial:m1740_21 |
|
||||
| ir.cpp:1740:42:1740:42 | ChiTotal | total:m1740_4 |
|
||||
| ir.cpp:1740:42:1740:42 | ChiTotal | total:m1740_8 |
|
||||
| ir.cpp:1740:42:1740:42 | ChiTotal | total:m1740_13 |
|
||||
| ir.cpp:1740:42:1740:42 | ChiTotal | total:m1740_15 |
|
||||
| ir.cpp:1740:42:1740:42 | SideEffect | ~m1740_4 |
|
||||
| ir.cpp:1740:42:1740:42 | SideEffect | ~m1740_13 |
|
||||
| ir.cpp:1743:7:1743:7 | Address | &:r1743_5 |
|
||||
| ir.cpp:1743:7:1743:7 | Address | &:r1743_5 |
|
||||
| ir.cpp:1743:7:1743:7 | Address | &:r1743_7 |
|
||||
| ir.cpp:1743:7:1743:7 | Address | &:r1743_7 |
|
||||
| ir.cpp:1743:7:1743:7 | Address | &:r1743_9 |
|
||||
| ir.cpp:1743:7:1743:7 | Address | &:r1743_11 |
|
||||
| ir.cpp:1743:7:1743:7 | Address | &:r1743_15 |
|
||||
| ir.cpp:1743:7:1743:7 | Arg(0) | 0:r1743_15 |
|
||||
| ir.cpp:1743:7:1743:7 | Arg(this) | this:r1743_9 |
|
||||
| ir.cpp:1743:7:1743:7 | CallTarget | func:r1743_10 |
|
||||
| ir.cpp:1743:7:1743:7 | ChiPartial | partial:m1743_3 |
|
||||
| ir.cpp:1743:7:1743:7 | ChiPartial | partial:m1743_17 |
|
||||
| ir.cpp:1743:7:1743:7 | ChiPartial | partial:m1743_20 |
|
||||
| ir.cpp:1743:7:1743:7 | ChiTotal | total:m1743_2 |
|
||||
| ir.cpp:1743:7:1743:7 | ChiTotal | total:m1743_4 |
|
||||
| ir.cpp:1743:7:1743:7 | ChiTotal | total:m1743_18 |
|
||||
| ir.cpp:1743:7:1743:7 | Load | m0_2 |
|
||||
| ir.cpp:1743:7:1743:7 | Load | m1743_6 |
|
||||
| ir.cpp:1743:7:1743:7 | SideEffect | m1743_8 |
|
||||
| ir.cpp:1743:7:1743:7 | SideEffect | ~m0_4 |
|
||||
| ir.cpp:1743:7:1743:7 | SideEffect | ~m1743_4 |
|
||||
| ir.cpp:1743:7:1743:7 | SideEffect | ~m1743_21 |
|
||||
| ir.cpp:1743:7:1743:7 | Unary | m1743_6 |
|
||||
| ir.cpp:1743:7:1743:7 | Unary | r1743_12 |
|
||||
| ir.cpp:1743:7:1743:7 | Unary | r1743_13 |
|
||||
| ir.cpp:1743:7:1743:7 | Unary | r1743_14 |
|
||||
| ir.cpp:1747:5:1747:35 | Address | &:r1747_5 |
|
||||
| ir.cpp:1747:5:1747:35 | Address | &:r1747_5 |
|
||||
| ir.cpp:1747:5:1747:35 | Address | &:r1747_7 |
|
||||
| ir.cpp:1747:5:1747:35 | Address | &:r1747_7 |
|
||||
| ir.cpp:1747:5:1747:35 | ChiPartial | partial:m1747_3 |
|
||||
| ir.cpp:1747:5:1747:35 | ChiTotal | total:m1747_2 |
|
||||
| ir.cpp:1747:5:1747:35 | Load | m1747_6 |
|
||||
| ir.cpp:1747:5:1747:35 | SideEffect | m1747_8 |
|
||||
| ir.cpp:1747:5:1747:35 | SideEffect | ~m1747_22 |
|
||||
| ir.cpp:1747:5:1747:35 | Unary | m1747_6 |
|
||||
| ir.cpp:1747:5:1747:35 | Unary | m1747_6 |
|
||||
| ir.cpp:1747:39:1747:39 | Address | &:r1747_9 |
|
||||
| ir.cpp:1747:39:1747:39 | Address | &:r1747_16 |
|
||||
| ir.cpp:1747:39:1747:39 | Arg(this) | this:r1747_9 |
|
||||
| ir.cpp:1747:39:1747:39 | Arg(this) | this:r1747_16 |
|
||||
| ir.cpp:1747:39:1747:39 | CallTarget | func:r1747_10 |
|
||||
| ir.cpp:1747:39:1747:39 | CallTarget | func:r1747_17 |
|
||||
| ir.cpp:1747:39:1747:39 | ChiPartial | partial:m1747_12 |
|
||||
| ir.cpp:1747:39:1747:39 | ChiPartial | partial:m1747_14 |
|
||||
| ir.cpp:1747:39:1747:39 | ChiPartial | partial:m1747_19 |
|
||||
| ir.cpp:1747:39:1747:39 | ChiPartial | partial:m1747_21 |
|
||||
| ir.cpp:1747:39:1747:39 | ChiTotal | total:m1747_4 |
|
||||
| ir.cpp:1747:39:1747:39 | ChiTotal | total:m1747_13 |
|
||||
| ir.cpp:1747:39:1747:39 | ChiTotal | total:m1747_15 |
|
||||
| ir.cpp:1747:39:1747:39 | ChiTotal | total:m1747_20 |
|
||||
| ir.cpp:1747:39:1747:39 | SideEffect | ~m1747_4 |
|
||||
| ir.cpp:1747:39:1747:39 | SideEffect | ~m1747_15 |
|
||||
| ir.cpp:1750:5:1750:34 | ChiPartial | partial:m1750_3 |
|
||||
| ir.cpp:1750:5:1750:34 | ChiTotal | total:m1750_2 |
|
||||
| ir.cpp:1751:51:1751:51 | Address | &:r1751_1 |
|
||||
| ir.cpp:1751:51:1751:51 | Address | &:r1751_1 |
|
||||
| ir.cpp:1751:51:1751:51 | Address | &:r1751_3 |
|
||||
| ir.cpp:1751:51:1751:51 | Load | m1751_2 |
|
||||
| ir.cpp:1752:48:1752:48 | Address | &:r1752_1 |
|
||||
| ir.cpp:1752:48:1752:48 | Address | &:r1752_1 |
|
||||
| ir.cpp:1752:48:1752:48 | Address | &:r1752_3 |
|
||||
| ir.cpp:1752:48:1752:48 | Load | m1752_2 |
|
||||
| ir.cpp:1753:40:1753:41 | Address | &:r1753_1 |
|
||||
| ir.cpp:1753:40:1753:41 | Address | &:r1753_1 |
|
||||
| ir.cpp:1753:40:1753:41 | Arg(this) | this:r1753_1 |
|
||||
| ir.cpp:1753:44:1753:45 | CallTarget | func:r1753_3 |
|
||||
| ir.cpp:1753:44:1753:45 | ChiPartial | partial:m1753_9 |
|
||||
| ir.cpp:1753:44:1753:45 | ChiPartial | partial:m1753_12 |
|
||||
| ir.cpp:1753:44:1753:45 | ChiTotal | total:m1750_4 |
|
||||
| ir.cpp:1753:44:1753:45 | ChiTotal | total:m1753_2 |
|
||||
| ir.cpp:1753:44:1753:45 | SideEffect | ~m1750_4 |
|
||||
| ir.cpp:1753:45:1753:45 | Address | &:r1753_4 |
|
||||
| ir.cpp:1753:45:1753:45 | Address | &:r1753_7 |
|
||||
| ir.cpp:1753:45:1753:45 | Arg(0) | 0:r1753_7 |
|
||||
| ir.cpp:1753:45:1753:45 | Load | m1751_2 |
|
||||
| ir.cpp:1753:45:1753:45 | SideEffect | ~m1751_4 |
|
||||
| ir.cpp:1753:45:1753:45 | Unary | r1753_5 |
|
||||
| ir.cpp:1753:45:1753:45 | Unary | r1753_6 |
|
||||
| ir.cpp:1754:37:1754:38 | Address | &:r1754_1 |
|
||||
| ir.cpp:1754:37:1754:38 | Address | &:r1754_1 |
|
||||
| ir.cpp:1754:37:1754:38 | Arg(this) | this:r1754_1 |
|
||||
| ir.cpp:1754:41:1754:42 | CallTarget | func:r1754_3 |
|
||||
| ir.cpp:1754:41:1754:42 | ChiPartial | partial:m1754_9 |
|
||||
| ir.cpp:1754:41:1754:42 | ChiPartial | partial:m1754_12 |
|
||||
| ir.cpp:1754:41:1754:42 | ChiTotal | total:m1753_10 |
|
||||
| ir.cpp:1754:41:1754:42 | ChiTotal | total:m1754_2 |
|
||||
| ir.cpp:1754:41:1754:42 | SideEffect | ~m1753_10 |
|
||||
| ir.cpp:1754:42:1754:42 | Address | &:r1754_4 |
|
||||
| ir.cpp:1754:42:1754:42 | Address | &:r1754_7 |
|
||||
| ir.cpp:1754:42:1754:42 | Arg(0) | 0:r1754_7 |
|
||||
| ir.cpp:1754:42:1754:42 | Load | m1752_2 |
|
||||
| ir.cpp:1754:42:1754:42 | SideEffect | ~m1752_4 |
|
||||
| ir.cpp:1754:42:1754:42 | Unary | r1754_5 |
|
||||
| ir.cpp:1754:42:1754:42 | Unary | r1754_6 |
|
||||
| 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 |
|
||||
|
||||
@@ -1,8 +1,4 @@
|
||||
missingOperand
|
||||
| ir.cpp:1688:24:1690:5 | Store: Unknown literal | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | ir.cpp:1683:6:1683:20 | void captured_lambda(int, int&, int&&) | void captured_lambda(int, int&, int&&) |
|
||||
| ir.cpp:1688:24:1690:5 | Store: Unknown literal | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | ir.cpp:1683:6:1683:20 | void captured_lambda(int, int&, int&&) | void captured_lambda(int, int&, int&&) |
|
||||
| ir.cpp:1689:28:1689:54 | Store: Unknown literal | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | ir.cpp:1688:46:1688:46 | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const |
|
||||
| ir.cpp:1689:28:1689:54 | Store: Unknown literal | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | ir.cpp:1688:46:1688:46 | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const |
|
||||
unexpectedOperand
|
||||
duplicateOperand
|
||||
missingPhiOperand
|
||||
@@ -11,10 +7,6 @@ duplicateChiOperand
|
||||
sideEffectWithoutPrimary
|
||||
instructionWithoutSuccessor
|
||||
| ../../../include/memory.h:68:25:68:33 | CopyValue: (reference to) | Instruction 'CopyValue: (reference to)' has no successors in function '$@'. | ../../../include/memory.h:67:5:67:5 | void std::unique_ptr<int, std::default_delete<int>>::~unique_ptr() | void std::unique_ptr<int, std::default_delete<int>>::~unique_ptr() |
|
||||
| ir.cpp:1688:24:1690:5 | FieldAddress: {...} | Instruction 'FieldAddress: {...}' has no successors in function '$@'. | ir.cpp:1683:6:1683:20 | void captured_lambda(int, int&, int&&) | void captured_lambda(int, int&, int&&) |
|
||||
| ir.cpp:1688:24:1690:5 | FieldAddress: {...} | Instruction 'FieldAddress: {...}' has no successors in function '$@'. | ir.cpp:1683:6:1683:20 | void captured_lambda(int, int&, int&&) | void captured_lambda(int, int&, int&&) |
|
||||
| ir.cpp:1689:28:1689:54 | FieldAddress: {...} | Instruction 'FieldAddress: {...}' has no successors in function '$@'. | ir.cpp:1688:46:1688:46 | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const |
|
||||
| ir.cpp:1689:28:1689:54 | FieldAddress: {...} | Instruction 'FieldAddress: {...}' has no successors in function '$@'. | ir.cpp:1688:46:1688:46 | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const |
|
||||
ambiguousSuccessors
|
||||
unexplainedLoop
|
||||
unnecessaryPhiInstruction
|
||||
@@ -26,25 +18,8 @@ lostReachability
|
||||
backEdgeCountMismatch
|
||||
useNotDominatedByDefinition
|
||||
| ir.cpp:1486:8:1486:8 | Unary | Operand 'Unary' is not dominated by its definition in function '$@'. | ir.cpp:1486:8:1486:8 | void StructuredBindingDataMemberStruct::StructuredBindingDataMemberStruct() | void StructuredBindingDataMemberStruct::StructuredBindingDataMemberStruct() |
|
||||
| ir.cpp:1683:34:1683:34 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:1683:6:1683:20 | void captured_lambda(int, int&, int&&) | void captured_lambda(int, int&, int&&) |
|
||||
| ir.cpp:1683:43:1683:43 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:1683:6:1683:20 | void captured_lambda(int, int&, int&&) | void captured_lambda(int, int&, int&&) |
|
||||
| ir.cpp:1688:10:1688:21 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:1683:6:1683:20 | void captured_lambda(int, int&, int&&) | void captured_lambda(int, int&, int&&) |
|
||||
| ir.cpp:1688:24:1690:5 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:1683:6:1683:20 | void captured_lambda(int, int&, int&&) | void captured_lambda(int, int&, int&&) |
|
||||
| ir.cpp:1688:24:1690:5 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:1683:6:1683:20 | void captured_lambda(int, int&, int&&) | void captured_lambda(int, int&, int&&) |
|
||||
| ir.cpp:1688:24:1690:5 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:1683:6:1683:20 | void captured_lambda(int, int&, int&&) | void captured_lambda(int, int&, int&&) |
|
||||
| ir.cpp:1688:24:1690:5 | Unary | Operand 'Unary' is not dominated by its definition in function '$@'. | ir.cpp:1683:6:1683:20 | void captured_lambda(int, int&, int&&) | void captured_lambda(int, int&, int&&) |
|
||||
| ir.cpp:1688:24:1690:5 | Unary | Operand 'Unary' is not dominated by its definition in function '$@'. | ir.cpp:1683:6:1683:20 | void captured_lambda(int, int&, int&&) | void captured_lambda(int, int&, int&&) |
|
||||
| ir.cpp:1688:24:1690:5 | Unary | Operand 'Unary' is not dominated by its definition in function '$@'. | ir.cpp:1683:6:1683:20 | void captured_lambda(int, int&, int&&) | void captured_lambda(int, int&, int&&) |
|
||||
| ir.cpp:1688:24:1690:5 | Unary | Operand 'Unary' is not dominated by its definition in function '$@'. | ir.cpp:1683:6:1683:20 | void captured_lambda(int, int&, int&&) | void captured_lambda(int, int&, int&&) |
|
||||
| ir.cpp:1688:46:1688:46 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:1688:46:1688:46 | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const |
|
||||
| ir.cpp:1689:14:1689:25 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:1688:46:1688:46 | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const |
|
||||
| ir.cpp:1689:28:1689:54 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:1688:46:1688:46 | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const |
|
||||
| ir.cpp:1689:28:1689:54 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:1688:46:1688:46 | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const |
|
||||
| ir.cpp:1689:28:1689:54 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:1688:46:1688:46 | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const |
|
||||
| ir.cpp:1689:28:1689:54 | Unary | Operand 'Unary' is not dominated by its definition in function '$@'. | ir.cpp:1688:46:1688:46 | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const |
|
||||
| ir.cpp:1689:28:1689:54 | Unary | Operand 'Unary' is not dominated by its definition in function '$@'. | ir.cpp:1688:46:1688:46 | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const |
|
||||
| ir.cpp:1689:28:1689:54 | Unary | Operand 'Unary' is not dominated by its definition in function '$@'. | ir.cpp:1688:46:1688:46 | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const |
|
||||
| ir.cpp:1689:28:1689:54 | Unary | Operand 'Unary' is not dominated by its definition in function '$@'. | ir.cpp:1688:46:1688:46 | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const |
|
||||
| ir.cpp:1751:51:1751:51 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:1750:5:1750:34 | int implicit_copy_constructor_test(CopyConstructorTestNonVirtualClass const&, CopyConstructorTestVirtualClass const&) | int implicit_copy_constructor_test(CopyConstructorTestNonVirtualClass const&, CopyConstructorTestVirtualClass const&) |
|
||||
| ir.cpp:1752:48:1752:48 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:1750:5:1750:34 | int implicit_copy_constructor_test(CopyConstructorTestNonVirtualClass const&, CopyConstructorTestVirtualClass const&) | int implicit_copy_constructor_test(CopyConstructorTestNonVirtualClass const&, CopyConstructorTestVirtualClass const&) |
|
||||
switchInstructionWithoutDefaultEdge
|
||||
notMarkedAsConflated
|
||||
wronglyMarkedAsConflated
|
||||
|
||||
@@ -49,6 +49,40 @@ bad_asts.cpp:
|
||||
# 14| v14_5(void) = AliasedUse : ~m?
|
||||
# 14| v14_6(void) = ExitFunction :
|
||||
|
||||
# 19| void Bad::Point::Point(Bad::Point const&)
|
||||
# 19| Block 0
|
||||
# 19| v19_1(void) = EnterFunction :
|
||||
# 19| mu19_2(unknown) = AliasedDefinition :
|
||||
# 19| mu19_3(unknown) = InitializeNonLocal :
|
||||
# 19| r19_4(glval<unknown>) = VariableAddress[#this] :
|
||||
# 19| mu19_5(glval<Point>) = InitializeParameter[#this] : &:r19_4
|
||||
# 19| r19_6(glval<Point>) = Load[#this] : &:r19_4, ~m?
|
||||
# 19| mu19_7(Point) = InitializeIndirection[#this] : &:r19_6
|
||||
#-----| r0_1(glval<Point &>) = VariableAddress[(unnamed parameter 0)] :
|
||||
#-----| mu0_2(Point &) = InitializeParameter[(unnamed parameter 0)] : &:r0_1
|
||||
#-----| r0_3(Point &) = Load[(unnamed parameter 0)] : &:r0_1, ~m?
|
||||
#-----| mu0_4(unknown) = InitializeIndirection[(unnamed parameter 0)] : &:r0_3
|
||||
# 19| r19_8(glval<int>) = FieldAddress[x] : mu19_5
|
||||
# 19| r19_9(glval<Point &>) = VariableAddress[(unnamed parameter 0)] :
|
||||
# 19| r19_10(Point &) = Load[(unnamed parameter 0)] : &:r19_9, ~m?
|
||||
# 19| r19_11(glval<Point>) = CopyValue : r19_10
|
||||
# 19| r19_12(glval<int>) = FieldAddress[x] : r19_11
|
||||
# 19| r19_13(int) = Load[?] : &:r19_12, ~m?
|
||||
# 19| mu19_14(int) = Store[?] : &:r19_8, r19_13
|
||||
# 19| r19_15(glval<int>) = FieldAddress[y] : mu19_5
|
||||
# 19| r19_16(glval<Point &>) = VariableAddress[(unnamed parameter 0)] :
|
||||
# 19| r19_17(Point &) = Load[(unnamed parameter 0)] : &:r19_16, ~m?
|
||||
# 19| r19_18(glval<Point>) = CopyValue : r19_17
|
||||
# 19| r19_19(glval<int>) = FieldAddress[y] : r19_18
|
||||
# 19| r19_20(int) = Load[?] : &:r19_19, ~m?
|
||||
# 19| mu19_21(int) = Store[?] : &:r19_15, r19_20
|
||||
# 19| v19_22(void) = NoOp :
|
||||
# 19| v19_23(void) = ReturnIndirection[#this] : &:r19_6, ~m?
|
||||
#-----| v0_5(void) = ReturnIndirection[(unnamed parameter 0)] : &:r0_3, ~m?
|
||||
# 19| v19_24(void) = ReturnVoid :
|
||||
# 19| v19_25(void) = AliasedUse : ~m?
|
||||
# 19| v19_26(void) = ExitFunction :
|
||||
|
||||
# 22| void Bad::Point::Point()
|
||||
# 22| Block 0
|
||||
# 22| v22_1(void) = EnterFunction :
|
||||
@@ -8029,6 +8063,82 @@ ir.cpp:
|
||||
# 1486| v1486_16(void) = AliasedUse : ~m?
|
||||
# 1486| v1486_17(void) = ExitFunction :
|
||||
|
||||
# 1486| void StructuredBindingDataMemberStruct::StructuredBindingDataMemberStruct(StructuredBindingDataMemberStruct const&)
|
||||
# 1486| Block 0
|
||||
# 1486| v1486_1(void) = EnterFunction :
|
||||
# 1486| mu1486_2(unknown) = AliasedDefinition :
|
||||
# 1486| mu1486_3(unknown) = InitializeNonLocal :
|
||||
# 1486| r1486_4(glval<unknown>) = VariableAddress[#this] :
|
||||
# 1486| mu1486_5(glval<StructuredBindingDataMemberStruct>) = InitializeParameter[#this] : &:r1486_4
|
||||
# 1486| r1486_6(glval<StructuredBindingDataMemberStruct>) = Load[#this] : &:r1486_4, ~m?
|
||||
# 1486| mu1486_7(StructuredBindingDataMemberStruct) = InitializeIndirection[#this] : &:r1486_6
|
||||
#-----| r0_1(glval<StructuredBindingDataMemberStruct &>) = VariableAddress[(unnamed parameter 0)] :
|
||||
#-----| mu0_2(StructuredBindingDataMemberStruct &) = InitializeParameter[(unnamed parameter 0)] : &:r0_1
|
||||
#-----| r0_3(StructuredBindingDataMemberStruct &) = Load[(unnamed parameter 0)] : &:r0_1, ~m?
|
||||
#-----| mu0_4(unknown) = InitializeIndirection[(unnamed parameter 0)] : &:r0_3
|
||||
# 1486| r1486_8(glval<int>) = FieldAddress[i] : mu1486_5
|
||||
# 1486| r1486_9(glval<StructuredBindingDataMemberStruct &>) = VariableAddress[(unnamed parameter 0)] :
|
||||
# 1486| r1486_10(StructuredBindingDataMemberStruct &) = Load[(unnamed parameter 0)] : &:r1486_9, ~m?
|
||||
# 1486| r1486_11(glval<StructuredBindingDataMemberStruct>) = CopyValue : r1486_10
|
||||
# 1486| r1486_12(glval<int>) = FieldAddress[i] : r1486_11
|
||||
# 1486| r1486_13(int) = Load[?] : &:r1486_12, ~m?
|
||||
# 1486| mu1486_14(int) = Store[?] : &:r1486_8, r1486_13
|
||||
# 1486| r1486_15(glval<double>) = FieldAddress[d] : mu1486_5
|
||||
# 1486| r1486_16(glval<StructuredBindingDataMemberStruct &>) = VariableAddress[(unnamed parameter 0)] :
|
||||
# 1486| r1486_17(StructuredBindingDataMemberStruct &) = Load[(unnamed parameter 0)] : &:r1486_16, ~m?
|
||||
# 1486| r1486_18(glval<StructuredBindingDataMemberStruct>) = CopyValue : r1486_17
|
||||
# 1486| r1486_19(glval<double>) = FieldAddress[d] : r1486_18
|
||||
# 1486| r1486_20(double) = Load[?] : &:r1486_19, ~m?
|
||||
# 1486| mu1486_21(double) = Store[?] : &:r1486_15, r1486_20
|
||||
# 1486| r1486_22(glval<unsigned int>) = FieldAddress[b] : mu1486_5
|
||||
# 1486| r1486_23(glval<StructuredBindingDataMemberStruct &>) = VariableAddress[(unnamed parameter 0)] :
|
||||
# 1486| r1486_24(StructuredBindingDataMemberStruct &) = Load[(unnamed parameter 0)] : &:r1486_23, ~m?
|
||||
# 1486| r1486_25(glval<StructuredBindingDataMemberStruct>) = CopyValue : r1486_24
|
||||
# 1486| r1486_26(glval<unsigned int>) = FieldAddress[b] : r1486_25
|
||||
# 1486| r1486_27(unsigned int) = Load[?] : &:r1486_26, ~m?
|
||||
# 1486| mu1486_28(unsigned int) = Store[?] : &:r1486_22, r1486_27
|
||||
# 1486| r1486_29(glval<int &>) = FieldAddress[r] : mu1486_5
|
||||
# 1486| r1486_30(glval<StructuredBindingDataMemberStruct &>) = VariableAddress[(unnamed parameter 0)] :
|
||||
# 1486| r1486_31(StructuredBindingDataMemberStruct &) = Load[(unnamed parameter 0)] : &:r1486_30, ~m?
|
||||
# 1486| r1486_32(glval<StructuredBindingDataMemberStruct>) = CopyValue : r1486_31
|
||||
# 1486| r1486_33(glval<int &>) = FieldAddress[r] : r1486_32
|
||||
# 1486| r1486_34(int &) = Load[?] : &:r1486_33, ~m?
|
||||
# 1486| mu1486_35(int &) = Store[?] : &:r1486_29, r1486_34
|
||||
# 1486| r1486_36(glval<int *>) = FieldAddress[p] : mu1486_5
|
||||
# 1486| r1486_37(glval<StructuredBindingDataMemberStruct &>) = VariableAddress[(unnamed parameter 0)] :
|
||||
# 1486| r1486_38(StructuredBindingDataMemberStruct &) = Load[(unnamed parameter 0)] : &:r1486_37, ~m?
|
||||
# 1486| r1486_39(glval<StructuredBindingDataMemberStruct>) = CopyValue : r1486_38
|
||||
# 1486| r1486_40(glval<int *>) = FieldAddress[p] : r1486_39
|
||||
# 1486| r1486_41(int *) = Load[?] : &:r1486_40, ~m?
|
||||
# 1486| mu1486_42(int *) = Store[?] : &:r1486_36, r1486_41
|
||||
# 1486| r1486_43(glval<int[2]>) = FieldAddress[xs] : mu1486_5
|
||||
# 1486| r1486_44(glval<StructuredBindingDataMemberStruct &>) = VariableAddress[(unnamed parameter 0)] :
|
||||
# 1486| r1486_45(StructuredBindingDataMemberStruct &) = Load[(unnamed parameter 0)] : &:r1486_44, ~m?
|
||||
# 1486| r1486_46(glval<StructuredBindingDataMemberStruct>) = CopyValue : r1486_45
|
||||
# 1486| r1486_47(glval<int[2]>) = FieldAddress[xs] : r1486_46
|
||||
# 1486| r1486_48(int[2]) = Load[?] : &:r1486_47, ~m?
|
||||
# 1486| mu1486_49(int[2]) = Store[?] : &:r1486_43, r1486_48
|
||||
# 1486| r1486_50(glval<int &>) = FieldAddress[r_alt] : mu1486_5
|
||||
# 1486| r1486_51(glval<StructuredBindingDataMemberStruct &>) = VariableAddress[(unnamed parameter 0)] :
|
||||
# 1486| r1486_52(StructuredBindingDataMemberStruct &) = Load[(unnamed parameter 0)] : &:r1486_51, ~m?
|
||||
# 1486| r1486_53(glval<StructuredBindingDataMemberStruct>) = CopyValue : r1486_52
|
||||
# 1486| r1486_54(glval<int &>) = FieldAddress[r_alt] : r1486_53
|
||||
# 1486| r1486_55(int &) = Load[?] : &:r1486_54, ~m?
|
||||
# 1486| mu1486_56(int &) = Store[?] : &:r1486_50, r1486_55
|
||||
# 1486| r1486_57(glval<StructuredBindingDataMemberMemberStruct>) = FieldAddress[m] : mu1486_5
|
||||
# 1486| r1486_58(glval<StructuredBindingDataMemberStruct &>) = VariableAddress[(unnamed parameter 0)] :
|
||||
# 1486| r1486_59(StructuredBindingDataMemberStruct &) = Load[(unnamed parameter 0)] : &:r1486_58, ~m?
|
||||
# 1486| r1486_60(glval<StructuredBindingDataMemberStruct>) = CopyValue : r1486_59
|
||||
# 1486| r1486_61(glval<StructuredBindingDataMemberMemberStruct>) = FieldAddress[m] : r1486_60
|
||||
# 1486| r1486_62(StructuredBindingDataMemberMemberStruct) = Load[?] : &:r1486_61, ~m?
|
||||
# 1486| mu1486_63(StructuredBindingDataMemberMemberStruct) = Store[?] : &:r1486_57, r1486_62
|
||||
# 1486| v1486_64(void) = NoOp :
|
||||
# 1486| v1486_65(void) = ReturnIndirection[#this] : &:r1486_6, ~m?
|
||||
#-----| v0_5(void) = ReturnIndirection[(unnamed parameter 0)] : &:r0_3, ~m?
|
||||
# 1486| v1486_66(void) = ReturnVoid :
|
||||
# 1486| v1486_67(void) = AliasedUse : ~m?
|
||||
# 1486| v1486_68(void) = ExitFunction :
|
||||
|
||||
# 1499| void data_member_structured_binding()
|
||||
# 1499| Block 0
|
||||
# 1499| v1499_1(void) = EnterFunction :
|
||||
@@ -8209,6 +8319,47 @@ ir.cpp:
|
||||
# 1539| v1539_11(void) = AliasedUse : ~m?
|
||||
# 1539| v1539_12(void) = ExitFunction :
|
||||
|
||||
# 1539| void StructuredBindingTupleRefGet::StructuredBindingTupleRefGet(StructuredBindingTupleRefGet const&)
|
||||
# 1539| Block 0
|
||||
# 1539| v1539_1(void) = EnterFunction :
|
||||
# 1539| mu1539_2(unknown) = AliasedDefinition :
|
||||
# 1539| mu1539_3(unknown) = InitializeNonLocal :
|
||||
# 1539| r1539_4(glval<unknown>) = VariableAddress[#this] :
|
||||
# 1539| mu1539_5(glval<StructuredBindingTupleRefGet>) = InitializeParameter[#this] : &:r1539_4
|
||||
# 1539| r1539_6(glval<StructuredBindingTupleRefGet>) = Load[#this] : &:r1539_4, ~m?
|
||||
# 1539| mu1539_7(StructuredBindingTupleRefGet) = InitializeIndirection[#this] : &:r1539_6
|
||||
#-----| r0_1(glval<StructuredBindingTupleRefGet &>) = VariableAddress[(unnamed parameter 0)] :
|
||||
#-----| mu0_2(StructuredBindingTupleRefGet &) = InitializeParameter[(unnamed parameter 0)] : &:r0_1
|
||||
#-----| r0_3(StructuredBindingTupleRefGet &) = Load[(unnamed parameter 0)] : &:r0_1, ~m?
|
||||
#-----| mu0_4(unknown) = InitializeIndirection[(unnamed parameter 0)] : &:r0_3
|
||||
# 1539| r1539_8(glval<int>) = FieldAddress[i] : mu1539_5
|
||||
# 1539| r1539_9(glval<StructuredBindingTupleRefGet &>) = VariableAddress[(unnamed parameter 0)] :
|
||||
# 1539| r1539_10(StructuredBindingTupleRefGet &) = Load[(unnamed parameter 0)] : &:r1539_9, ~m?
|
||||
# 1539| r1539_11(glval<StructuredBindingTupleRefGet>) = CopyValue : r1539_10
|
||||
# 1539| r1539_12(glval<int>) = FieldAddress[i] : r1539_11
|
||||
# 1539| r1539_13(int) = Load[?] : &:r1539_12, ~m?
|
||||
# 1539| mu1539_14(int) = Store[?] : &:r1539_8, r1539_13
|
||||
# 1539| r1539_15(glval<double>) = FieldAddress[d] : mu1539_5
|
||||
# 1539| r1539_16(glval<StructuredBindingTupleRefGet &>) = VariableAddress[(unnamed parameter 0)] :
|
||||
# 1539| r1539_17(StructuredBindingTupleRefGet &) = Load[(unnamed parameter 0)] : &:r1539_16, ~m?
|
||||
# 1539| r1539_18(glval<StructuredBindingTupleRefGet>) = CopyValue : r1539_17
|
||||
# 1539| r1539_19(glval<double>) = FieldAddress[d] : r1539_18
|
||||
# 1539| r1539_20(double) = Load[?] : &:r1539_19, ~m?
|
||||
# 1539| mu1539_21(double) = Store[?] : &:r1539_15, r1539_20
|
||||
# 1539| r1539_22(glval<int &>) = FieldAddress[r] : mu1539_5
|
||||
# 1539| r1539_23(glval<StructuredBindingTupleRefGet &>) = VariableAddress[(unnamed parameter 0)] :
|
||||
# 1539| r1539_24(StructuredBindingTupleRefGet &) = Load[(unnamed parameter 0)] : &:r1539_23, ~m?
|
||||
# 1539| r1539_25(glval<StructuredBindingTupleRefGet>) = CopyValue : r1539_24
|
||||
# 1539| r1539_26(glval<int &>) = FieldAddress[r] : r1539_25
|
||||
# 1539| r1539_27(int &) = Load[?] : &:r1539_26, ~m?
|
||||
# 1539| mu1539_28(int &) = Store[?] : &:r1539_22, r1539_27
|
||||
# 1539| v1539_29(void) = NoOp :
|
||||
# 1539| v1539_30(void) = ReturnIndirection[#this] : &:r1539_6, ~m?
|
||||
#-----| v0_5(void) = ReturnIndirection[(unnamed parameter 0)] : &:r0_3, ~m?
|
||||
# 1539| v1539_31(void) = ReturnVoid :
|
||||
# 1539| v1539_32(void) = AliasedUse : ~m?
|
||||
# 1539| v1539_33(void) = ExitFunction :
|
||||
|
||||
# 1567| std::tuple_element<int 0, StructuredBindingTupleRefGet>::type& StructuredBindingTupleRefGet::get<int 0>()
|
||||
# 1567| Block 0
|
||||
# 1567| v1567_1(void) = EnterFunction :
|
||||
@@ -8750,81 +8901,86 @@ ir.cpp:
|
||||
# 1688| r1688_2(glval<decltype([...](...){...})>) = VariableAddress[#temp1688:24] :
|
||||
# 1688| mu1688_3(decltype([...](...){...})) = Uninitialized[#temp1688:24] : &:r1688_2
|
||||
# 1688| r1688_4(glval<CapturedLambdaMyObj>) = FieldAddress[obj1] : r1688_2
|
||||
|
||||
# 1688| Block 1
|
||||
# 1688| mu1688_5(CapturedLambdaMyObj) = Store[?] : &:r1688_4
|
||||
# 1688| r1688_6(glval<CapturedLambdaMyObj>) = FieldAddress[obj2] : r1688_2
|
||||
|
||||
# 1688| Block 2
|
||||
# 1688| mu1688_7(CapturedLambdaMyObj) = Store[?] : &:r1688_6
|
||||
# 1688| r1688_8(glval<int>) = FieldAddress[x] : r1688_2
|
||||
# 1688| r1688_9(glval<int>) = VariableAddress[x] :
|
||||
# 1688| r1688_10(int) = Load[x] : &:r1688_9, ~m?
|
||||
# 1688| mu1688_11(int) = Store[?] : &:r1688_8, r1688_10
|
||||
# 1688| r1688_12(glval<int>) = FieldAddress[y] : r1688_2
|
||||
# 1688| r1688_13(glval<int &>) = VariableAddress[y] :
|
||||
# 1688| r1688_14(int &) = Load[y] : &:r1688_13, ~m?
|
||||
# 1690| r1690_1(int) = Load[?] : &:r1688_14, ~m?
|
||||
# 1690| mu1690_2(int) = Store[?] : &:r1688_12, r1690_1
|
||||
# 1688| r1688_15(glval<int>) = FieldAddress[z] : r1688_2
|
||||
# 1688| r1688_16(glval<int &&>) = VariableAddress[z] :
|
||||
# 1688| r1688_17(int &&) = Load[z] : &:r1688_16, ~m?
|
||||
# 1690| r1690_3(int) = Load[?] : &:r1688_17, ~m?
|
||||
# 1690| mu1690_4(int) = Store[?] : &:r1688_15, r1690_3
|
||||
# 1688| r1688_18(decltype([...](...){...})) = Load[#temp1688:24] : &:r1688_2, ~m?
|
||||
# 1688| mu1688_19(decltype([...](...){...})) = Store[lambda_outer] : &:r1688_1, r1688_18
|
||||
# 1691| v1691_1(void) = NoOp :
|
||||
# 1683| v1683_14(void) = ReturnIndirection[y] : &:r1683_8, ~m?
|
||||
# 1683| v1683_15(void) = ReturnIndirection[z] : &:r1683_12, ~m?
|
||||
# 1683| v1683_16(void) = ReturnVoid :
|
||||
# 1683| v1683_17(void) = AliasedUse : ~m?
|
||||
# 1683| v1683_18(void) = ExitFunction :
|
||||
# 1688| r1688_5(glval<CapturedLambdaMyObj &>) = VariableAddress[obj1] :
|
||||
# 1688| r1688_6(CapturedLambdaMyObj &) = Load[obj1] : &:r1688_5, ~m?
|
||||
#-----| r0_1(CapturedLambdaMyObj) = Load[?] : &:r1688_6, ~m?
|
||||
#-----| mu0_2(CapturedLambdaMyObj) = Store[?] : &:r1688_4, r0_1
|
||||
# 1688| r1688_7(glval<CapturedLambdaMyObj>) = FieldAddress[obj2] : r1688_2
|
||||
# 1688| r1688_8(glval<CapturedLambdaMyObj>) = VariableAddress[obj2] :
|
||||
# 1688| r1688_9(CapturedLambdaMyObj) = Load[obj2] : &:r1688_8, ~m?
|
||||
# 1688| mu1688_10(CapturedLambdaMyObj) = Store[?] : &:r1688_7, r1688_9
|
||||
# 1688| r1688_11(glval<int>) = FieldAddress[x] : r1688_2
|
||||
# 1688| r1688_12(glval<int>) = VariableAddress[x] :
|
||||
# 1688| r1688_13(int) = Load[x] : &:r1688_12, ~m?
|
||||
# 1688| mu1688_14(int) = Store[?] : &:r1688_11, r1688_13
|
||||
# 1688| r1688_15(glval<int>) = FieldAddress[y] : r1688_2
|
||||
# 1688| r1688_16(glval<int &>) = VariableAddress[y] :
|
||||
# 1688| r1688_17(int &) = Load[y] : &:r1688_16, ~m?
|
||||
# 1690| r1690_1(int) = Load[?] : &:r1688_17, ~m?
|
||||
# 1690| mu1690_2(int) = Store[?] : &:r1688_15, r1690_1
|
||||
# 1688| r1688_18(glval<int>) = FieldAddress[z] : r1688_2
|
||||
# 1688| r1688_19(glval<int &&>) = VariableAddress[z] :
|
||||
# 1688| r1688_20(int &&) = Load[z] : &:r1688_19, ~m?
|
||||
# 1690| r1690_3(int) = Load[?] : &:r1688_20, ~m?
|
||||
# 1690| mu1690_4(int) = Store[?] : &:r1688_18, r1690_3
|
||||
# 1688| r1688_21(decltype([...](...){...})) = Load[#temp1688:24] : &:r1688_2, ~m?
|
||||
# 1688| mu1688_22(decltype([...](...){...})) = Store[lambda_outer] : &:r1688_1, r1688_21
|
||||
# 1691| v1691_1(void) = NoOp :
|
||||
# 1683| v1683_14(void) = ReturnIndirection[y] : &:r1683_8, ~m?
|
||||
# 1683| v1683_15(void) = ReturnIndirection[z] : &:r1683_12, ~m?
|
||||
# 1683| v1683_16(void) = ReturnVoid :
|
||||
# 1683| v1683_17(void) = AliasedUse : ~m?
|
||||
# 1683| v1683_18(void) = ExitFunction :
|
||||
|
||||
# 1688| void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const
|
||||
# 1688| Block 0
|
||||
# 1688| v1688_1(void) = EnterFunction :
|
||||
# 1688| mu1688_2(unknown) = AliasedDefinition :
|
||||
# 1688| mu1688_3(unknown) = InitializeNonLocal :
|
||||
# 1688| r1688_4(glval<unknown>) = VariableAddress[#this] :
|
||||
# 1688| mu1688_5(glval<decltype([...](...){...})>) = InitializeParameter[#this] : &:r1688_4
|
||||
# 1688| r1688_6(glval<decltype([...](...){...})>) = Load[#this] : &:r1688_4, ~m?
|
||||
# 1688| mu1688_7(decltype([...](...){...})) = InitializeIndirection[#this] : &:r1688_6
|
||||
# 1689| r1689_1(glval<decltype([...](...){...})>) = VariableAddress[lambda_inner] :
|
||||
# 1689| r1689_2(glval<decltype([...](...){...})>) = VariableAddress[#temp1689:28] :
|
||||
# 1689| mu1689_3(decltype([...](...){...})) = Uninitialized[#temp1689:28] : &:r1689_2
|
||||
# 1689| r1689_4(glval<CapturedLambdaMyObj>) = FieldAddress[obj1] : r1689_2
|
||||
|
||||
# 1689| Block 1
|
||||
# 1689| mu1689_5(CapturedLambdaMyObj) = Store[?] : &:r1689_4
|
||||
# 1689| r1689_6(glval<CapturedLambdaMyObj>) = FieldAddress[obj2] : r1689_2
|
||||
|
||||
# 1689| Block 2
|
||||
# 1689| mu1689_7(CapturedLambdaMyObj) = Store[?] : &:r1689_6
|
||||
# 1689| r1689_8(glval<int>) = FieldAddress[x] : r1689_2
|
||||
# 1689| r1689_9(glval<unknown>) = VariableAddress[#this] :
|
||||
# 1689| r1689_10(lambda [] type at line 1688, col. 25 *) = Load[#this] : &:r1689_9, ~m?
|
||||
# 1689| r1689_11(glval<int>) = FieldAddress[x] : r1689_10
|
||||
# 1689| r1689_12(int) = Load[?] : &:r1689_11, ~m?
|
||||
# 1689| mu1689_13(int) = Store[?] : &:r1689_8, r1689_12
|
||||
# 1689| r1689_14(glval<int>) = FieldAddress[y] : r1689_2
|
||||
# 1689| r1689_15(glval<unknown>) = VariableAddress[#this] :
|
||||
# 1689| r1689_16(lambda [] type at line 1688, col. 25 *) = Load[#this] : &:r1689_15, ~m?
|
||||
# 1689| r1689_17(glval<int>) = FieldAddress[y] : r1689_16
|
||||
# 1689| r1689_18(int) = Load[?] : &:r1689_17, ~m?
|
||||
# 1689| mu1689_19(int) = Store[?] : &:r1689_14, r1689_18
|
||||
# 1689| r1689_20(glval<int>) = FieldAddress[z] : r1689_2
|
||||
# 1689| r1689_21(glval<unknown>) = VariableAddress[#this] :
|
||||
# 1689| r1689_22(lambda [] type at line 1688, col. 25 *) = Load[#this] : &:r1689_21, ~m?
|
||||
# 1689| r1689_23(glval<int>) = FieldAddress[z] : r1689_22
|
||||
# 1689| r1689_24(int) = Load[?] : &:r1689_23, ~m?
|
||||
# 1689| mu1689_25(int) = Store[?] : &:r1689_20, r1689_24
|
||||
# 1689| r1689_26(decltype([...](...){...})) = Load[#temp1689:28] : &:r1689_2, ~m?
|
||||
# 1689| mu1689_27(decltype([...](...){...})) = Store[lambda_inner] : &:r1689_1, r1689_26
|
||||
# 1690| v1690_1(void) = NoOp :
|
||||
# 1688| v1688_8(void) = ReturnIndirection[#this] : &:r1688_6, ~m?
|
||||
# 1688| v1688_9(void) = ReturnVoid :
|
||||
# 1688| v1688_10(void) = AliasedUse : ~m?
|
||||
# 1688| v1688_11(void) = ExitFunction :
|
||||
# 1688| v1688_1(void) = EnterFunction :
|
||||
# 1688| mu1688_2(unknown) = AliasedDefinition :
|
||||
# 1688| mu1688_3(unknown) = InitializeNonLocal :
|
||||
# 1688| r1688_4(glval<unknown>) = VariableAddress[#this] :
|
||||
# 1688| mu1688_5(glval<decltype([...](...){...})>) = InitializeParameter[#this] : &:r1688_4
|
||||
# 1688| r1688_6(glval<decltype([...](...){...})>) = Load[#this] : &:r1688_4, ~m?
|
||||
# 1688| mu1688_7(decltype([...](...){...})) = InitializeIndirection[#this] : &:r1688_6
|
||||
# 1689| r1689_1(glval<decltype([...](...){...})>) = VariableAddress[lambda_inner] :
|
||||
# 1689| r1689_2(glval<decltype([...](...){...})>) = VariableAddress[#temp1689:28] :
|
||||
# 1689| mu1689_3(decltype([...](...){...})) = Uninitialized[#temp1689:28] : &:r1689_2
|
||||
# 1689| r1689_4(glval<CapturedLambdaMyObj>) = FieldAddress[obj1] : r1689_2
|
||||
# 1689| r1689_5(glval<unknown>) = VariableAddress[#this] :
|
||||
# 1689| r1689_6(lambda [] type at line 1689, col. 29 *) = Load[#this] : &:r1689_5, ~m?
|
||||
# 1689| r1689_7(glval<CapturedLambdaMyObj>) = FieldAddress[obj1] : r1689_6
|
||||
# 1689| r1689_8(CapturedLambdaMyObj) = Load[?] : &:r1689_7, ~m?
|
||||
# 1689| mu1689_9(CapturedLambdaMyObj) = Store[?] : &:r1689_4, r1689_8
|
||||
# 1689| r1689_10(glval<CapturedLambdaMyObj>) = FieldAddress[obj2] : r1689_2
|
||||
# 1689| r1689_11(glval<unknown>) = VariableAddress[#this] :
|
||||
# 1689| r1689_12(lambda [] type at line 1689, col. 29 *) = Load[#this] : &:r1689_11, ~m?
|
||||
# 1689| r1689_13(glval<CapturedLambdaMyObj>) = FieldAddress[obj2] : r1689_12
|
||||
# 1689| r1689_14(CapturedLambdaMyObj) = Load[?] : &:r1689_13, ~m?
|
||||
# 1689| mu1689_15(CapturedLambdaMyObj) = Store[?] : &:r1689_10, r1689_14
|
||||
# 1689| r1689_16(glval<int>) = FieldAddress[x] : r1689_2
|
||||
# 1689| r1689_17(glval<unknown>) = VariableAddress[#this] :
|
||||
# 1689| r1689_18(lambda [] type at line 1688, col. 25 *) = Load[#this] : &:r1689_17, ~m?
|
||||
# 1689| r1689_19(glval<int>) = FieldAddress[x] : r1689_18
|
||||
# 1689| r1689_20(int) = Load[?] : &:r1689_19, ~m?
|
||||
# 1689| mu1689_21(int) = Store[?] : &:r1689_16, r1689_20
|
||||
# 1689| r1689_22(glval<int>) = FieldAddress[y] : r1689_2
|
||||
# 1689| r1689_23(glval<unknown>) = VariableAddress[#this] :
|
||||
# 1689| r1689_24(lambda [] type at line 1688, col. 25 *) = Load[#this] : &:r1689_23, ~m?
|
||||
# 1689| r1689_25(glval<int>) = FieldAddress[y] : r1689_24
|
||||
# 1689| r1689_26(int) = Load[?] : &:r1689_25, ~m?
|
||||
# 1689| mu1689_27(int) = Store[?] : &:r1689_22, r1689_26
|
||||
# 1689| r1689_28(glval<int>) = FieldAddress[z] : r1689_2
|
||||
# 1689| r1689_29(glval<unknown>) = VariableAddress[#this] :
|
||||
# 1689| r1689_30(lambda [] type at line 1688, col. 25 *) = Load[#this] : &:r1689_29, ~m?
|
||||
# 1689| r1689_31(glval<int>) = FieldAddress[z] : r1689_30
|
||||
# 1689| r1689_32(int) = Load[?] : &:r1689_31, ~m?
|
||||
# 1689| mu1689_33(int) = Store[?] : &:r1689_28, r1689_32
|
||||
# 1689| r1689_34(decltype([...](...){...})) = Load[#temp1689:28] : &:r1689_2, ~m?
|
||||
# 1689| mu1689_35(decltype([...](...){...})) = Store[lambda_inner] : &:r1689_1, r1689_34
|
||||
# 1690| v1690_1(void) = NoOp :
|
||||
# 1688| v1688_8(void) = ReturnIndirection[#this] : &:r1688_6, ~m?
|
||||
# 1688| v1688_9(void) = ReturnVoid :
|
||||
# 1688| v1688_10(void) = AliasedUse : ~m?
|
||||
# 1688| v1688_11(void) = ExitFunction :
|
||||
|
||||
# 1689| void (void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const)::(lambda [] type at line 1689, col. 29)::operator()() const
|
||||
# 1689| Block 0
|
||||
@@ -8842,6 +8998,426 @@ ir.cpp:
|
||||
# 1689| v1689_12(void) = AliasedUse : ~m?
|
||||
# 1689| v1689_13(void) = ExitFunction :
|
||||
|
||||
# 1693| int goto_on_same_line()
|
||||
# 1693| Block 0
|
||||
# 1693| v1693_1(void) = EnterFunction :
|
||||
# 1693| mu1693_2(unknown) = AliasedDefinition :
|
||||
# 1693| mu1693_3(unknown) = InitializeNonLocal :
|
||||
# 1694| r1694_1(glval<int>) = VariableAddress[x] :
|
||||
# 1694| r1694_2(int) = Constant[42] :
|
||||
# 1694| mu1694_3(int) = Store[x] : &:r1694_1, r1694_2
|
||||
# 1695| v1695_1(void) = NoOp :
|
||||
# 1695| v1695_2(void) = NoOp :
|
||||
# 1696| r1696_1(glval<int>) = VariableAddress[#return] :
|
||||
# 1696| r1696_2(glval<int>) = VariableAddress[x] :
|
||||
# 1696| r1696_3(int) = Load[x] : &:r1696_2, ~m?
|
||||
# 1696| mu1696_4(int) = Store[#return] : &:r1696_1, r1696_3
|
||||
# 1693| r1693_4(glval<int>) = VariableAddress[#return] :
|
||||
# 1693| v1693_5(void) = ReturnValue : &:r1693_4, ~m?
|
||||
# 1693| v1693_6(void) = AliasedUse : ~m?
|
||||
# 1693| v1693_7(void) = ExitFunction :
|
||||
|
||||
# 1701| void TrivialLambdaClass::m() const
|
||||
# 1701| Block 0
|
||||
# 1701| v1701_1(void) = EnterFunction :
|
||||
# 1701| mu1701_2(unknown) = AliasedDefinition :
|
||||
# 1701| mu1701_3(unknown) = InitializeNonLocal :
|
||||
# 1701| r1701_4(glval<unknown>) = VariableAddress[#this] :
|
||||
# 1701| mu1701_5(glval<TrivialLambdaClass>) = InitializeParameter[#this] : &:r1701_4
|
||||
# 1701| r1701_6(glval<TrivialLambdaClass>) = Load[#this] : &:r1701_4, ~m?
|
||||
# 1701| mu1701_7(TrivialLambdaClass) = InitializeIndirection[#this] : &:r1701_6
|
||||
# 1702| r1702_1(glval<decltype([...](...){...})>) = VariableAddress[l_m_outer] :
|
||||
# 1702| r1702_2(glval<decltype([...](...){...})>) = VariableAddress[#temp1702:25] :
|
||||
# 1702| mu1702_3(decltype([...](...){...})) = Uninitialized[#temp1702:25] : &:r1702_2
|
||||
# 1702| r1702_4(glval<TrivialLambdaClass>) = FieldAddress[(captured this)] : r1702_2
|
||||
# 1702| r1702_5(glval<unknown>) = VariableAddress[#this] :
|
||||
# 1702| r1702_6(TrivialLambdaClass *) = Load[#this] : &:r1702_5, ~m?
|
||||
# 1702| r1702_7(TrivialLambdaClass) = Load[?] : &:r1702_6, ~m?
|
||||
# 1702| mu1702_8(TrivialLambdaClass) = Store[?] : &:r1702_4, r1702_7
|
||||
# 1702| r1702_9(decltype([...](...){...})) = Load[#temp1702:25] : &:r1702_2, ~m?
|
||||
# 1702| mu1702_10(decltype([...](...){...})) = Store[l_m_outer] : &:r1702_1, r1702_9
|
||||
# 1709| v1709_1(void) = NoOp :
|
||||
# 1701| v1701_8(void) = ReturnIndirection[#this] : &:r1701_6, ~m?
|
||||
# 1701| v1701_9(void) = ReturnVoid :
|
||||
# 1701| v1701_10(void) = AliasedUse : ~m?
|
||||
# 1701| v1701_11(void) = ExitFunction :
|
||||
|
||||
# 1702| void (void TrivialLambdaClass::m() const)::(lambda [] type at line 1702, col. 26)::operator()() const
|
||||
# 1702| Block 0
|
||||
# 1702| v1702_1(void) = EnterFunction :
|
||||
# 1702| mu1702_2(unknown) = AliasedDefinition :
|
||||
# 1702| mu1702_3(unknown) = InitializeNonLocal :
|
||||
# 1702| r1702_4(glval<unknown>) = VariableAddress[#this] :
|
||||
# 1702| mu1702_5(glval<decltype([...](...){...})>) = InitializeParameter[#this] : &:r1702_4
|
||||
# 1702| r1702_6(glval<decltype([...](...){...})>) = Load[#this] : &:r1702_4, ~m?
|
||||
# 1702| mu1702_7(decltype([...](...){...})) = InitializeIndirection[#this] : &:r1702_6
|
||||
# 1703| r1703_1(glval<unknown>) = VariableAddress[#this] :
|
||||
# 1703| r1703_2(lambda [] type at line 1702, col. 26 *) = Load[#this] : &:r1703_1, ~m?
|
||||
# 1703| r1703_3(glval<TrivialLambdaClass>) = FieldAddress[(captured this)] : r1703_2
|
||||
# 1703| r1703_4(TrivialLambdaClass *) = CopyValue : r1703_3
|
||||
# 1703| r1703_5(glval<unknown>) = FunctionAddress[m] :
|
||||
# 1703| v1703_6(void) = Call[m] : func:r1703_5, this:r1703_4
|
||||
# 1703| mu1703_7(unknown) = ^CallSideEffect : ~m?
|
||||
# 1703| v1703_8(void) = ^IndirectReadSideEffect[-1] : &:r1703_4, ~m?
|
||||
# 1705| r1705_1(glval<decltype([...](...){...})>) = VariableAddress[l_m_inner] :
|
||||
# 1705| r1705_2(glval<decltype([...](...){...})>) = VariableAddress[#temp1705:29] :
|
||||
# 1705| mu1705_3(decltype([...](...){...})) = Uninitialized[#temp1705:29] : &:r1705_2
|
||||
# 1705| r1705_4(glval<TrivialLambdaClass>) = FieldAddress[(captured this)] : r1705_2
|
||||
# 1705| r1705_5(glval<unknown>) = VariableAddress[#this] :
|
||||
# 1705| r1705_6(lambda [] type at line 1705, col. 30 *) = Load[#this] : &:r1705_5, ~m?
|
||||
# 1705| r1705_7(glval<TrivialLambdaClass>) = FieldAddress[(captured this)] : r1705_6
|
||||
# 1705| r1705_8(TrivialLambdaClass) = Load[?] : &:r1705_7, ~m?
|
||||
# 1705| mu1705_9(TrivialLambdaClass) = Store[?] : &:r1705_4, r1705_8
|
||||
# 1705| r1705_10(decltype([...](...){...})) = Load[#temp1705:29] : &:r1705_2, ~m?
|
||||
# 1705| mu1705_11(decltype([...](...){...})) = Store[l_m_inner] : &:r1705_1, r1705_10
|
||||
# 1708| v1708_1(void) = NoOp :
|
||||
# 1702| v1702_8(void) = ReturnIndirection[#this] : &:r1702_6, ~m?
|
||||
# 1702| v1702_9(void) = ReturnVoid :
|
||||
# 1702| v1702_10(void) = AliasedUse : ~m?
|
||||
# 1702| v1702_11(void) = ExitFunction :
|
||||
|
||||
# 1705| void (void (void TrivialLambdaClass::m() const)::(lambda [] type at line 1702, col. 26)::operator()() const)::(lambda [] type at line 1705, col. 30)::operator()() const
|
||||
# 1705| Block 0
|
||||
# 1705| v1705_1(void) = EnterFunction :
|
||||
# 1705| mu1705_2(unknown) = AliasedDefinition :
|
||||
# 1705| mu1705_3(unknown) = InitializeNonLocal :
|
||||
# 1705| r1705_4(glval<unknown>) = VariableAddress[#this] :
|
||||
# 1705| mu1705_5(glval<decltype([...](...){...})>) = InitializeParameter[#this] : &:r1705_4
|
||||
# 1705| r1705_6(glval<decltype([...](...){...})>) = Load[#this] : &:r1705_4, ~m?
|
||||
# 1705| mu1705_7(decltype([...](...){...})) = InitializeIndirection[#this] : &:r1705_6
|
||||
# 1706| r1706_1(glval<unknown>) = VariableAddress[#this] :
|
||||
# 1706| r1706_2(lambda [] type at line 1705, col. 30 *) = Load[#this] : &:r1706_1, ~m?
|
||||
# 1706| r1706_3(glval<TrivialLambdaClass>) = FieldAddress[(captured this)] : r1706_2
|
||||
# 1706| r1706_4(TrivialLambdaClass *) = CopyValue : r1706_3
|
||||
# 1706| r1706_5(glval<unknown>) = FunctionAddress[m] :
|
||||
# 1706| v1706_6(void) = Call[m] : func:r1706_5, this:r1706_4
|
||||
# 1706| mu1706_7(unknown) = ^CallSideEffect : ~m?
|
||||
# 1706| v1706_8(void) = ^IndirectReadSideEffect[-1] : &:r1706_4, ~m?
|
||||
# 1707| v1707_1(void) = NoOp :
|
||||
# 1705| v1705_8(void) = ReturnIndirection[#this] : &:r1705_6, ~m?
|
||||
# 1705| v1705_9(void) = ReturnVoid :
|
||||
# 1705| v1705_10(void) = AliasedUse : ~m?
|
||||
# 1705| v1705_11(void) = ExitFunction :
|
||||
|
||||
# 1712| void captured_lambda2(TrivialLambdaClass, TrivialLambdaClass&, TrivialLambdaClass&&)
|
||||
# 1712| Block 0
|
||||
# 1712| v1712_1(void) = EnterFunction :
|
||||
# 1712| mu1712_2(unknown) = AliasedDefinition :
|
||||
# 1712| mu1712_3(unknown) = InitializeNonLocal :
|
||||
# 1712| r1712_4(glval<TrivialLambdaClass>) = VariableAddress[p1] :
|
||||
# 1712| mu1712_5(TrivialLambdaClass) = InitializeParameter[p1] : &:r1712_4
|
||||
# 1712| r1712_6(glval<TrivialLambdaClass &>) = VariableAddress[p2] :
|
||||
# 1712| mu1712_7(TrivialLambdaClass &) = InitializeParameter[p2] : &:r1712_6
|
||||
# 1712| r1712_8(TrivialLambdaClass &) = Load[p2] : &:r1712_6, ~m?
|
||||
# 1712| mu1712_9(unknown) = InitializeIndirection[p2] : &:r1712_8
|
||||
# 1712| r1712_10(glval<TrivialLambdaClass &&>) = VariableAddress[p3] :
|
||||
# 1712| mu1712_11(TrivialLambdaClass &&) = InitializeParameter[p3] : &:r1712_10
|
||||
# 1712| r1712_12(TrivialLambdaClass &&) = Load[p3] : &:r1712_10, ~m?
|
||||
# 1712| mu1712_13(unknown) = InitializeIndirection[p3] : &:r1712_12
|
||||
# 1713| r1713_1(glval<TrivialLambdaClass>) = VariableAddress[l1] :
|
||||
# 1713| mu1713_2(TrivialLambdaClass) = Uninitialized[l1] : &:r1713_1
|
||||
# 1714| r1714_1(glval<TrivialLambdaClass &>) = VariableAddress[l2] :
|
||||
# 1714| r1714_2(glval<TrivialLambdaClass>) = VariableAddress[#temp1714:36] :
|
||||
# 1714| r1714_3(glval<TrivialLambdaClass>) = VariableAddress[#temp1714:36] :
|
||||
# 1714| r1714_4(TrivialLambdaClass) = Constant[0] :
|
||||
# 1714| mu1714_5(TrivialLambdaClass) = Store[#temp1714:36] : &:r1714_3, r1714_4
|
||||
# 1714| r1714_6(TrivialLambdaClass) = Load[#temp1714:36] : &:r1714_3, ~m?
|
||||
# 1714| mu1714_7(TrivialLambdaClass) = Store[#temp1714:36] : &:r1714_2, r1714_6
|
||||
# 1714| r1714_8(glval<TrivialLambdaClass>) = Convert : r1714_2
|
||||
# 1714| r1714_9(TrivialLambdaClass &) = CopyValue : r1714_8
|
||||
# 1714| mu1714_10(TrivialLambdaClass &) = Store[l2] : &:r1714_1, r1714_9
|
||||
# 1716| r1716_1(glval<decltype([...](...){...})>) = VariableAddress[l_outer1] :
|
||||
# 1716| r1716_2(glval<decltype([...](...){...})>) = VariableAddress[#temp1716:20] :
|
||||
# 1716| mu1716_3(decltype([...](...){...})) = Uninitialized[#temp1716:20] : &:r1716_2
|
||||
# 1716| r1716_4(glval<TrivialLambdaClass>) = FieldAddress[p1] : r1716_2
|
||||
# 1716| r1716_5(glval<TrivialLambdaClass>) = VariableAddress[p1] :
|
||||
# 1716| r1716_6(TrivialLambdaClass) = Load[p1] : &:r1716_5, ~m?
|
||||
# 1716| mu1716_7(TrivialLambdaClass) = Store[?] : &:r1716_4, r1716_6
|
||||
# 1716| r1716_8(glval<TrivialLambdaClass>) = FieldAddress[p2] : r1716_2
|
||||
# 1716| r1716_9(glval<TrivialLambdaClass &>) = VariableAddress[p2] :
|
||||
# 1716| r1716_10(TrivialLambdaClass &) = Load[p2] : &:r1716_9, ~m?
|
||||
#-----| r0_1(TrivialLambdaClass) = Load[?] : &:r1716_10, ~m?
|
||||
#-----| mu0_2(TrivialLambdaClass) = Store[?] : &:r1716_8, r0_1
|
||||
# 1716| r1716_11(glval<TrivialLambdaClass>) = FieldAddress[p3] : r1716_2
|
||||
# 1716| r1716_12(glval<TrivialLambdaClass &&>) = VariableAddress[p3] :
|
||||
# 1716| r1716_13(TrivialLambdaClass &&) = Load[p3] : &:r1716_12, ~m?
|
||||
#-----| r0_3(TrivialLambdaClass) = Load[?] : &:r1716_13, ~m?
|
||||
#-----| mu0_4(TrivialLambdaClass) = Store[?] : &:r1716_11, r0_3
|
||||
# 1716| r1716_14(glval<TrivialLambdaClass>) = FieldAddress[l1] : r1716_2
|
||||
# 1716| r1716_15(glval<TrivialLambdaClass>) = VariableAddress[l1] :
|
||||
# 1716| r1716_16(TrivialLambdaClass) = Load[l1] : &:r1716_15, ~m?
|
||||
# 1716| mu1716_17(TrivialLambdaClass) = Store[?] : &:r1716_14, r1716_16
|
||||
# 1716| r1716_18(glval<TrivialLambdaClass>) = FieldAddress[l2] : r1716_2
|
||||
# 1716| r1716_19(glval<TrivialLambdaClass &>) = VariableAddress[l2] :
|
||||
# 1716| r1716_20(TrivialLambdaClass &) = Load[l2] : &:r1716_19, ~m?
|
||||
#-----| r0_5(TrivialLambdaClass) = Load[?] : &:r1716_20, ~m?
|
||||
#-----| mu0_6(TrivialLambdaClass) = Store[?] : &:r1716_18, r0_5
|
||||
# 1716| r1716_21(decltype([...](...){...})) = Load[#temp1716:20] : &:r1716_2, ~m?
|
||||
# 1716| mu1716_22(decltype([...](...){...})) = Store[l_outer1] : &:r1716_1, r1716_21
|
||||
# 1719| v1719_1(void) = NoOp :
|
||||
# 1712| v1712_14(void) = ReturnIndirection[p2] : &:r1712_8, ~m?
|
||||
# 1712| v1712_15(void) = ReturnIndirection[p3] : &:r1712_12, ~m?
|
||||
# 1712| v1712_16(void) = ReturnVoid :
|
||||
# 1712| v1712_17(void) = AliasedUse : ~m?
|
||||
# 1712| v1712_18(void) = ExitFunction :
|
||||
|
||||
# 1716| void (void captured_lambda2(TrivialLambdaClass, TrivialLambdaClass&, TrivialLambdaClass&&))::(lambda [] type at line 1716, col. 21)::operator()() const
|
||||
# 1716| Block 0
|
||||
# 1716| v1716_1(void) = EnterFunction :
|
||||
# 1716| mu1716_2(unknown) = AliasedDefinition :
|
||||
# 1716| mu1716_3(unknown) = InitializeNonLocal :
|
||||
# 1716| r1716_4(glval<unknown>) = VariableAddress[#this] :
|
||||
# 1716| mu1716_5(glval<decltype([...](...){...})>) = InitializeParameter[#this] : &:r1716_4
|
||||
# 1716| r1716_6(glval<decltype([...](...){...})>) = Load[#this] : &:r1716_4, ~m?
|
||||
# 1716| mu1716_7(decltype([...](...){...})) = InitializeIndirection[#this] : &:r1716_6
|
||||
# 1717| r1717_1(glval<decltype([...](...){...})>) = VariableAddress[l_inner1] :
|
||||
# 1717| r1717_2(glval<decltype([...](...){...})>) = VariableAddress[#temp1717:24] :
|
||||
# 1717| mu1717_3(decltype([...](...){...})) = Uninitialized[#temp1717:24] : &:r1717_2
|
||||
# 1717| r1717_4(glval<TrivialLambdaClass>) = FieldAddress[p1] : r1717_2
|
||||
# 1717| r1717_5(glval<unknown>) = VariableAddress[#this] :
|
||||
# 1717| r1717_6(lambda [] type at line 1717, col. 25 *) = Load[#this] : &:r1717_5, ~m?
|
||||
# 1717| r1717_7(glval<TrivialLambdaClass>) = FieldAddress[p1] : r1717_6
|
||||
# 1717| r1717_8(TrivialLambdaClass) = Load[?] : &:r1717_7, ~m?
|
||||
# 1717| mu1717_9(TrivialLambdaClass) = Store[?] : &:r1717_4, r1717_8
|
||||
# 1717| r1717_10(decltype([...](...){...})) = Load[#temp1717:24] : &:r1717_2, ~m?
|
||||
# 1717| mu1717_11(decltype([...](...){...})) = Store[l_inner1] : &:r1717_1, r1717_10
|
||||
# 1718| v1718_1(void) = NoOp :
|
||||
# 1716| v1716_8(void) = ReturnIndirection[#this] : &:r1716_6, ~m?
|
||||
# 1716| v1716_9(void) = ReturnVoid :
|
||||
# 1716| v1716_10(void) = AliasedUse : ~m?
|
||||
# 1716| v1716_11(void) = ExitFunction :
|
||||
|
||||
# 1717| void (void (void captured_lambda2(TrivialLambdaClass, TrivialLambdaClass&, TrivialLambdaClass&&))::(lambda [] type at line 1716, col. 21)::operator()() const)::(lambda [] type at line 1717, col. 25)::operator()() const
|
||||
# 1717| Block 0
|
||||
# 1717| v1717_1(void) = EnterFunction :
|
||||
# 1717| mu1717_2(unknown) = AliasedDefinition :
|
||||
# 1717| mu1717_3(unknown) = InitializeNonLocal :
|
||||
# 1717| r1717_4(glval<unknown>) = VariableAddress[#this] :
|
||||
# 1717| mu1717_5(glval<decltype([...](...){...})>) = InitializeParameter[#this] : &:r1717_4
|
||||
# 1717| r1717_6(glval<decltype([...](...){...})>) = Load[#this] : &:r1717_4, ~m?
|
||||
# 1717| mu1717_7(decltype([...](...){...})) = InitializeIndirection[#this] : &:r1717_6
|
||||
# 1717| v1717_8(void) = NoOp :
|
||||
# 1717| v1717_9(void) = ReturnIndirection[#this] : &:r1717_6, ~m?
|
||||
# 1717| v1717_10(void) = ReturnVoid :
|
||||
# 1717| v1717_11(void) = AliasedUse : ~m?
|
||||
# 1717| v1717_12(void) = ExitFunction :
|
||||
|
||||
# 1724| void CopyConstructorWithImplicitArgumentClass::CopyConstructorWithImplicitArgumentClass()
|
||||
# 1724| Block 0
|
||||
# 1724| v1724_1(void) = EnterFunction :
|
||||
# 1724| mu1724_2(unknown) = AliasedDefinition :
|
||||
# 1724| mu1724_3(unknown) = InitializeNonLocal :
|
||||
# 1724| r1724_4(glval<unknown>) = VariableAddress[#this] :
|
||||
# 1724| mu1724_5(glval<CopyConstructorWithImplicitArgumentClass>) = InitializeParameter[#this] : &:r1724_4
|
||||
# 1724| r1724_6(glval<CopyConstructorWithImplicitArgumentClass>) = Load[#this] : &:r1724_4, ~m?
|
||||
# 1724| mu1724_7(CopyConstructorWithImplicitArgumentClass) = InitializeIndirection[#this] : &:r1724_6
|
||||
# 1724| v1724_8(void) = NoOp :
|
||||
# 1724| v1724_9(void) = ReturnIndirection[#this] : &:r1724_6, ~m?
|
||||
# 1724| v1724_10(void) = ReturnVoid :
|
||||
# 1724| v1724_11(void) = AliasedUse : ~m?
|
||||
# 1724| v1724_12(void) = ExitFunction :
|
||||
|
||||
# 1725| void CopyConstructorWithImplicitArgumentClass::CopyConstructorWithImplicitArgumentClass(CopyConstructorWithImplicitArgumentClass const&)
|
||||
# 1725| Block 0
|
||||
# 1725| v1725_1(void) = EnterFunction :
|
||||
# 1725| mu1725_2(unknown) = AliasedDefinition :
|
||||
# 1725| mu1725_3(unknown) = InitializeNonLocal :
|
||||
# 1725| r1725_4(glval<unknown>) = VariableAddress[#this] :
|
||||
# 1725| mu1725_5(glval<CopyConstructorWithImplicitArgumentClass>) = InitializeParameter[#this] : &:r1725_4
|
||||
# 1725| r1725_6(glval<CopyConstructorWithImplicitArgumentClass>) = Load[#this] : &:r1725_4, ~m?
|
||||
# 1725| mu1725_7(CopyConstructorWithImplicitArgumentClass) = InitializeIndirection[#this] : &:r1725_6
|
||||
# 1725| r1725_8(glval<CopyConstructorWithImplicitArgumentClass &>) = VariableAddress[c] :
|
||||
# 1725| mu1725_9(CopyConstructorWithImplicitArgumentClass &) = InitializeParameter[c] : &:r1725_8
|
||||
# 1725| r1725_10(CopyConstructorWithImplicitArgumentClass &) = Load[c] : &:r1725_8, ~m?
|
||||
# 1725| mu1725_11(unknown) = InitializeIndirection[c] : &:r1725_10
|
||||
# 1726| r1726_1(glval<CopyConstructorWithImplicitArgumentClass &>) = VariableAddress[c] :
|
||||
# 1726| r1726_2(CopyConstructorWithImplicitArgumentClass &) = Load[c] : &:r1726_1, ~m?
|
||||
# 1726| r1726_3(glval<CopyConstructorWithImplicitArgumentClass>) = CopyValue : r1726_2
|
||||
# 1726| r1726_4(glval<int>) = FieldAddress[x] : r1726_3
|
||||
# 1726| r1726_5(int) = Load[?] : &:r1726_4, ~m?
|
||||
# 1726| r1726_6(glval<unknown>) = VariableAddress[#this] :
|
||||
# 1726| r1726_7(CopyConstructorWithImplicitArgumentClass *) = Load[#this] : &:r1726_6, ~m?
|
||||
# 1726| r1726_8(glval<int>) = FieldAddress[x] : r1726_7
|
||||
# 1726| mu1726_9(int) = Store[?] : &:r1726_8, r1726_5
|
||||
# 1727| v1727_1(void) = NoOp :
|
||||
# 1725| v1725_12(void) = ReturnIndirection[#this] : &:r1725_6, ~m?
|
||||
# 1725| v1725_13(void) = ReturnIndirection[c] : &:r1725_10, ~m?
|
||||
# 1725| v1725_14(void) = ReturnVoid :
|
||||
# 1725| v1725_15(void) = AliasedUse : ~m?
|
||||
# 1725| v1725_16(void) = ExitFunction :
|
||||
|
||||
# 1733| void CopyConstructorWithBitwiseCopyClass::CopyConstructorWithBitwiseCopyClass()
|
||||
# 1733| Block 0
|
||||
# 1733| v1733_1(void) = EnterFunction :
|
||||
# 1733| mu1733_2(unknown) = AliasedDefinition :
|
||||
# 1733| mu1733_3(unknown) = InitializeNonLocal :
|
||||
# 1733| r1733_4(glval<unknown>) = VariableAddress[#this] :
|
||||
# 1733| mu1733_5(glval<CopyConstructorWithBitwiseCopyClass>) = InitializeParameter[#this] : &:r1733_4
|
||||
# 1733| r1733_6(glval<CopyConstructorWithBitwiseCopyClass>) = Load[#this] : &:r1733_4, ~m?
|
||||
# 1733| mu1733_7(CopyConstructorWithBitwiseCopyClass) = InitializeIndirection[#this] : &:r1733_6
|
||||
# 1733| v1733_8(void) = NoOp :
|
||||
# 1733| v1733_9(void) = ReturnIndirection[#this] : &:r1733_6, ~m?
|
||||
# 1733| v1733_10(void) = ReturnVoid :
|
||||
# 1733| v1733_11(void) = AliasedUse : ~m?
|
||||
# 1733| v1733_12(void) = ExitFunction :
|
||||
|
||||
# 1736| void CopyConstructorTestNonVirtualClass::CopyConstructorTestNonVirtualClass(CopyConstructorTestNonVirtualClass const&)
|
||||
# 1736| Block 0
|
||||
# 1736| v1736_1(void) = EnterFunction :
|
||||
# 1736| mu1736_2(unknown) = AliasedDefinition :
|
||||
# 1736| mu1736_3(unknown) = InitializeNonLocal :
|
||||
# 1736| r1736_4(glval<unknown>) = VariableAddress[#this] :
|
||||
# 1736| mu1736_5(glval<CopyConstructorTestNonVirtualClass>) = InitializeParameter[#this] : &:r1736_4
|
||||
# 1736| r1736_6(glval<CopyConstructorTestNonVirtualClass>) = Load[#this] : &:r1736_4, ~m?
|
||||
# 1736| mu1736_7(CopyConstructorTestNonVirtualClass) = InitializeIndirection[#this] : &:r1736_6
|
||||
#-----| r0_1(glval<CopyConstructorTestNonVirtualClass &>) = VariableAddress[(unnamed parameter 0)] :
|
||||
#-----| mu0_2(CopyConstructorTestNonVirtualClass &) = InitializeParameter[(unnamed parameter 0)] : &:r0_1
|
||||
#-----| r0_3(CopyConstructorTestNonVirtualClass &) = Load[(unnamed parameter 0)] : &:r0_1, ~m?
|
||||
#-----| mu0_4(unknown) = InitializeIndirection[(unnamed parameter 0)] : &:r0_3
|
||||
# 1736| r1736_8(glval<CopyConstructorWithImplicitArgumentClass>) = ConvertToNonVirtualBase[CopyConstructorTestNonVirtualClass : CopyConstructorWithImplicitArgumentClass] : mu1736_5
|
||||
# 1736| r1736_9(glval<unknown>) = FunctionAddress[CopyConstructorWithImplicitArgumentClass] :
|
||||
# 1736| r1736_10(glval<CopyConstructorTestNonVirtualClass &>) = VariableAddress[(unnamed parameter 0)] :
|
||||
# 1736| r1736_11(CopyConstructorTestNonVirtualClass &) = Load[(unnamed parameter 0)] : &:r1736_10, ~m?
|
||||
# 1736| r1736_12(glval<CopyConstructorTestNonVirtualClass>) = CopyValue : r1736_11
|
||||
# 1736| r1736_13(glval<CopyConstructorWithImplicitArgumentClass>) = ConvertToNonVirtualBase[CopyConstructorTestNonVirtualClass : CopyConstructorWithImplicitArgumentClass] : r1736_12
|
||||
# 1736| r1736_14(CopyConstructorWithImplicitArgumentClass &) = CopyValue : r1736_13
|
||||
# 1736| v1736_15(void) = Call[CopyConstructorWithImplicitArgumentClass] : func:r1736_9, this:r1736_8, 0:r1736_14
|
||||
# 1736| mu1736_16(unknown) = ^CallSideEffect : ~m?
|
||||
# 1736| v1736_17(void) = ^BufferReadSideEffect[0] : &:r1736_14, ~m?
|
||||
# 1736| mu1736_18(CopyConstructorWithImplicitArgumentClass) = ^IndirectMayWriteSideEffect[-1] : &:r1736_8
|
||||
# 1736| v1736_19(void) = NoOp :
|
||||
# 1736| v1736_20(void) = ReturnIndirection[#this] : &:r1736_6, ~m?
|
||||
#-----| v0_5(void) = ReturnIndirection[(unnamed parameter 0)] : &:r0_3, ~m?
|
||||
# 1736| v1736_21(void) = ReturnVoid :
|
||||
# 1736| v1736_22(void) = AliasedUse : ~m?
|
||||
# 1736| v1736_23(void) = ExitFunction :
|
||||
|
||||
# 1740| void CopyConstructorTestNonVirtualClass::CopyConstructorTestNonVirtualClass()
|
||||
# 1740| Block 0
|
||||
# 1740| v1740_1(void) = EnterFunction :
|
||||
# 1740| mu1740_2(unknown) = AliasedDefinition :
|
||||
# 1740| mu1740_3(unknown) = InitializeNonLocal :
|
||||
# 1740| r1740_4(glval<unknown>) = VariableAddress[#this] :
|
||||
# 1740| mu1740_5(glval<CopyConstructorTestNonVirtualClass>) = InitializeParameter[#this] : &:r1740_4
|
||||
# 1740| r1740_6(glval<CopyConstructorTestNonVirtualClass>) = Load[#this] : &:r1740_4, ~m?
|
||||
# 1740| mu1740_7(CopyConstructorTestNonVirtualClass) = InitializeIndirection[#this] : &:r1740_6
|
||||
# 1740| r1740_8(glval<CopyConstructorWithImplicitArgumentClass>) = ConvertToNonVirtualBase[CopyConstructorTestNonVirtualClass : CopyConstructorWithImplicitArgumentClass] : mu1740_5
|
||||
# 1740| r1740_9(glval<unknown>) = FunctionAddress[CopyConstructorWithImplicitArgumentClass] :
|
||||
# 1740| v1740_10(void) = Call[CopyConstructorWithImplicitArgumentClass] : func:r1740_9, this:r1740_8
|
||||
# 1740| mu1740_11(unknown) = ^CallSideEffect : ~m?
|
||||
# 1740| mu1740_12(CopyConstructorWithImplicitArgumentClass) = ^IndirectMayWriteSideEffect[-1] : &:r1740_8
|
||||
# 1740| r1740_13(glval<CopyConstructorWithBitwiseCopyClass>) = ConvertToNonVirtualBase[CopyConstructorTestNonVirtualClass : CopyConstructorWithBitwiseCopyClass] : mu1740_5
|
||||
# 1740| r1740_14(glval<unknown>) = FunctionAddress[CopyConstructorWithBitwiseCopyClass] :
|
||||
# 1740| v1740_15(void) = Call[CopyConstructorWithBitwiseCopyClass] : func:r1740_14, this:r1740_13
|
||||
# 1740| mu1740_16(unknown) = ^CallSideEffect : ~m?
|
||||
# 1740| mu1740_17(CopyConstructorWithBitwiseCopyClass) = ^IndirectMayWriteSideEffect[-1] : &:r1740_13
|
||||
# 1740| v1740_18(void) = NoOp :
|
||||
# 1740| v1740_19(void) = ReturnIndirection[#this] : &:r1740_6, ~m?
|
||||
# 1740| v1740_20(void) = ReturnVoid :
|
||||
# 1740| v1740_21(void) = AliasedUse : ~m?
|
||||
# 1740| v1740_22(void) = ExitFunction :
|
||||
|
||||
# 1743| void CopyConstructorTestVirtualClass::CopyConstructorTestVirtualClass(CopyConstructorTestVirtualClass const&)
|
||||
# 1743| Block 0
|
||||
# 1743| v1743_1(void) = EnterFunction :
|
||||
# 1743| mu1743_2(unknown) = AliasedDefinition :
|
||||
# 1743| mu1743_3(unknown) = InitializeNonLocal :
|
||||
# 1743| r1743_4(glval<unknown>) = VariableAddress[#this] :
|
||||
# 1743| mu1743_5(glval<CopyConstructorTestVirtualClass>) = InitializeParameter[#this] : &:r1743_4
|
||||
# 1743| r1743_6(glval<CopyConstructorTestVirtualClass>) = Load[#this] : &:r1743_4, ~m?
|
||||
# 1743| mu1743_7(CopyConstructorTestVirtualClass) = InitializeIndirection[#this] : &:r1743_6
|
||||
#-----| r0_1(glval<CopyConstructorTestVirtualClass &>) = VariableAddress[(unnamed parameter 0)] :
|
||||
#-----| mu0_2(CopyConstructorTestVirtualClass &) = InitializeParameter[(unnamed parameter 0)] : &:r0_1
|
||||
#-----| r0_3(CopyConstructorTestVirtualClass &) = Load[(unnamed parameter 0)] : &:r0_1, ~m?
|
||||
#-----| mu0_4(unknown) = InitializeIndirection[(unnamed parameter 0)] : &:r0_3
|
||||
# 1743| r1743_8(glval<CopyConstructorWithImplicitArgumentClass>) = ConvertToNonVirtualBase[CopyConstructorTestVirtualClass : CopyConstructorWithImplicitArgumentClass] : mu1743_5
|
||||
# 1743| r1743_9(glval<unknown>) = FunctionAddress[CopyConstructorWithImplicitArgumentClass] :
|
||||
# 1743| r1743_10(glval<CopyConstructorTestVirtualClass &>) = VariableAddress[(unnamed parameter 0)] :
|
||||
# 1743| r1743_11(CopyConstructorTestVirtualClass &) = Load[(unnamed parameter 0)] : &:r1743_10, ~m?
|
||||
# 1743| r1743_12(glval<CopyConstructorTestVirtualClass>) = CopyValue : r1743_11
|
||||
# 1743| r1743_13(glval<CopyConstructorWithImplicitArgumentClass>) = ConvertToVirtualBase[CopyConstructorTestVirtualClass : CopyConstructorWithImplicitArgumentClass] : r1743_12
|
||||
# 1743| r1743_14(CopyConstructorWithImplicitArgumentClass &) = CopyValue : r1743_13
|
||||
# 1743| v1743_15(void) = Call[CopyConstructorWithImplicitArgumentClass] : func:r1743_9, this:r1743_8, 0:r1743_14
|
||||
# 1743| mu1743_16(unknown) = ^CallSideEffect : ~m?
|
||||
# 1743| v1743_17(void) = ^BufferReadSideEffect[0] : &:r1743_14, ~m?
|
||||
# 1743| mu1743_18(CopyConstructorWithImplicitArgumentClass) = ^IndirectMayWriteSideEffect[-1] : &:r1743_8
|
||||
# 1743| v1743_19(void) = NoOp :
|
||||
# 1743| v1743_20(void) = ReturnIndirection[#this] : &:r1743_6, ~m?
|
||||
#-----| v0_5(void) = ReturnIndirection[(unnamed parameter 0)] : &:r0_3, ~m?
|
||||
# 1743| v1743_21(void) = ReturnVoid :
|
||||
# 1743| v1743_22(void) = AliasedUse : ~m?
|
||||
# 1743| v1743_23(void) = ExitFunction :
|
||||
|
||||
# 1747| void CopyConstructorTestVirtualClass::CopyConstructorTestVirtualClass()
|
||||
# 1747| Block 0
|
||||
# 1747| v1747_1(void) = EnterFunction :
|
||||
# 1747| mu1747_2(unknown) = AliasedDefinition :
|
||||
# 1747| mu1747_3(unknown) = InitializeNonLocal :
|
||||
# 1747| r1747_4(glval<unknown>) = VariableAddress[#this] :
|
||||
# 1747| mu1747_5(glval<CopyConstructorTestVirtualClass>) = InitializeParameter[#this] : &:r1747_4
|
||||
# 1747| r1747_6(glval<CopyConstructorTestVirtualClass>) = Load[#this] : &:r1747_4, ~m?
|
||||
# 1747| mu1747_7(CopyConstructorTestVirtualClass) = InitializeIndirection[#this] : &:r1747_6
|
||||
# 1747| r1747_8(glval<CopyConstructorWithImplicitArgumentClass>) = ConvertToNonVirtualBase[CopyConstructorTestVirtualClass : CopyConstructorWithImplicitArgumentClass] : mu1747_5
|
||||
# 1747| r1747_9(glval<unknown>) = FunctionAddress[CopyConstructorWithImplicitArgumentClass] :
|
||||
# 1747| v1747_10(void) = Call[CopyConstructorWithImplicitArgumentClass] : func:r1747_9, this:r1747_8
|
||||
# 1747| mu1747_11(unknown) = ^CallSideEffect : ~m?
|
||||
# 1747| mu1747_12(CopyConstructorWithImplicitArgumentClass) = ^IndirectMayWriteSideEffect[-1] : &:r1747_8
|
||||
# 1747| r1747_13(glval<CopyConstructorWithBitwiseCopyClass>) = ConvertToNonVirtualBase[CopyConstructorTestVirtualClass : CopyConstructorWithBitwiseCopyClass] : mu1747_5
|
||||
# 1747| r1747_14(glval<unknown>) = FunctionAddress[CopyConstructorWithBitwiseCopyClass] :
|
||||
# 1747| v1747_15(void) = Call[CopyConstructorWithBitwiseCopyClass] : func:r1747_14, this:r1747_13
|
||||
# 1747| mu1747_16(unknown) = ^CallSideEffect : ~m?
|
||||
# 1747| mu1747_17(CopyConstructorWithBitwiseCopyClass) = ^IndirectMayWriteSideEffect[-1] : &:r1747_13
|
||||
# 1747| v1747_18(void) = NoOp :
|
||||
# 1747| v1747_19(void) = ReturnIndirection[#this] : &:r1747_6, ~m?
|
||||
# 1747| v1747_20(void) = ReturnVoid :
|
||||
# 1747| v1747_21(void) = AliasedUse : ~m?
|
||||
# 1747| v1747_22(void) = ExitFunction :
|
||||
|
||||
# 1750| int implicit_copy_constructor_test(CopyConstructorTestNonVirtualClass const&, CopyConstructorTestVirtualClass const&)
|
||||
# 1750| Block 0
|
||||
# 1750| v1750_1(void) = EnterFunction :
|
||||
# 1750| mu1750_2(unknown) = AliasedDefinition :
|
||||
# 1750| mu1750_3(unknown) = InitializeNonLocal :
|
||||
# 1751| r1751_1(glval<CopyConstructorTestNonVirtualClass &>) = VariableAddress[x] :
|
||||
# 1751| mu1751_2(CopyConstructorTestNonVirtualClass &) = InitializeParameter[x] : &:r1751_1
|
||||
# 1751| r1751_3(CopyConstructorTestNonVirtualClass &) = Load[x] : &:r1751_1, ~m?
|
||||
# 1751| mu1751_4(unknown) = InitializeIndirection[x] : &:r1751_3
|
||||
# 1752| r1752_1(glval<CopyConstructorTestVirtualClass &>) = VariableAddress[y] :
|
||||
# 1752| mu1752_2(CopyConstructorTestVirtualClass &) = InitializeParameter[y] : &:r1752_1
|
||||
# 1752| r1752_3(CopyConstructorTestVirtualClass &) = Load[y] : &:r1752_1, ~m?
|
||||
# 1752| mu1752_4(unknown) = InitializeIndirection[y] : &:r1752_3
|
||||
# 1753| r1753_1(glval<CopyConstructorTestNonVirtualClass>) = VariableAddress[cx] :
|
||||
# 1753| mu1753_2(CopyConstructorTestNonVirtualClass) = Uninitialized[cx] : &:r1753_1
|
||||
# 1753| r1753_3(glval<unknown>) = FunctionAddress[CopyConstructorTestNonVirtualClass] :
|
||||
# 1753| r1753_4(glval<CopyConstructorTestNonVirtualClass &>) = VariableAddress[x] :
|
||||
# 1753| r1753_5(CopyConstructorTestNonVirtualClass &) = Load[x] : &:r1753_4, ~m?
|
||||
# 1753| r1753_6(glval<CopyConstructorTestNonVirtualClass>) = CopyValue : r1753_5
|
||||
# 1753| r1753_7(CopyConstructorTestNonVirtualClass &) = CopyValue : r1753_6
|
||||
# 1753| v1753_8(void) = Call[CopyConstructorTestNonVirtualClass] : func:r1753_3, this:r1753_1, 0:r1753_7
|
||||
# 1753| mu1753_9(unknown) = ^CallSideEffect : ~m?
|
||||
# 1753| v1753_10(void) = ^BufferReadSideEffect[0] : &:r1753_7, ~m?
|
||||
# 1753| mu1753_11(CopyConstructorTestNonVirtualClass) = ^IndirectMayWriteSideEffect[-1] : &:r1753_1
|
||||
# 1754| r1754_1(glval<CopyConstructorTestVirtualClass>) = VariableAddress[cy] :
|
||||
# 1754| mu1754_2(CopyConstructorTestVirtualClass) = Uninitialized[cy] : &:r1754_1
|
||||
# 1754| r1754_3(glval<unknown>) = FunctionAddress[CopyConstructorTestVirtualClass] :
|
||||
# 1754| r1754_4(glval<CopyConstructorTestVirtualClass &>) = VariableAddress[y] :
|
||||
# 1754| r1754_5(CopyConstructorTestVirtualClass &) = Load[y] : &:r1754_4, ~m?
|
||||
# 1754| r1754_6(glval<CopyConstructorTestVirtualClass>) = CopyValue : r1754_5
|
||||
# 1754| r1754_7(CopyConstructorTestVirtualClass &) = CopyValue : r1754_6
|
||||
# 1754| v1754_8(void) = Call[CopyConstructorTestVirtualClass] : func:r1754_3, this:r1754_1, 0:r1754_7
|
||||
# 1754| mu1754_9(unknown) = ^CallSideEffect : ~m?
|
||||
# 1754| v1754_10(void) = ^BufferReadSideEffect[0] : &:r1754_7, ~m?
|
||||
# 1754| mu1754_11(CopyConstructorTestVirtualClass) = ^IndirectMayWriteSideEffect[-1] : &:r1754_1
|
||||
# 1755| v1755_1(void) = Unreached :
|
||||
|
||||
# 1751| Block 1
|
||||
# 1751| v1751_5(void) = ReturnIndirection[x] : &:r1751_3, ~m?
|
||||
# 1752| v1752_5(void) = ReturnIndirection[y] : &:r1752_3, ~m?
|
||||
# 1750| r1750_4(glval<int>) = VariableAddress[#return] :
|
||||
# 1750| v1750_5(void) = ReturnValue : &:r1750_4, ~m?
|
||||
# 1750| v1750_6(void) = AliasedUse : ~m?
|
||||
# 1750| v1750_7(void) = ExitFunction :
|
||||
|
||||
perf-regression.cpp:
|
||||
# 6| void Big::Big()
|
||||
# 6| Block 0
|
||||
|
||||
@@ -6,8 +6,6 @@ missingOperandType
|
||||
duplicateChiOperand
|
||||
sideEffectWithoutPrimary
|
||||
instructionWithoutSuccessor
|
||||
| ir.cpp:1688:24:1690:5 | FieldAddress: {...} | Instruction 'FieldAddress: {...}' has no successors in function '$@'. | ir.cpp:1683:6:1683:20 | void captured_lambda(int, int&, int&&) | void captured_lambda(int, int&, int&&) |
|
||||
| ir.cpp:1689:28:1689:54 | FieldAddress: {...} | Instruction 'FieldAddress: {...}' has no successors in function '$@'. | ir.cpp:1688:46:1688:46 | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const |
|
||||
ambiguousSuccessors
|
||||
unexplainedLoop
|
||||
unnecessaryPhiInstruction
|
||||
|
||||
@@ -6,8 +6,6 @@ missingOperandType
|
||||
duplicateChiOperand
|
||||
sideEffectWithoutPrimary
|
||||
instructionWithoutSuccessor
|
||||
| ir.cpp:1688:24:1690:5 | FieldAddress: {...} | Instruction 'FieldAddress: {...}' has no successors in function '$@'. | ir.cpp:1683:6:1683:20 | void captured_lambda(int, int&, int&&) | void captured_lambda(int, int&, int&&) |
|
||||
| ir.cpp:1689:28:1689:54 | FieldAddress: {...} | Instruction 'FieldAddress: {...}' has no successors in function '$@'. | ir.cpp:1688:46:1688:46 | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const |
|
||||
ambiguousSuccessors
|
||||
unexplainedLoop
|
||||
unnecessaryPhiInstruction
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
import cpp
|
||||
import experimental.semmle.code.cpp.semantic.analysis.ModulusAnalysis
|
||||
import experimental.semmle.code.cpp.semantic.Semantic
|
||||
import semmle.code.cpp.ir.IR as IR
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
|
||||
class ModulusAnalysisTest extends InlineExpectationsTest {
|
||||
ModulusAnalysisTest() { this = "ModulusAnalysisTest" }
|
||||
|
||||
override string getARelevantTag() { result = "mod" }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(SemExpr e, IR::CallInstruction call |
|
||||
call.getArgument(0) = e and
|
||||
call.getStaticCallTarget().hasName("mod") and
|
||||
tag = "mod" and
|
||||
element = e.toString() and
|
||||
location = e.getLocation() and
|
||||
value = getAModString(e)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private string getAModString(SemExpr e) {
|
||||
exists(SemBound b, int delta, int mod |
|
||||
semExprModulus(e, b, delta, mod) and
|
||||
result = b.toString() + "," + delta.toString() + "," + mod.toString() and
|
||||
not (delta = 0 and mod = 0)
|
||||
)
|
||||
}
|
||||
60
cpp/ql/test/library-tests/ir/modulus-analysis/test.cpp
Normal file
60
cpp/ql/test/library-tests/ir/modulus-analysis/test.cpp
Normal file
@@ -0,0 +1,60 @@
|
||||
template<typename T> void mod(T value);
|
||||
|
||||
const int c1 = 42;
|
||||
const int c2 = 43;
|
||||
|
||||
void m(int i, bool cond, int x, int y) {
|
||||
int eq = i + 3;
|
||||
|
||||
int mul = eq * c1 + 3; // congruent 3 mod 42
|
||||
|
||||
int seven = 7;
|
||||
if (mul % c2 == seven) {
|
||||
mod(mul); // congruent 3 mod 42, 7 mod 43
|
||||
}
|
||||
|
||||
int j = cond
|
||||
? i * 4 + 3
|
||||
: i * 8 + 7;
|
||||
mod(j); // $ mod=0,3,4
|
||||
|
||||
if (x % c1 == 3 && y % c1 == 7) {
|
||||
// Need implies_v2
|
||||
mod(x + y); // $ MISSING: 0,10,42
|
||||
}
|
||||
|
||||
if (x % c1 == 3 && y % c1 == 7) {
|
||||
// Need implies_v2
|
||||
mod(x - y); // $ MISSING: mod=0,38,42
|
||||
}
|
||||
|
||||
if (cond) {
|
||||
j = i * 4 + 3;
|
||||
}
|
||||
else {
|
||||
j = i * 8 + 7;
|
||||
}
|
||||
mod(j); // $ mod=0,3,4
|
||||
|
||||
if (cond) {
|
||||
mod(j); // $ mod=0,3,4
|
||||
} else {
|
||||
mod(j); // $ mod=0,3,4
|
||||
}
|
||||
|
||||
if ((x & 15) == 3) {
|
||||
mod(x); // $ mod=0,3,16
|
||||
}
|
||||
}
|
||||
|
||||
void loops(int cap)
|
||||
{
|
||||
for (int i = 0; i < cap; i++)
|
||||
mod(i);
|
||||
|
||||
for (int j = 0; j < cap; j += 1)
|
||||
mod(j);
|
||||
|
||||
for (int k = 0; k < cap; k += 3)
|
||||
mod(k); // $ mod=0,0,3
|
||||
}
|
||||
51
cpp/ql/test/library-tests/ir/range-analysis/RangeAnalysis.ql
Normal file
51
cpp/ql/test/library-tests/ir/range-analysis/RangeAnalysis.ql
Normal file
@@ -0,0 +1,51 @@
|
||||
import cpp
|
||||
import experimental.semmle.code.cpp.semantic.analysis.RangeAnalysis
|
||||
import experimental.semmle.code.cpp.semantic.Semantic
|
||||
import semmle.code.cpp.ir.IR as IR
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
|
||||
class RangeAnalysisTest extends InlineExpectationsTest {
|
||||
RangeAnalysisTest() { this = "RangeAnalysisTest" }
|
||||
|
||||
override string getARelevantTag() { result = "range" }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(SemExpr e, IR::CallInstruction call |
|
||||
call.getArgument(0) = e and
|
||||
call.getStaticCallTarget().hasName("range") and
|
||||
tag = "range" and
|
||||
element = e.toString() and
|
||||
location = e.getLocation() and
|
||||
value = getARangeString(e)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private string getDirectionString(boolean d) {
|
||||
result = "<=" and d = true
|
||||
or
|
||||
result = ">=" and d = false
|
||||
}
|
||||
|
||||
bindingset[value]
|
||||
private string getOffsetString(int value) {
|
||||
if value >= 0 then result = "+" + value.toString() else result = value.toString()
|
||||
}
|
||||
|
||||
bindingset[delta]
|
||||
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)
|
||||
}
|
||||
|
||||
private string getARangeString(SemExpr e) {
|
||||
exists(SemBound b, int delta, boolean upper |
|
||||
semBounded(e, b, delta, upper, _) and
|
||||
if semBounded(e, b, delta, upper.booleanNot(), _)
|
||||
then delta != 0 and result = "==" + getBoundString(b, delta)
|
||||
else result = getDirectionString(upper) + getBoundString(b, delta)
|
||||
)
|
||||
}
|
||||
51
cpp/ql/test/library-tests/ir/range-analysis/test.cpp
Normal file
51
cpp/ql/test/library-tests/ir/range-analysis/test.cpp
Normal file
@@ -0,0 +1,51 @@
|
||||
template<typename T> void range(T value);
|
||||
int f1(int x, int y) {
|
||||
if (x < 500) {
|
||||
if (x > 400) {
|
||||
range(x); // $ range=>=401 range=<=499
|
||||
return x;
|
||||
}
|
||||
|
||||
if (y - 2 == x && y > 300) {
|
||||
range(x + y); // $ range=>=300 range=>=x+1 range=>=y-1
|
||||
return x + y;
|
||||
}
|
||||
|
||||
if (x != y + 1) {
|
||||
range(x); // $ range=<=400
|
||||
int sum = x + y;
|
||||
} else {
|
||||
if (y > 300) {
|
||||
range(x); // $ range=>=302 range=<=400 range===y+1
|
||||
range(y); // $ range=>=301 range=<=399 range===x-1
|
||||
int sum = x + y;
|
||||
}
|
||||
}
|
||||
|
||||
if (x > 500) {
|
||||
range(x); // $ range=<=400 range=>=501
|
||||
return x;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int f2(int x, int y, int z) {
|
||||
if (x < 500) {
|
||||
if (x > 400) {
|
||||
range(x); // $ range=>=401 range=<=499
|
||||
return x;
|
||||
}
|
||||
|
||||
if (y == x - 1 && y > 300 && y + 2 == z && z == 350) {
|
||||
range(x); // $ range===349 range===y+1 range===z-1
|
||||
range(y); // $ range===348 range===x-1 range===z-2
|
||||
range(z); // $ range===350 range===x+1 range===y+2
|
||||
return x + y + z;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
24
cpp/ql/test/library-tests/ir/sign-analysis/SignAnalysis.ql
Normal file
24
cpp/ql/test/library-tests/ir/sign-analysis/SignAnalysis.ql
Normal file
@@ -0,0 +1,24 @@
|
||||
import cpp
|
||||
import experimental.semmle.code.cpp.semantic.analysis.SignAnalysisCommon
|
||||
import experimental.semmle.code.cpp.semantic.Semantic
|
||||
import semmle.code.cpp.ir.IR as IR
|
||||
import TestUtilities.InlineExpectationsTest
|
||||
|
||||
class SignAnalysisTest extends InlineExpectationsTest {
|
||||
SignAnalysisTest() { this = "SignAnalysisTest" }
|
||||
|
||||
override string getARelevantTag() { result = "sign" }
|
||||
|
||||
override predicate hasActualResult(Location location, string element, string tag, string value) {
|
||||
exists(SemExpr e, IR::CallInstruction call |
|
||||
call.getArgument(0) = e and
|
||||
call.getStaticCallTarget().hasName("sign") and
|
||||
tag = "sign" and
|
||||
element = e.toString() and
|
||||
location = e.getLocation() and
|
||||
value = getASignString(e)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private string getASignString(SemExpr e) { result = strictconcat(semExprSign(e).toString(), "") }
|
||||
57
cpp/ql/test/library-tests/ir/sign-analysis/test.cpp
Normal file
57
cpp/ql/test/library-tests/ir/sign-analysis/test.cpp
Normal file
@@ -0,0 +1,57 @@
|
||||
template<typename T> T sign(T value);
|
||||
|
||||
int f1(int x, int y) {
|
||||
if (x < 0) {
|
||||
return sign(x); // $ sign=-
|
||||
}
|
||||
if (x < y) {
|
||||
return sign(y); // $ sign=+
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void u(int x) {
|
||||
unsigned c = (unsigned)x;
|
||||
sign(c); // $ sign=+0
|
||||
}
|
||||
|
||||
void constants() {
|
||||
int i_pos = 1234;
|
||||
sign(i_pos); // $ sign=+
|
||||
int i_neg = -1234;
|
||||
sign(i_neg); // $ sign=-
|
||||
int i_zero = 0;
|
||||
sign(i_zero); // $ sign=0
|
||||
long l_pos = 1234;
|
||||
sign(l_pos); // $ sign=+
|
||||
long l_neg = -1234;
|
||||
sign(l_neg); // $ sign=-
|
||||
long l_zero = 0;
|
||||
sign(l_zero); // $ sign=0
|
||||
long l_pos_big = 0x00000001baadf00d;
|
||||
sign(l_pos_big); // $ sign=+
|
||||
float f_pos = 1.234f;
|
||||
sign(f_pos); // $ sign=+
|
||||
float f_neg = -1.234f;
|
||||
sign(f_neg); // $ sign=-
|
||||
float f_zero = 0.0f;
|
||||
sign(f_zero); // $ sign=0
|
||||
}
|
||||
|
||||
void arithmetic(int y) {
|
||||
int x = 0;
|
||||
sign(x + 1); // $ sign=+
|
||||
x = -1;
|
||||
sign(x); // $ sign=-
|
||||
sign(x + 1); // $ sign=+-0 // Ideally 0 because it's constant
|
||||
if (y < 0) {
|
||||
sign(y); // $ sign=-
|
||||
sign(y + 1); // $ sign=+-0 // Ideally -0 because it's only adding one.
|
||||
int z = y;
|
||||
sign(++z); // $ sign=+-0 // Ideally -0 because it's only adding one.
|
||||
z = y;
|
||||
sign(z++); // $ sign=-
|
||||
sign(z); // $ sign=+-0 // Ideally -0 because it's only adding one.
|
||||
}
|
||||
}
|
||||
@@ -122,11 +122,13 @@
|
||||
| captures.cpp:22:18:24:3 | initializer for myLambda |
|
||||
| captures.cpp:22:18:24:3 | y |
|
||||
| captures.cpp:22:18:24:3 | {...} |
|
||||
| captures.cpp:22:19:22:19 | (reference dereference) |
|
||||
| captures.cpp:22:19:22:19 | (reference dereference) |
|
||||
| captures.cpp:22:19:22:19 | (unnamed constructor) |
|
||||
| captures.cpp:22:19:22:19 | (unnamed constructor) |
|
||||
| captures.cpp:22:19:22:19 | (unnamed constructor) |
|
||||
| captures.cpp:22:19:22:19 | Unknown literal |
|
||||
| captures.cpp:22:19:22:19 | Unknown literal |
|
||||
| captures.cpp:22:19:22:19 | (unnamed parameter 0) |
|
||||
| captures.cpp:22:19:22:19 | (unnamed parameter 0) |
|
||||
| captures.cpp:22:19:22:19 | constructor init of field x |
|
||||
| captures.cpp:22:19:22:19 | constructor init of field y |
|
||||
| captures.cpp:22:19:22:19 | declaration of (unnamed constructor) |
|
||||
@@ -135,6 +137,8 @@
|
||||
| captures.cpp:22:19:22:19 | definition of operator= |
|
||||
| captures.cpp:22:19:22:19 | operator= |
|
||||
| captures.cpp:22:19:22:19 | return ... |
|
||||
| captures.cpp:22:19:22:19 | x |
|
||||
| captures.cpp:22:19:22:19 | y |
|
||||
| captures.cpp:22:19:22:19 | { ... } |
|
||||
| captures.cpp:22:23:22:23 | definition of x |
|
||||
| captures.cpp:22:23:22:23 | x |
|
||||
@@ -182,15 +186,17 @@
|
||||
| end_pos.cpp:9:14:11:5 | [...](...){...} |
|
||||
| end_pos.cpp:9:14:11:5 | initializer for fp |
|
||||
| end_pos.cpp:9:14:11:5 | {...} |
|
||||
| end_pos.cpp:9:15:9:15 | (reference dereference) |
|
||||
| end_pos.cpp:9:15:9:15 | (unnamed constructor) |
|
||||
| end_pos.cpp:9:15:9:15 | (unnamed constructor) |
|
||||
| end_pos.cpp:9:15:9:15 | (unnamed constructor) |
|
||||
| end_pos.cpp:9:15:9:15 | Unknown literal |
|
||||
| end_pos.cpp:9:15:9:15 | (unnamed parameter 0) |
|
||||
| end_pos.cpp:9:15:9:15 | constructor init of field ii |
|
||||
| end_pos.cpp:9:15:9:15 | declaration of (unnamed constructor) |
|
||||
| end_pos.cpp:9:15:9:15 | definition of (unnamed constructor) |
|
||||
| end_pos.cpp:9:15:9:15 | definition of (unnamed constructor) |
|
||||
| end_pos.cpp:9:15:9:15 | definition of operator= |
|
||||
| end_pos.cpp:9:15:9:15 | ii |
|
||||
| end_pos.cpp:9:15:9:15 | operator= |
|
||||
| end_pos.cpp:9:15:9:15 | return ... |
|
||||
| end_pos.cpp:9:15:9:15 | { ... } |
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user