mirror of
https://github.com/github/codeql.git
synced 2026-04-29 18:55:14 +02:00
Merge remote-tracking branch 'remotes/origin/main' into marcono1234/statement-expression
This commit is contained in:
3
.github/workflows/check-qldoc.yml
vendored
3
.github/workflows/check-qldoc.yml
vendored
@@ -37,6 +37,9 @@ jobs:
|
||||
done
|
||||
git checkout HEAD^
|
||||
for pack_dir in ${changed_lib_packs}; do
|
||||
# When we add a new language, pack_dir would not exist in HEAD^.
|
||||
# In this case the right thing to do is to skip the check.
|
||||
[[ ! -d "${pack_dir}" ]] && continue
|
||||
lang="${pack_dir%/ql/lib}"
|
||||
gh codeql generate library-doc-coverage --output="${RUNNER_TEMP}/${lang}-baseline.txt" --dir="${pack_dir}"
|
||||
awk -F, '{gsub(/"/,""); if ($4==0 && $6=="public") print "\""$3"\"" }' "${RUNNER_TEMP}/${lang}-current.txt" | sort -u > "${RUNNER_TEMP}/current-undocumented.txt"
|
||||
|
||||
7
.gitignore
vendored
7
.gitignore
vendored
@@ -17,7 +17,7 @@
|
||||
# Byte-compiled python files
|
||||
*.pyc
|
||||
|
||||
# python virtual environment folder
|
||||
# python virtual environment folder
|
||||
.venv/
|
||||
|
||||
# It's useful (though not required) to be able to unpack codeql in the ql checkout itself
|
||||
@@ -29,4 +29,7 @@ csharp/extractor/Semmle.Extraction.CSharp.Driver/Properties/launchSettings.json
|
||||
.codeql
|
||||
|
||||
# Compiled class file
|
||||
*.class
|
||||
*.class
|
||||
|
||||
# links create by bazel
|
||||
/bazel-*
|
||||
|
||||
12
CODEOWNERS
12
CODEOWNERS
@@ -5,14 +5,6 @@
|
||||
/python/ @github/codeql-python
|
||||
/ruby/ @github/codeql-ruby
|
||||
|
||||
# Make @xcorail (GitHub Security Lab) a code owner for experimental queries so he gets pinged when we promote a query out of experimental
|
||||
/cpp/**/experimental/**/* @github/codeql-c-analysis @xcorail
|
||||
/csharp/**/experimental/**/* @github/codeql-csharp @xcorail
|
||||
/java/**/experimental/**/* @github/codeql-java @xcorail
|
||||
/javascript/**/experimental/**/* @github/codeql-javascript @xcorail
|
||||
/python/**/experimental/**/* @github/codeql-python @xcorail
|
||||
/ruby/**/experimental/**/* @github/codeql-ruby @xcorail
|
||||
|
||||
# ML-powered queries
|
||||
/javascript/ql/experimental/adaptivethreatmodeling/ @github/codeql-ml-powered-queries-reviewers
|
||||
|
||||
@@ -31,3 +23,7 @@
|
||||
|
||||
# QL for QL reviewers
|
||||
/ql/ @github/codeql-ql-for-ql-reviewers
|
||||
|
||||
# Bazel
|
||||
**/*.bazel @github/codeql-ci-reviewers
|
||||
**/*.bzl @github/codeql-ci-reviewers
|
||||
|
||||
@@ -70,3 +70,7 @@ After the experimental query is merged, we welcome pull requests to improve it.
|
||||
If you contribute to this project, we will record your name and email address (as provided by you with your contributions) as part of the code repositories, which are public. We might also use this information to contact you in relation to your contributions, as well as in the normal course of software development. We also store records of CLA agreements signed in the past, but no longer require contributors to sign a CLA. Under GDPR legislation, we do this on the basis of our legitimate interest in creating the CodeQL product.
|
||||
|
||||
Please do get in touch (privacy@github.com) if you have any questions about this or our data protection policies.
|
||||
|
||||
## Bazel
|
||||
Please notice that any bazel targets and definitions in this repository are currently experimental
|
||||
and for internal use only.
|
||||
|
||||
2
WORKSPACE.bazel
Normal file
2
WORKSPACE.bazel
Normal file
@@ -0,0 +1,2 @@
|
||||
# Please notice that any bazel targets and definitions in this repository are currently experimental
|
||||
# and for internal use only.
|
||||
@@ -75,13 +75,9 @@
|
||||
"java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/SsaReadPositionCommon.qll",
|
||||
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SsaReadPositionCommon.qll"
|
||||
],
|
||||
"Model as Data Generation Java/C# - Utils": [
|
||||
"java/ql/src/utils/model-generator/ModelGeneratorUtils.qll",
|
||||
"csharp/ql/src/utils/model-generator/ModelGeneratorUtils.qll"
|
||||
],
|
||||
"Model as Data Generation Java/C# - SummaryModels": [
|
||||
"java/ql/src/utils/model-generator/CaptureSummaryModels.qll",
|
||||
"csharp/ql/src/utils/model-generator/CaptureSummaryModels.qll"
|
||||
"Model as Data Generation Java/C# - CaptureModels": [
|
||||
"java/ql/src/utils/model-generator/internal/CaptureModels.qll",
|
||||
"csharp/ql/src/utils/model-generator/internal/CaptureModels.qll"
|
||||
],
|
||||
"Sign Java/C#": [
|
||||
"java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/Sign.qll",
|
||||
@@ -519,6 +515,10 @@
|
||||
"javascript/ql/lib/semmle/javascript/frameworks/data/internal/AccessPathSyntax.qll",
|
||||
"ruby/ql/lib/codeql/ruby/dataflow/internal/AccessPathSyntax.qll"
|
||||
],
|
||||
"IncompleteUrlSubstringSanitization": [
|
||||
"javascript/ql/src/Security/CWE-020/IncompleteUrlSubstringSanitization.qll",
|
||||
"ruby/ql/src/queries/security/cwe-020/IncompleteUrlSubstringSanitization.qll"
|
||||
],
|
||||
"Concepts Python/Ruby/JS": [
|
||||
"python/ql/lib/semmle/python/internal/ConceptsShared.qll",
|
||||
"ruby/ql/lib/codeql/ruby/internal/ConceptsShared.qll",
|
||||
@@ -549,4 +549,4 @@
|
||||
"javascript/ql/lib/semmle/javascript/security/dataflow/HttpToFileAccessCustomizations.qll",
|
||||
"ruby/ql/lib/codeql/ruby/security/HttpToFileAccessCustomizations.qll"
|
||||
]
|
||||
}
|
||||
}
|
||||
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",
|
||||
)
|
||||
@@ -1,3 +1,26 @@
|
||||
## 0.0.13
|
||||
|
||||
## 0.0.12
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
* The flow state variants of `isBarrier` and `isAdditionalFlowStep` are no longer exposed in the taint tracking library. The `isSanitizer` and `isAdditionalTaintStep` predicates should be used instead.
|
||||
|
||||
### Deprecated APIs
|
||||
|
||||
* Many classes/predicates/modules that had upper-case acronyms have been renamed to follow our style-guide.
|
||||
The old name still exists as a deprecated alias.
|
||||
|
||||
### New Features
|
||||
|
||||
* The data flow and taint tracking libraries have been extended with versions of `isBarrierIn`, `isBarrierOut`, and `isBarrierGuard`, respectively `isSanitizerIn`, `isSanitizerOut`, and `isSanitizerGuard`, that support flow states.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* `DefaultOptions::exits` now holds for C11 functions with the `_Noreturn` or `noreturn` specifier.
|
||||
* `hasImplicitCopyConstructor` and `hasImplicitCopyAssignmentOperator` now correctly handle implicitly-deleted operators in templates.
|
||||
* All deprecated predicates/classes/modules that have been deprecated for over a year have been deleted.
|
||||
|
||||
## 0.0.11
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* All deprecated predicates/classes/modules that have been deprecated for over a year have been deleted.
|
||||
@@ -1,5 +0,0 @@
|
||||
---
|
||||
category: deprecated
|
||||
---
|
||||
* Many classes/predicates/modules that had upper-case acronyms have been renamed to follow our style-guide.
|
||||
The old name still exists as a deprecated alias.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* `hasImplicitCopyConstructor` and `hasImplicitCopyAssignmentOperator` now correctly handle implicitly-deleted operators in templates.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* `DefaultOptions::exits` now holds for C11 functions with the `_Noreturn` or `noreturn` specifier.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: feature
|
||||
---
|
||||
* The data flow and taint tracking libraries have been extended with versions of `isBarrierIn`, `isBarrierOut`, and `isBarrierGuard`, respectively `isSanitizerIn`, `isSanitizerOut`, and `isSanitizerGuard`, that support flow states.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: breaking
|
||||
---
|
||||
* The flow state variants of `isBarrier` and `isAdditionalFlowStep` are no longer exposed in the taint tracking library. The `isSanitizer` and `isAdditionalTaintStep` predicates should be used instead.
|
||||
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.
|
||||
20
cpp/ql/lib/change-notes/released/0.0.12.md
Normal file
20
cpp/ql/lib/change-notes/released/0.0.12.md
Normal file
@@ -0,0 +1,20 @@
|
||||
## 0.0.12
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
* The flow state variants of `isBarrier` and `isAdditionalFlowStep` are no longer exposed in the taint tracking library. The `isSanitizer` and `isAdditionalTaintStep` predicates should be used instead.
|
||||
|
||||
### Deprecated APIs
|
||||
|
||||
* Many classes/predicates/modules that had upper-case acronyms have been renamed to follow our style-guide.
|
||||
The old name still exists as a deprecated alias.
|
||||
|
||||
### New Features
|
||||
|
||||
* The data flow and taint tracking libraries have been extended with versions of `isBarrierIn`, `isBarrierOut`, and `isBarrierGuard`, respectively `isSanitizerIn`, `isSanitizerOut`, and `isSanitizerGuard`, that support flow states.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* `DefaultOptions::exits` now holds for C11 functions with the `_Noreturn` or `noreturn` specifier.
|
||||
* `hasImplicitCopyConstructor` and `hasImplicitCopyAssignmentOperator` now correctly handle implicitly-deleted operators in templates.
|
||||
* All deprecated predicates/classes/modules that have been deprecated for over a year have been deleted.
|
||||
1
cpp/ql/lib/change-notes/released/0.0.13.md
Normal file
1
cpp/ql/lib/change-notes/released/0.0.13.md
Normal file
@@ -0,0 +1 @@
|
||||
## 0.0.13
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.0.11
|
||||
lastReleaseVersion: 0.0.13
|
||||
|
||||
@@ -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() }
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-all
|
||||
version: 0.0.12-dev
|
||||
version: 0.1.0-dev
|
||||
groups: cpp
|
||||
dbscheme: semmlecode.cpp.dbscheme
|
||||
extractor: cpp
|
||||
|
||||
@@ -80,7 +80,11 @@ abstract class StackVariableReachability extends string {
|
||||
j > i and
|
||||
sink = bb.getNode(j) and
|
||||
this.isSink(sink, v) and
|
||||
not exists(int k | this.isBarrier(bb.getNode(k), v) | k in [i + 1 .. j - 1])
|
||||
not exists(int k, ControlFlowNode node |
|
||||
node = bb.getNode(k) and this.isBarrier(pragma[only_bind_into](node), v)
|
||||
|
|
||||
k in [i + 1 .. j - 1]
|
||||
)
|
||||
)
|
||||
or
|
||||
not exists(int k | this.isBarrier(bb.getNode(k), v) | k > i) and
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -25,6 +25,7 @@ predicate guardedAbs(Operation e, Expr use) {
|
||||
* Holds if the value of `use` is guarded to be less than something, and `e`
|
||||
* is in code controlled by that guard (where the guard condition held).
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate guardedLesser(Operation e, Expr use) {
|
||||
exists(GuardCondition c | c.ensuresLt(use, _, _, e.getBasicBlock(), true))
|
||||
or
|
||||
@@ -35,6 +36,7 @@ predicate guardedLesser(Operation e, Expr use) {
|
||||
* Holds if the value of `use` is guarded to be greater than something, and `e`
|
||||
* is in code controlled by that guard (where the guard condition held).
|
||||
*/
|
||||
pragma[nomagic]
|
||||
predicate guardedGreater(Operation e, Expr use) {
|
||||
exists(GuardCondition c | c.ensuresLt(use, _, _, e.getBasicBlock(), false))
|
||||
or
|
||||
|
||||
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"
|
||||
|
||||
@@ -1,3 +1,12 @@
|
||||
## 0.0.13
|
||||
|
||||
## 0.0.12
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The `cpp/overflow-destination`, `cpp/unclear-array-index-validation`, and `cpp/uncontrolled-allocation-size` queries have been modernized and converted to `path-problem` queries and provide more true positive results.
|
||||
* The `cpp/system-data-exposure` query has been increased from `medium` to `high` precision, following a number of improvements to the query logic.
|
||||
|
||||
## 0.0.11
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
@@ -116,8 +116,8 @@ class ExecTaintConfiguration extends TaintTracking::Configuration {
|
||||
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
|
||||
override predicate isSanitizerOut(DataFlow::Node node) {
|
||||
isSink(node, _) // Prevent duplicates along a call chain, since `shellCommand` will include wrappers
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The `cpp/system-data-exposure` query has been increased from `medium` to `high` precision, following a number of improvements to the query logic.
|
||||
@@ -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.
|
||||
@@ -1,4 +1,6 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
## 0.0.12
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The `cpp/overflow-destination`, `cpp/unclear-array-index-validation`, and `cpp/uncontrolled-allocation-size` queries have been modernized and converted to `path-problem` queries and provide more true positive results.
|
||||
* The `cpp/system-data-exposure` query has been increased from `medium` to `high` precision, following a number of improvements to the query logic.
|
||||
1
cpp/ql/src/change-notes/released/0.0.13.md
Normal file
1
cpp/ql/src/change-notes/released/0.0.13.md
Normal file
@@ -0,0 +1 @@
|
||||
## 0.0.13
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.0.11
|
||||
lastReleaseVersion: 0.0.13
|
||||
|
||||
@@ -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()
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-queries
|
||||
version: 0.0.12-dev
|
||||
version: 0.1.0-dev
|
||||
groups:
|
||||
- cpp
|
||||
- queries
|
||||
|
||||
@@ -155,21 +155,27 @@ bad_asts.cpp:
|
||||
# 19| getInitializer(0): [ConstructorFieldInit] constructor init of field x
|
||||
# 19| Type = [IntType] int
|
||||
# 19| ValueCategory = prvalue
|
||||
# 19| getExpr(): [FieldAccess] x
|
||||
# 19| getExpr(): [ReferenceFieldAccess] x
|
||||
# 19| Type = [IntType] int
|
||||
# 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(): [FieldAccess] y
|
||||
# 19| getExpr(): [ReferenceFieldAccess] y
|
||||
# 19| Type = [IntType] int
|
||||
# 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&&)
|
||||
@@ -11651,75 +11657,99 @@ ir.cpp:
|
||||
# 1486| getInitializer(0): [ConstructorFieldInit] constructor init of field i
|
||||
# 1486| Type = [IntType] int
|
||||
# 1486| ValueCategory = prvalue
|
||||
# 1486| getExpr(): [FieldAccess] i
|
||||
# 1486| getExpr(): [ReferenceFieldAccess] i
|
||||
# 1486| Type = [IntType] int
|
||||
# 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(): [FieldAccess] d
|
||||
# 1486| getExpr(): [ReferenceFieldAccess] d
|
||||
# 1486| Type = [DoubleType] double
|
||||
# 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(): [FieldAccess] b
|
||||
# 1486| getExpr(): [ReferenceFieldAccess] b
|
||||
# 1486| Type = [IntType] unsigned int
|
||||
# 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(): [FieldAccess] r
|
||||
# 1486| getExpr(): [ReferenceFieldAccess] r
|
||||
# 1486| Type = [LValueReferenceType] int &
|
||||
# 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(): [FieldAccess] p
|
||||
# 1486| getExpr(): [ReferenceFieldAccess] p
|
||||
# 1486| Type = [IntPointerType] int *
|
||||
# 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(): [FieldAccess] xs
|
||||
# 1486| getExpr(): [ReferenceFieldAccess] xs
|
||||
# 1486| Type = [CTypedefType,NestedTypedefType] ArrayType
|
||||
# 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(): [FieldAccess] r_alt
|
||||
# 1486| getExpr(): [ReferenceFieldAccess] r_alt
|
||||
# 1486| Type = [CTypedefType,NestedTypedefType] RefType
|
||||
# 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(): [FieldAccess] m
|
||||
# 1486| getExpr(): [ReferenceFieldAccess] m
|
||||
# 1486| Type = [Struct] StructuredBindingDataMemberMemberStruct
|
||||
# 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&&)
|
||||
@@ -12096,30 +12126,39 @@ ir.cpp:
|
||||
# 1539| getInitializer(0): [ConstructorFieldInit] constructor init of field i
|
||||
# 1539| Type = [IntType] int
|
||||
# 1539| ValueCategory = prvalue
|
||||
# 1539| getExpr(): [FieldAccess] i
|
||||
# 1539| getExpr(): [ReferenceFieldAccess] i
|
||||
# 1539| Type = [IntType] int
|
||||
# 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(): [FieldAccess] d
|
||||
# 1539| getExpr(): [ReferenceFieldAccess] d
|
||||
# 1539| Type = [DoubleType] double
|
||||
# 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(): [FieldAccess] r
|
||||
# 1539| getExpr(): [ReferenceFieldAccess] r
|
||||
# 1539| Type = [LValueReferenceType] int &
|
||||
# 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&&)
|
||||
@@ -12981,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)
|
||||
@@ -12996,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)
|
||||
@@ -13030,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)
|
||||
@@ -13091,6 +13139,426 @@ ir.cpp:
|
||||
# 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
|
||||
|
||||
@@ -1696,4 +1696,62 @@ int goto_on_same_line() {
|
||||
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
|
||||
|
||||
@@ -47,29 +47,31 @@
|
||||
| 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_12 |
|
||||
| bad_asts.cpp:19:10:19:10 | Address | &:r19_16 |
|
||||
| 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_19 |
|
||||
| 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_14 |
|
||||
| bad_asts.cpp:19:10:19:10 | ChiPartial | partial:m19_21 |
|
||||
| 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_15 |
|
||||
| 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_22 |
|
||||
| bad_asts.cpp:19:10:19:10 | StoreValue | r19_13 |
|
||||
| bad_asts.cpp:19:10:19:10 | StoreValue | r19_20 |
|
||||
| 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_18 |
|
||||
| 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 |
|
||||
@@ -668,6 +670,10 @@
|
||||
| file://:0:0:0:0 | Address | &:r0_1 |
|
||||
| file://:0:0:0:0 | Address | &:r0_1 |
|
||||
| file://:0:0:0:0 | Address | &:r0_1 |
|
||||
| file://:0:0:0:0 | Address | &:r0_1 |
|
||||
| file://:0:0:0:0 | Address | &:r0_1 |
|
||||
| file://:0:0:0:0 | Address | &:r0_1 |
|
||||
| file://:0:0:0:0 | Address | &:r0_1 |
|
||||
| file://:0:0:0:0 | Address | &:r0_2 |
|
||||
| file://:0:0:0:0 | Address | &:r0_3 |
|
||||
| file://:0:0:0:0 | Address | &:r0_3 |
|
||||
@@ -684,6 +690,10 @@
|
||||
| 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 |
|
||||
@@ -716,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 |
|
||||
@@ -736,12 +754,18 @@
|
||||
| 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 |
|
||||
@@ -753,6 +777,8 @@
|
||||
| file://:0:0:0:0 | SideEffect | m0_4 |
|
||||
| file://:0:0:0:0 | SideEffect | m0_4 |
|
||||
| file://:0:0:0:0 | SideEffect | m0_4 |
|
||||
| file://:0:0:0:0 | SideEffect | m0_4 |
|
||||
| file://:0:0:0:0 | SideEffect | m0_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 |
|
||||
@@ -776,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 |
|
||||
@@ -6824,48 +6854,48 @@
|
||||
| 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_12 |
|
||||
| ir.cpp:1486:8:1486:8 | Address | &:r1486_16 |
|
||||
| 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_19 |
|
||||
| ir.cpp:1486:8:1486:8 | Address | &:r1486_23 |
|
||||
| ir.cpp:1486:8:1486:8 | Address | &:r1486_24 |
|
||||
| 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_30 |
|
||||
| ir.cpp:1486:8:1486:8 | Address | &:r1486_31 |
|
||||
| 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_38 |
|
||||
| ir.cpp:1486:8:1486:8 | Address | &:r1486_40 |
|
||||
| ir.cpp:1486:8:1486:8 | Address | &:r1486_44 |
|
||||
| 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_47 |
|
||||
| ir.cpp:1486:8:1486:8 | Address | &:r1486_51 |
|
||||
| ir.cpp:1486:8:1486:8 | Address | &:r1486_52 |
|
||||
| ir.cpp:1486:8:1486:8 | Address | &:r1486_54 |
|
||||
| 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_59 |
|
||||
| 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_14 |
|
||||
| ir.cpp:1486:8:1486:8 | ChiPartial | partial:m1486_21 |
|
||||
| ir.cpp:1486:8:1486:8 | ChiPartial | partial:m1486_28 |
|
||||
| ir.cpp:1486:8:1486:8 | ChiPartial | partial:m1486_35 |
|
||||
| ir.cpp:1486:8:1486:8 | ChiPartial | partial:m1486_42 |
|
||||
| ir.cpp:1486:8:1486:8 | ChiPartial | partial:m1486_49 |
|
||||
| ir.cpp:1486:8:1486:8 | ChiPartial | partial:m1486_56 |
|
||||
| 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_15 |
|
||||
| ir.cpp:1486:8:1486:8 | ChiTotal | total:m1486_22 |
|
||||
| ir.cpp:1486:8:1486:8 | ChiTotal | total:m1486_29 |
|
||||
| ir.cpp:1486:8:1486:8 | ChiTotal | total:m1486_36 |
|
||||
| ir.cpp:1486:8:1486:8 | ChiTotal | total:m1486_43 |
|
||||
| ir.cpp:1486:8:1486:8 | ChiTotal | total:m1486_50 |
|
||||
| ir.cpp:1486:8:1486:8 | ChiTotal | total:m1486_57 |
|
||||
| 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 |
|
||||
@@ -6887,15 +6917,15 @@
|
||||
| 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_64 |
|
||||
| ir.cpp:1486:8:1486:8 | StoreValue | r1486_13 |
|
||||
| ir.cpp:1486:8:1486:8 | StoreValue | r1486_20 |
|
||||
| ir.cpp:1486:8:1486:8 | StoreValue | r1486_27 |
|
||||
| ir.cpp:1486:8:1486:8 | StoreValue | r1486_34 |
|
||||
| ir.cpp:1486:8:1486:8 | StoreValue | r1486_41 |
|
||||
| ir.cpp:1486:8:1486:8 | StoreValue | r1486_48 |
|
||||
| ir.cpp:1486:8:1486:8 | StoreValue | r1486_55 |
|
||||
| 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 |
|
||||
@@ -6905,13 +6935,21 @@
|
||||
| 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_18 |
|
||||
| ir.cpp:1486:8:1486:8 | Unary | r1486_25 |
|
||||
| ir.cpp:1486:8:1486:8 | Unary | r1486_32 |
|
||||
| ir.cpp:1486:8:1486:8 | Unary | r1486_39 |
|
||||
| ir.cpp:1486:8:1486:8 | Unary | r1486_46 |
|
||||
| ir.cpp:1486:8:1486:8 | Unary | r1486_53 |
|
||||
| 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 |
|
||||
@@ -7092,23 +7130,23 @@
|
||||
| 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_12 |
|
||||
| ir.cpp:1539:8:1539:8 | Address | &:r1539_16 |
|
||||
| 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_19 |
|
||||
| ir.cpp:1539:8:1539:8 | Address | &:r1539_23 |
|
||||
| ir.cpp:1539:8:1539:8 | Address | &:r1539_24 |
|
||||
| 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_14 |
|
||||
| ir.cpp:1539:8:1539:8 | ChiPartial | partial:m1539_21 |
|
||||
| ir.cpp:1539:8:1539:8 | ChiPartial | partial:m1539_28 |
|
||||
| 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_15 |
|
||||
| ir.cpp:1539:8:1539:8 | ChiTotal | total:m1539_22 |
|
||||
| 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 |
|
||||
@@ -7120,16 +7158,19 @@
|
||||
| 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_29 |
|
||||
| ir.cpp:1539:8:1539:8 | StoreValue | r1539_13 |
|
||||
| ir.cpp:1539:8:1539:8 | StoreValue | r1539_20 |
|
||||
| ir.cpp:1539:8:1539:8 | StoreValue | r1539_27 |
|
||||
| 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_18 |
|
||||
| ir.cpp:1539:8:1539:8 | Unary | r1539_25 |
|
||||
| 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 |
|
||||
@@ -7652,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 |
|
||||
@@ -7683,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 |
|
||||
@@ -7702,6 +7836,14 @@
|
||||
| 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 |
|
||||
@@ -7713,6 +7855,366 @@
|
||||
| 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
|
||||
|
||||
@@ -65,21 +65,23 @@ bad_asts.cpp:
|
||||
# 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<int>) = FieldAddress[x] : r19_10
|
||||
# 19| r19_12(int) = Load[?] : &:r19_11, ~m?
|
||||
# 19| mu19_13(int) = Store[?] : &:r19_8, r19_12
|
||||
# 19| r19_14(glval<int>) = FieldAddress[y] : mu19_5
|
||||
# 19| r19_15(glval<Point &>) = VariableAddress[(unnamed parameter 0)] :
|
||||
# 19| r19_16(Point &) = Load[(unnamed parameter 0)] : &:r19_15, ~m?
|
||||
# 19| r19_17(glval<int>) = FieldAddress[y] : r19_16
|
||||
# 19| r19_18(int) = Load[?] : &:r19_17, ~m?
|
||||
# 19| mu19_19(int) = Store[?] : &:r19_14, r19_18
|
||||
# 19| v19_20(void) = NoOp :
|
||||
# 19| v19_21(void) = ReturnIndirection[#this] : &:r19_6, ~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_22(void) = ReturnVoid :
|
||||
# 19| v19_23(void) = AliasedUse : ~m?
|
||||
# 19| v19_24(void) = ExitFunction :
|
||||
# 19| v19_24(void) = ReturnVoid :
|
||||
# 19| v19_25(void) = AliasedUse : ~m?
|
||||
# 19| v19_26(void) = ExitFunction :
|
||||
|
||||
# 22| void Bad::Point::Point()
|
||||
# 22| Block 0
|
||||
@@ -8077,57 +8079,65 @@ ir.cpp:
|
||||
# 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<int>) = FieldAddress[i] : r1486_10
|
||||
# 1486| r1486_12(int) = Load[?] : &:r1486_11, ~m?
|
||||
# 1486| mu1486_13(int) = Store[?] : &:r1486_8, r1486_12
|
||||
# 1486| r1486_14(glval<double>) = FieldAddress[d] : mu1486_5
|
||||
# 1486| r1486_15(glval<StructuredBindingDataMemberStruct &>) = VariableAddress[(unnamed parameter 0)] :
|
||||
# 1486| r1486_16(StructuredBindingDataMemberStruct &) = Load[(unnamed parameter 0)] : &:r1486_15, ~m?
|
||||
# 1486| r1486_17(glval<double>) = FieldAddress[d] : r1486_16
|
||||
# 1486| r1486_18(double) = Load[?] : &:r1486_17, ~m?
|
||||
# 1486| mu1486_19(double) = Store[?] : &:r1486_14, r1486_18
|
||||
# 1486| r1486_20(glval<unsigned int>) = FieldAddress[b] : mu1486_5
|
||||
# 1486| r1486_21(glval<StructuredBindingDataMemberStruct &>) = VariableAddress[(unnamed parameter 0)] :
|
||||
# 1486| r1486_22(StructuredBindingDataMemberStruct &) = Load[(unnamed parameter 0)] : &:r1486_21, ~m?
|
||||
# 1486| r1486_23(glval<unsigned int>) = FieldAddress[b] : r1486_22
|
||||
# 1486| r1486_24(unsigned int) = Load[?] : &:r1486_23, ~m?
|
||||
# 1486| mu1486_25(unsigned int) = Store[?] : &:r1486_20, r1486_24
|
||||
# 1486| r1486_26(glval<int &>) = FieldAddress[r] : mu1486_5
|
||||
# 1486| r1486_27(glval<StructuredBindingDataMemberStruct &>) = VariableAddress[(unnamed parameter 0)] :
|
||||
# 1486| r1486_28(StructuredBindingDataMemberStruct &) = Load[(unnamed parameter 0)] : &:r1486_27, ~m?
|
||||
# 1486| r1486_29(glval<int &>) = FieldAddress[r] : r1486_28
|
||||
# 1486| r1486_30(int &) = Load[?] : &:r1486_29, ~m?
|
||||
# 1486| mu1486_31(int &) = Store[?] : &:r1486_26, r1486_30
|
||||
# 1486| r1486_32(glval<int *>) = FieldAddress[p] : mu1486_5
|
||||
# 1486| r1486_33(glval<StructuredBindingDataMemberStruct &>) = VariableAddress[(unnamed parameter 0)] :
|
||||
# 1486| r1486_34(StructuredBindingDataMemberStruct &) = Load[(unnamed parameter 0)] : &:r1486_33, ~m?
|
||||
# 1486| r1486_35(glval<int *>) = FieldAddress[p] : r1486_34
|
||||
# 1486| r1486_36(int *) = Load[?] : &:r1486_35, ~m?
|
||||
# 1486| mu1486_37(int *) = Store[?] : &:r1486_32, r1486_36
|
||||
# 1486| r1486_38(glval<int[2]>) = FieldAddress[xs] : mu1486_5
|
||||
# 1486| r1486_39(glval<StructuredBindingDataMemberStruct &>) = VariableAddress[(unnamed parameter 0)] :
|
||||
# 1486| r1486_40(StructuredBindingDataMemberStruct &) = Load[(unnamed parameter 0)] : &:r1486_39, ~m?
|
||||
# 1486| r1486_41(glval<int[2]>) = FieldAddress[xs] : r1486_40
|
||||
# 1486| r1486_42(int[2]) = Load[?] : &:r1486_41, ~m?
|
||||
# 1486| mu1486_43(int[2]) = Store[?] : &:r1486_38, r1486_42
|
||||
# 1486| r1486_44(glval<int &>) = FieldAddress[r_alt] : mu1486_5
|
||||
# 1486| r1486_45(glval<StructuredBindingDataMemberStruct &>) = VariableAddress[(unnamed parameter 0)] :
|
||||
# 1486| r1486_46(StructuredBindingDataMemberStruct &) = Load[(unnamed parameter 0)] : &:r1486_45, ~m?
|
||||
# 1486| r1486_47(glval<int &>) = FieldAddress[r_alt] : r1486_46
|
||||
# 1486| r1486_48(int &) = Load[?] : &:r1486_47, ~m?
|
||||
# 1486| mu1486_49(int &) = Store[?] : &:r1486_44, r1486_48
|
||||
# 1486| r1486_50(glval<StructuredBindingDataMemberMemberStruct>) = FieldAddress[m] : mu1486_5
|
||||
# 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<StructuredBindingDataMemberMemberStruct>) = FieldAddress[m] : r1486_52
|
||||
# 1486| r1486_54(StructuredBindingDataMemberMemberStruct) = Load[?] : &:r1486_53, ~m?
|
||||
# 1486| mu1486_55(StructuredBindingDataMemberMemberStruct) = Store[?] : &:r1486_50, r1486_54
|
||||
# 1486| v1486_56(void) = NoOp :
|
||||
# 1486| v1486_57(void) = ReturnIndirection[#this] : &:r1486_6, ~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_58(void) = ReturnVoid :
|
||||
# 1486| v1486_59(void) = AliasedUse : ~m?
|
||||
# 1486| v1486_60(void) = ExitFunction :
|
||||
# 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
|
||||
@@ -8325,27 +8335,30 @@ ir.cpp:
|
||||
# 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<int>) = FieldAddress[i] : r1539_10
|
||||
# 1539| r1539_12(int) = Load[?] : &:r1539_11, ~m?
|
||||
# 1539| mu1539_13(int) = Store[?] : &:r1539_8, r1539_12
|
||||
# 1539| r1539_14(glval<double>) = FieldAddress[d] : mu1539_5
|
||||
# 1539| r1539_15(glval<StructuredBindingTupleRefGet &>) = VariableAddress[(unnamed parameter 0)] :
|
||||
# 1539| r1539_16(StructuredBindingTupleRefGet &) = Load[(unnamed parameter 0)] : &:r1539_15, ~m?
|
||||
# 1539| r1539_17(glval<double>) = FieldAddress[d] : r1539_16
|
||||
# 1539| r1539_18(double) = Load[?] : &:r1539_17, ~m?
|
||||
# 1539| mu1539_19(double) = Store[?] : &:r1539_14, r1539_18
|
||||
# 1539| r1539_20(glval<int &>) = FieldAddress[r] : mu1539_5
|
||||
# 1539| r1539_21(glval<StructuredBindingTupleRefGet &>) = VariableAddress[(unnamed parameter 0)] :
|
||||
# 1539| r1539_22(StructuredBindingTupleRefGet &) = Load[(unnamed parameter 0)] : &:r1539_21, ~m?
|
||||
# 1539| r1539_23(glval<int &>) = FieldAddress[r] : r1539_22
|
||||
# 1539| r1539_24(int &) = Load[?] : &:r1539_23, ~m?
|
||||
# 1539| mu1539_25(int &) = Store[?] : &:r1539_20, r1539_24
|
||||
# 1539| v1539_26(void) = NoOp :
|
||||
# 1539| v1539_27(void) = ReturnIndirection[#this] : &:r1539_6, ~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_28(void) = ReturnVoid :
|
||||
# 1539| v1539_29(void) = AliasedUse : ~m?
|
||||
# 1539| v1539_30(void) = ExitFunction :
|
||||
# 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
|
||||
@@ -8888,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
|
||||
@@ -8999,6 +9017,407 @@ ir.cpp:
|
||||
# 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,6 +122,8 @@
|
||||
| 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) |
|
||||
@@ -184,6 +186,7 @@
|
||||
| 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) |
|
||||
|
||||
@@ -123,3 +123,4 @@ postWithInFlow
|
||||
| misc.c:220:4:220:5 | sp [inner post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| static_init_templates.cpp:3:2:3:4 | ref [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| static_init_templates.cpp:21:2:21:4 | val [post update] | PostUpdateNode should not be the target of local flow. |
|
||||
| try_catch.cpp:7:8:7:8 | call to exception | PostUpdateNode should not be the target of local flow. |
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// semmle-extractor-options: --edg --trap_container=folder --edg --trap-compression=none
|
||||
|
||||
template <int i>
|
||||
int addToSelf() { return i + i; };
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// semmle-extractor-options: --edg --trap_container=folder --edg --trap-compression=none
|
||||
|
||||
template<int x>
|
||||
struct C { };
|
||||
|
||||
|
||||
@@ -163,3 +163,16 @@ void test_captured_contructor()
|
||||
|
||||
myFunction2( [obj](){} );
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
void test_switch_initializer()
|
||||
{
|
||||
bool a = 42, b = 43; // GOOD: a, b are both used
|
||||
|
||||
switch (a = b; a)
|
||||
{
|
||||
default:
|
||||
// ...
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ edges
|
||||
nodes
|
||||
| test2.cpp:43:36:43:43 | password | semmle.label | password |
|
||||
| test2.cpp:44:37:44:45 | thepasswd | semmle.label | thepasswd |
|
||||
| test2.cpp:45:38:45:47 | accountkey | semmle.label | accountkey |
|
||||
| test2.cpp:50:41:50:53 | passwd_config | semmle.label | passwd_config |
|
||||
| test2.cpp:52:40:52:58 | * ... | semmle.label | * ... |
|
||||
| test2.cpp:52:44:52:57 | password_tries | semmle.label | password_tries |
|
||||
@@ -29,6 +30,7 @@ subpaths
|
||||
#select
|
||||
| test2.cpp:43:2:43:8 | call to fprintf | test2.cpp:43:36:43:43 | password | test2.cpp:43:36:43:43 | password | This write into file 'log' may contain unencrypted data from $@ | test2.cpp:43:36:43:43 | password | this source. |
|
||||
| test2.cpp:44:2:44:8 | call to fprintf | test2.cpp:44:37:44:45 | thepasswd | test2.cpp:44:37:44:45 | thepasswd | This write into file 'log' may contain unencrypted data from $@ | test2.cpp:44:37:44:45 | thepasswd | this source. |
|
||||
| test2.cpp:45:2:45:8 | call to fprintf | test2.cpp:45:38:45:47 | accountkey | test2.cpp:45:38:45:47 | accountkey | This write into file 'log' may contain unencrypted data from $@ | test2.cpp:45:38:45:47 | accountkey | this source. |
|
||||
| test2.cpp:50:2:50:8 | call to fprintf | test2.cpp:50:41:50:53 | passwd_config | test2.cpp:50:41:50:53 | passwd_config | This write into file 'log' may contain unencrypted data from $@ | test2.cpp:50:41:50:53 | passwd_config | this source. |
|
||||
| test2.cpp:54:2:54:8 | call to fprintf | test2.cpp:54:41:54:52 | widepassword | test2.cpp:54:41:54:52 | widepassword | This write into file 'log' may contain unencrypted data from $@ | test2.cpp:54:41:54:52 | widepassword | this source. |
|
||||
| test2.cpp:55:2:55:8 | call to fprintf | test2.cpp:55:40:55:51 | widepassword | test2.cpp:55:40:55:51 | widepassword | This write into file 'log' may contain unencrypted data from $@ | test2.cpp:55:40:55:51 | widepassword | this source. |
|
||||
|
||||
@@ -92,6 +92,12 @@ edges
|
||||
| test3.cpp:398:18:398:25 | password | test3.cpp:400:33:400:40 | password |
|
||||
| test3.cpp:421:21:421:28 | password | test3.cpp:421:3:421:17 | call to decrypt_inplace |
|
||||
| test3.cpp:429:7:429:14 | password | test3.cpp:431:8:431:15 | password |
|
||||
| test3.cpp:526:44:526:54 | my_latitude | test3.cpp:527:15:527:20 | buffer |
|
||||
| test3.cpp:532:45:532:58 | home_longitude | test3.cpp:533:15:533:20 | buffer |
|
||||
| test3.cpp:551:47:551:58 | salaryString | test3.cpp:552:15:552:20 | buffer |
|
||||
| test3.cpp:556:19:556:30 | salaryString | test3.cpp:559:15:559:20 | buffer |
|
||||
| test3.cpp:571:8:571:21 | call to get_home_phone | test3.cpp:572:14:572:16 | str |
|
||||
| test3.cpp:577:8:577:23 | call to get_home_address | test3.cpp:578:14:578:16 | str |
|
||||
| test.cpp:41:23:41:43 | cleartext password! | test.cpp:48:21:48:27 | call to encrypt |
|
||||
| test.cpp:41:23:41:43 | cleartext password! | test.cpp:48:29:48:39 | thePassword |
|
||||
| test.cpp:66:23:66:43 | cleartext password! | test.cpp:76:21:76:27 | call to encrypt |
|
||||
@@ -221,6 +227,30 @@ nodes
|
||||
| test3.cpp:421:21:421:28 | password | semmle.label | password |
|
||||
| test3.cpp:429:7:429:14 | password | semmle.label | password |
|
||||
| test3.cpp:431:8:431:15 | password | semmle.label | password |
|
||||
| test3.cpp:507:18:507:39 | social_security_number | semmle.label | social_security_number |
|
||||
| test3.cpp:508:18:508:33 | socialSecurityNo | semmle.label | socialSecurityNo |
|
||||
| test3.cpp:509:18:509:29 | homePostCode | semmle.label | homePostCode |
|
||||
| test3.cpp:510:18:510:28 | my_zip_code | semmle.label | my_zip_code |
|
||||
| test3.cpp:511:18:511:26 | telephone | semmle.label | telephone |
|
||||
| test3.cpp:512:18:512:36 | mobile_phone_number | semmle.label | mobile_phone_number |
|
||||
| test3.cpp:513:18:513:22 | email | semmle.label | email |
|
||||
| test3.cpp:514:18:514:38 | my_credit_card_number | semmle.label | my_credit_card_number |
|
||||
| test3.cpp:515:18:515:35 | my_bank_account_no | semmle.label | my_bank_account_no |
|
||||
| test3.cpp:516:18:516:29 | employerName | semmle.label | employerName |
|
||||
| test3.cpp:517:18:517:29 | medical_info | semmle.label | medical_info |
|
||||
| test3.cpp:518:18:518:28 | license_key | semmle.label | license_key |
|
||||
| test3.cpp:526:44:526:54 | my_latitude | semmle.label | my_latitude |
|
||||
| test3.cpp:527:15:527:20 | buffer | semmle.label | buffer |
|
||||
| test3.cpp:532:45:532:58 | home_longitude | semmle.label | home_longitude |
|
||||
| test3.cpp:533:15:533:20 | buffer | semmle.label | buffer |
|
||||
| test3.cpp:551:47:551:58 | salaryString | semmle.label | salaryString |
|
||||
| test3.cpp:552:15:552:20 | buffer | semmle.label | buffer |
|
||||
| test3.cpp:556:19:556:30 | salaryString | semmle.label | salaryString |
|
||||
| test3.cpp:559:15:559:20 | buffer | semmle.label | buffer |
|
||||
| test3.cpp:571:8:571:21 | call to get_home_phone | semmle.label | call to get_home_phone |
|
||||
| test3.cpp:572:14:572:16 | str | semmle.label | str |
|
||||
| test3.cpp:577:8:577:23 | call to get_home_address | semmle.label | call to get_home_address |
|
||||
| test3.cpp:578:14:578:16 | str | semmle.label | str |
|
||||
| test.cpp:41:23:41:43 | cleartext password! | semmle.label | cleartext password! |
|
||||
| test.cpp:48:21:48:27 | call to encrypt | semmle.label | call to encrypt |
|
||||
| test.cpp:48:29:48:39 | thePassword | semmle.label | thePassword |
|
||||
@@ -254,3 +284,21 @@ subpaths
|
||||
| test3.cpp:414:3:414:6 | call to recv | test3.cpp:414:17:414:24 | password | test3.cpp:414:17:414:24 | password | This operation receives into 'password', which may put unencrypted sensitive data into $@ | test3.cpp:414:17:414:24 | password | password |
|
||||
| test3.cpp:420:3:420:6 | call to recv | test3.cpp:420:17:420:24 | password | test3.cpp:420:17:420:24 | password | This operation receives into 'password', which may put unencrypted sensitive data into $@ | test3.cpp:420:17:420:24 | password | password |
|
||||
| test3.cpp:431:2:431:6 | call to fgets | test3.cpp:429:7:429:14 | password | test3.cpp:431:8:431:15 | password | This operation receives into 'password', which may put unencrypted sensitive data into $@ | test3.cpp:429:7:429:14 | password | password |
|
||||
| test3.cpp:507:2:507:5 | call to send | test3.cpp:507:18:507:39 | social_security_number | test3.cpp:507:18:507:39 | social_security_number | This operation transmits 'social_security_number', which may contain unencrypted sensitive data from $@ | test3.cpp:507:18:507:39 | social_security_number | social_security_number |
|
||||
| test3.cpp:508:2:508:5 | call to send | test3.cpp:508:18:508:33 | socialSecurityNo | test3.cpp:508:18:508:33 | socialSecurityNo | This operation transmits 'socialSecurityNo', which may contain unencrypted sensitive data from $@ | test3.cpp:508:18:508:33 | socialSecurityNo | socialSecurityNo |
|
||||
| test3.cpp:509:2:509:5 | call to send | test3.cpp:509:18:509:29 | homePostCode | test3.cpp:509:18:509:29 | homePostCode | This operation transmits 'homePostCode', which may contain unencrypted sensitive data from $@ | test3.cpp:509:18:509:29 | homePostCode | homePostCode |
|
||||
| test3.cpp:510:2:510:5 | call to send | test3.cpp:510:18:510:28 | my_zip_code | test3.cpp:510:18:510:28 | my_zip_code | This operation transmits 'my_zip_code', which may contain unencrypted sensitive data from $@ | test3.cpp:510:18:510:28 | my_zip_code | my_zip_code |
|
||||
| test3.cpp:511:2:511:5 | call to send | test3.cpp:511:18:511:26 | telephone | test3.cpp:511:18:511:26 | telephone | This operation transmits 'telephone', which may contain unencrypted sensitive data from $@ | test3.cpp:511:18:511:26 | telephone | telephone |
|
||||
| test3.cpp:512:2:512:5 | call to send | test3.cpp:512:18:512:36 | mobile_phone_number | test3.cpp:512:18:512:36 | mobile_phone_number | This operation transmits 'mobile_phone_number', which may contain unencrypted sensitive data from $@ | test3.cpp:512:18:512:36 | mobile_phone_number | mobile_phone_number |
|
||||
| test3.cpp:513:2:513:5 | call to send | test3.cpp:513:18:513:22 | email | test3.cpp:513:18:513:22 | email | This operation transmits 'email', which may contain unencrypted sensitive data from $@ | test3.cpp:513:18:513:22 | email | email |
|
||||
| test3.cpp:514:2:514:5 | call to send | test3.cpp:514:18:514:38 | my_credit_card_number | test3.cpp:514:18:514:38 | my_credit_card_number | This operation transmits 'my_credit_card_number', which may contain unencrypted sensitive data from $@ | test3.cpp:514:18:514:38 | my_credit_card_number | my_credit_card_number |
|
||||
| test3.cpp:515:2:515:5 | call to send | test3.cpp:515:18:515:35 | my_bank_account_no | test3.cpp:515:18:515:35 | my_bank_account_no | This operation transmits 'my_bank_account_no', which may contain unencrypted sensitive data from $@ | test3.cpp:515:18:515:35 | my_bank_account_no | my_bank_account_no |
|
||||
| test3.cpp:516:2:516:5 | call to send | test3.cpp:516:18:516:29 | employerName | test3.cpp:516:18:516:29 | employerName | This operation transmits 'employerName', which may contain unencrypted sensitive data from $@ | test3.cpp:516:18:516:29 | employerName | employerName |
|
||||
| test3.cpp:517:2:517:5 | call to send | test3.cpp:517:18:517:29 | medical_info | test3.cpp:517:18:517:29 | medical_info | This operation transmits 'medical_info', which may contain unencrypted sensitive data from $@ | test3.cpp:517:18:517:29 | medical_info | medical_info |
|
||||
| test3.cpp:518:2:518:5 | call to send | test3.cpp:518:18:518:28 | license_key | test3.cpp:518:18:518:28 | license_key | This operation transmits 'license_key', which may contain unencrypted sensitive data from $@ | test3.cpp:518:18:518:28 | license_key | license_key |
|
||||
| test3.cpp:527:3:527:6 | call to send | test3.cpp:526:44:526:54 | my_latitude | test3.cpp:527:15:527:20 | buffer | This operation transmits 'buffer', which may contain unencrypted sensitive data from $@ | test3.cpp:526:44:526:54 | my_latitude | my_latitude |
|
||||
| test3.cpp:533:3:533:6 | call to send | test3.cpp:532:45:532:58 | home_longitude | test3.cpp:533:15:533:20 | buffer | This operation transmits 'buffer', which may contain unencrypted sensitive data from $@ | test3.cpp:532:45:532:58 | home_longitude | home_longitude |
|
||||
| test3.cpp:552:3:552:6 | call to send | test3.cpp:551:47:551:58 | salaryString | test3.cpp:552:15:552:20 | buffer | This operation transmits 'buffer', which may contain unencrypted sensitive data from $@ | test3.cpp:551:47:551:58 | salaryString | salaryString |
|
||||
| test3.cpp:559:3:559:6 | call to send | test3.cpp:556:19:556:30 | salaryString | test3.cpp:559:15:559:20 | buffer | This operation transmits 'buffer', which may contain unencrypted sensitive data from $@ | test3.cpp:556:19:556:30 | salaryString | salaryString |
|
||||
| test3.cpp:572:2:572:5 | call to send | test3.cpp:571:8:571:21 | call to get_home_phone | test3.cpp:572:14:572:16 | str | This operation transmits 'str', which may contain unencrypted sensitive data from $@ | test3.cpp:571:8:571:21 | call to get_home_phone | call to get_home_phone |
|
||||
| test3.cpp:578:2:578:5 | call to send | test3.cpp:577:8:577:23 | call to get_home_address | test3.cpp:578:14:578:16 | str | This operation transmits 'str', which may contain unencrypted sensitive data from $@ | test3.cpp:577:8:577:23 | call to get_home_address | call to get_home_address |
|
||||
|
||||
@@ -42,7 +42,7 @@ void tests(FILE *log, myStruct &s)
|
||||
{
|
||||
fprintf(log, "password = %s\n", s.password); // BAD
|
||||
fprintf(log, "thepasswd = %s\n", s.thepasswd); // BAD
|
||||
fprintf(log, "accountkey = %s\n", s.accountkey); // DUBIOUS [NOT REPORTED]
|
||||
fprintf(log, "accountkey = %s\n", s.accountkey); // BAD
|
||||
fprintf(log, "password_hash = %s\n", s.password_hash); // GOOD
|
||||
fprintf(log, "encrypted_passwd = %s\n", s.encrypted_passwd); // GOOD
|
||||
fprintf(log, "password_file = %s\n", s.password_file); // GOOD
|
||||
@@ -109,4 +109,4 @@ void test_gets()
|
||||
|
||||
gets(password); // BAD
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user