mirror of
https://github.com/github/codeql.git
synced 2026-05-26 17:11:24 +02:00
Compare commits
270 Commits
calumgrant
...
criemen/re
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
205209c324 | ||
|
|
5d5e31378b | ||
|
|
5cde3fa697 | ||
|
|
eb0621ab7a | ||
|
|
c0cf1c7c8c | ||
|
|
d5475c4a89 | ||
|
|
7ca54a6f94 | ||
|
|
e8cb8b4f81 | ||
|
|
ba64cf3016 | ||
|
|
807e6795a7 | ||
|
|
880262d462 | ||
|
|
95ff5bae65 | ||
|
|
6cbe16e0c2 | ||
|
|
75615f2817 | ||
|
|
c07bf65eb6 | ||
|
|
8def1c2c13 | ||
|
|
1b90f22e84 | ||
|
|
ecdf62376d | ||
|
|
96d69ca49c | ||
|
|
daea674095 | ||
|
|
315f439135 | ||
|
|
e4cf7df38f | ||
|
|
b8b3689251 | ||
|
|
0693bf9e75 | ||
|
|
ccad70897d | ||
|
|
3239af9973 | ||
|
|
f7113e0105 | ||
|
|
2cff081f2b | ||
|
|
f99cb3f649 | ||
|
|
dfdd79d8cf | ||
|
|
b912918d8b | ||
|
|
ef88f3ed09 | ||
|
|
d909f2bc4f | ||
|
|
9bfb189fa7 | ||
|
|
322fa36359 | ||
|
|
4a47e11a16 | ||
|
|
83249cd9c2 | ||
|
|
c6185b30ba | ||
|
|
9ce08c586c | ||
|
|
7d92ec5ddf | ||
|
|
9157dee0db | ||
|
|
677520aa8e | ||
|
|
16dcc0969b | ||
|
|
09e59ccf44 | ||
|
|
a8f2cbc2b1 | ||
|
|
c00d0d302d | ||
|
|
5a7a1dc92e | ||
|
|
c480431ec0 | ||
|
|
f7fc2e0b00 | ||
|
|
397e641f2f | ||
|
|
00cbfaf40e | ||
|
|
dc4604f5a5 | ||
|
|
40b6e1624f | ||
|
|
22e843abc6 | ||
|
|
3c70a2d7df | ||
|
|
541effb8cb | ||
|
|
248ffa15a2 | ||
|
|
5843326b5c | ||
|
|
3a2b0a2feb | ||
|
|
07dd6d5c8d | ||
|
|
708d12624f | ||
|
|
3eddd3114f | ||
|
|
61ce7252e6 | ||
|
|
b86aeb68ae | ||
|
|
cf025e1924 | ||
|
|
a200ced2d6 | ||
|
|
c04e59611b | ||
|
|
c5a87c95d8 | ||
|
|
797f675285 | ||
|
|
c32c810ae7 | ||
|
|
32fe084630 | ||
|
|
0715c4ac5a | ||
|
|
99928b82ed | ||
|
|
377c6b4cc8 | ||
|
|
2939c89f7a | ||
|
|
bb6cc92728 | ||
|
|
d736426529 | ||
|
|
806d42852c | ||
|
|
8e251ee54f | ||
|
|
5228d94d42 | ||
|
|
7d9f78b2de | ||
|
|
7e839792da | ||
|
|
98106f31c1 | ||
|
|
676bcf39a5 | ||
|
|
a28f87fff0 | ||
|
|
94364f724e | ||
|
|
607ed2efb4 | ||
|
|
a304e2d8d6 | ||
|
|
1c611fecde | ||
|
|
51bc8e917e | ||
|
|
0fa5a1f274 | ||
|
|
5c454bdd8c | ||
|
|
f194c70e8a | ||
|
|
179270ffc1 | ||
|
|
8ccedd658a | ||
|
|
401717d739 | ||
|
|
527409d05f | ||
|
|
d3d2e2188d | ||
|
|
141af7cc87 | ||
|
|
6e3dddede0 | ||
|
|
683fe26034 | ||
|
|
ea1b8a3999 | ||
|
|
5f0efc19fa | ||
|
|
d62e888b86 | ||
|
|
50775d0c53 | ||
|
|
9874d40d29 | ||
|
|
044ee9b08a | ||
|
|
8b23f6db10 | ||
|
|
3c2206728d | ||
|
|
8c87cb83bb | ||
|
|
c9ce642e7a | ||
|
|
d18cdee0bc | ||
|
|
b78537dd74 | ||
|
|
e78091e9d0 | ||
|
|
c10e00d389 | ||
|
|
bf61114284 | ||
|
|
800d7546fa | ||
|
|
d6c57de650 | ||
|
|
6147a38bea | ||
|
|
67fb866efa | ||
|
|
4b0a217420 | ||
|
|
3195f0c828 | ||
|
|
a707e14495 | ||
|
|
1d45e3a558 | ||
|
|
70e9c48a47 | ||
|
|
dcc4ad2550 | ||
|
|
54cadcfe9b | ||
|
|
3716b8c6a0 | ||
|
|
9f7edf378e | ||
|
|
4f46ce1133 | ||
|
|
f95b33049e | ||
|
|
2482519cd3 | ||
|
|
e44d4c45aa | ||
|
|
14d88eb3ce | ||
|
|
b754706e44 | ||
|
|
9db32f4d26 | ||
|
|
acb2bbb2a3 | ||
|
|
06f987ad58 | ||
|
|
0468c5d0bf | ||
|
|
e55f2c5309 | ||
|
|
d7c784ef2f | ||
|
|
fb376a1cfd | ||
|
|
baa31e1469 | ||
|
|
8d962a5c28 | ||
|
|
389df35fb7 | ||
|
|
aa80dd41da | ||
|
|
553871678a | ||
|
|
15123a7b40 | ||
|
|
bbd80ec7a4 | ||
|
|
1d421b3b28 | ||
|
|
a87b991d78 | ||
|
|
0fb71e24cb | ||
|
|
14d04903dc | ||
|
|
181a063bb9 | ||
|
|
131d0b911f | ||
|
|
0124b0749f | ||
|
|
6daf80cdd0 | ||
|
|
9c139b591f | ||
|
|
b8cfff6d19 | ||
|
|
f33d7ee80d | ||
|
|
15a6308c72 | ||
|
|
dd9183c345 | ||
|
|
d0c9e3f7ad | ||
|
|
9082972842 | ||
|
|
05819a52ef | ||
|
|
116873c9b0 | ||
|
|
290b0fc4ab | ||
|
|
332d118d93 | ||
|
|
82bbecc9c4 | ||
|
|
15c1fd9425 | ||
|
|
13ff9412a4 | ||
|
|
9d24b5afa6 | ||
|
|
95ec4e8d26 | ||
|
|
17e0cc5648 | ||
|
|
196b6d7a1d | ||
|
|
9def57250d | ||
|
|
9af9873e04 | ||
|
|
9f5782b67b | ||
|
|
c61177cf42 | ||
|
|
4140942479 | ||
|
|
fd306ed79b | ||
|
|
8962307291 | ||
|
|
0000c72329 | ||
|
|
3ef7a0932a | ||
|
|
f29d2c21bd | ||
|
|
3b44b131b9 | ||
|
|
4a97f95890 | ||
|
|
84ea3a9a2c | ||
|
|
8f2e51faa6 | ||
|
|
f828f8ea65 | ||
|
|
95d579d9de | ||
|
|
f3daba510b | ||
|
|
88e67715a1 | ||
|
|
53eb753346 | ||
|
|
037114b336 | ||
|
|
af72c0848e | ||
|
|
de58ee5a22 | ||
|
|
a1a93c7331 | ||
|
|
db07c162e4 | ||
|
|
9d00f660f1 | ||
|
|
0311888fd4 | ||
|
|
e4f23b31c6 | ||
|
|
57a53891e9 | ||
|
|
b6703bc25c | ||
|
|
003d208574 | ||
|
|
d8d7688f88 | ||
|
|
830b83f653 | ||
|
|
3592e76269 | ||
|
|
6aa4c5c187 | ||
|
|
fb8ee07b43 | ||
|
|
4ccff1a630 | ||
|
|
4b7160d4b2 | ||
|
|
5cce5008a3 | ||
|
|
5b6ce56ca2 | ||
|
|
2b81b6c323 | ||
|
|
a39d8b7c7c | ||
|
|
1bc085c8f7 | ||
|
|
bb00d6919a | ||
|
|
e0e405bb31 | ||
|
|
ce711f7d2f | ||
|
|
f20812d8ad | ||
|
|
05f3c64172 | ||
|
|
dae187eb0b | ||
|
|
7f195d0257 | ||
|
|
a8162baada | ||
|
|
ef53184c10 | ||
|
|
9d38c255f5 | ||
|
|
4de4525528 | ||
|
|
79b4890794 | ||
|
|
dc985c2c98 | ||
|
|
b6f6bdc6f4 | ||
|
|
a49b43fdf6 | ||
|
|
317c335269 | ||
|
|
db06c08141 | ||
|
|
f39301f533 | ||
|
|
a6646021d0 | ||
|
|
d967b2baa3 | ||
|
|
a4df20da85 | ||
|
|
81eaa6e327 | ||
|
|
5fba9895c6 | ||
|
|
64321b314f | ||
|
|
7b5f2c7d94 | ||
|
|
41e666c724 | ||
|
|
88f6e04339 | ||
|
|
b560ab1a73 | ||
|
|
3626c814ac | ||
|
|
bef556e208 | ||
|
|
5a5fc79b3b | ||
|
|
9926c817de | ||
|
|
53902c824d | ||
|
|
3c5675b3fb | ||
|
|
3154a11b43 | ||
|
|
1ff4c0daf3 | ||
|
|
f77f91ef49 | ||
|
|
79fe5f851b | ||
|
|
407837afc4 | ||
|
|
78ddb998a2 | ||
|
|
f33222c83b | ||
|
|
df463e51c1 | ||
|
|
60944a9bcb | ||
|
|
1d51d182ec | ||
|
|
04a0740ccb | ||
|
|
cd84500c56 | ||
|
|
0515b12305 | ||
|
|
b12f4d97f8 | ||
|
|
ee3085e15e | ||
|
|
53e96e5adf | ||
|
|
6f60eb9e1a | ||
|
|
845f384df6 | ||
|
|
39c52c9ecf |
3
.bazelrc
3
.bazelrc
@@ -14,4 +14,7 @@ build:linux --cxxopt=-std=c++20
|
||||
build:macos --cxxopt=-std=c++20 --cpu=darwin_x86_64
|
||||
build:windows --cxxopt=/std:c++20 --cxxopt=/Zc:preprocessor
|
||||
|
||||
common --registry=file:///%workspace%/misc/bazel/registry
|
||||
common --registry=https://bcr.bazel.build
|
||||
|
||||
try-import %workspace%/local.bazelrc
|
||||
|
||||
4
.bazelrc.internal
Normal file
4
.bazelrc.internal
Normal file
@@ -0,0 +1,4 @@
|
||||
# this file should contain bazel settings required to build things from `semmle-code`
|
||||
|
||||
common --registry=file:///%workspace%/ql/misc/bazel/registry
|
||||
common --registry=https://bcr.bazel.build
|
||||
28
.github/workflows/buildifier.yml
vendored
Normal file
28
.github/workflows/buildifier.yml
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
name: Check bazel formatting
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
paths:
|
||||
- "**.bazel"
|
||||
- "**.bzl"
|
||||
branches:
|
||||
- main
|
||||
- "rc/*"
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
check:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
- name: Check bazel formatting
|
||||
uses: pre-commit/action@646c83fcd040023954eafda54b4db0192ce70507
|
||||
with:
|
||||
extra_args: >
|
||||
buildifier --all-files 2>&1 ||
|
||||
(
|
||||
echo -e "In order to format all bazel files, please run:\n bazel run //:buildifier"; exit 1
|
||||
)
|
||||
5
.lfsconfig
Normal file
5
.lfsconfig
Normal file
@@ -0,0 +1,5 @@
|
||||
[lfs]
|
||||
# codeql is publicly forked by many users, and we don't want any LFS file polluting their working
|
||||
# copies. We therefore exclude everything by default.
|
||||
# For files required by bazel builds, use rules in `misc/bazel/lfs.bzl` to download them on demand.
|
||||
fetchinclude = /nothing
|
||||
@@ -20,13 +20,15 @@ repos:
|
||||
- id: autopep8
|
||||
files: ^misc/codegen/.*\.py
|
||||
|
||||
- repo: https://github.com/warchant/pre-commit-buildifier
|
||||
rev: 0.0.2
|
||||
hooks:
|
||||
- id: buildifier
|
||||
|
||||
- repo: local
|
||||
hooks:
|
||||
- id: buildifier
|
||||
name: Format bazel files
|
||||
files: \.(bazel|bzl)
|
||||
language: system
|
||||
entry: bazel run //:buildifier
|
||||
pass_filenames: false
|
||||
|
||||
- id: codeql-format
|
||||
name: Fix QL file formatting
|
||||
files: \.qll?$
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
load("@buildifier_prebuilt//:rules.bzl", "buildifier")
|
||||
|
||||
buildifier(
|
||||
name = "buildifier",
|
||||
exclude_patterns = [
|
||||
"./.git/*",
|
||||
],
|
||||
lint_mode = "fix",
|
||||
)
|
||||
|
||||
@@ -21,6 +21,7 @@ bazel_dep(name = "bazel_skylib", version = "1.5.0")
|
||||
bazel_dep(name = "abseil-cpp", version = "20240116.0", repo_name = "absl")
|
||||
bazel_dep(name = "nlohmann_json", version = "3.11.3", repo_name = "json")
|
||||
bazel_dep(name = "fmt", version = "10.0.0")
|
||||
bazel_dep(name = "buildifier_prebuilt", version = "6.4.0")
|
||||
|
||||
pip = use_extension("@rules_python//python/extensions:pip.bzl", "pip")
|
||||
pip.parse(
|
||||
|
||||
@@ -362,7 +362,7 @@
|
||||
"java/ql/lib/semmle/code/java/security/internal/EncryptionKeySizes.qll"
|
||||
],
|
||||
"Python model summaries test extension": [
|
||||
"python/ql/test/experimental/dataflow/model-summaries/InlineTaintTest.ext.yml",
|
||||
"python/ql/test/experimental/dataflow/model-summaries/NormalDataflowTest.ext.yml"
|
||||
"python/ql/test/library-tests/dataflow/model-summaries/InlineTaintTest.ext.yml",
|
||||
"python/ql/test/library-tests/dataflow/model-summaries/NormalDataflowTest.ext.yml"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,3 +1,20 @@
|
||||
## 0.13.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
* Deleted the deprecated `GlobalValueNumberingImpl.qll` implementation.
|
||||
|
||||
### New Features
|
||||
|
||||
* Models-as-Data support has been added for C/C++. This feature allows flow sources, sinks and summaries to be expressed in compact strings as an alternative to modelling each source / sink / summary with explicit QL. See `dataflow/ExternalFlow.qll` for documentation and specification of the model format, and `models/implementations/ZMQ.qll` for a simple example of models. Importing models from `.yml` is not yet supported.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Source models have been added for the standard library function `getc` (and variations).
|
||||
* Source, sink and flow models for the ZeroMQ (ZMQ) networking library have been added.
|
||||
* Parameters of functions without definitions now have `ParameterNode`s.
|
||||
* The alias analysis used internally by various libraries has been improved to answer alias questions more conservatively. As a result, some queries may report fewer false positives.
|
||||
|
||||
## 0.12.11
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* The alias analysis used internally by various libraries has been improved to answer alias questions more conservatively. As a result, some queries may report fewer false positives.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Parameters of functions without definitions now have `ParameterNode`s.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Source models have been added for the standard library function `getc` (and variations).
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: feature
|
||||
---
|
||||
* Models-as-Data support has been added for C/C++. This feature allows flow sources, sinks and summaries to be expressed in compact strings as an alternative to modelling each source / sink / summary with explicit QL. See `dataflow/ExternalFlow.qll` for documentation and specification of the model format, and `models/implementations/ZMQ.qll` for a simple example of models. Importing models from `.yml` is not yet supported.
|
||||
@@ -1,4 +0,0 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
* Source, sink and flow models for the ZeroMQ (ZMQ) networking library have been added.
|
||||
16
cpp/ql/lib/change-notes/released/0.13.0.md
Normal file
16
cpp/ql/lib/change-notes/released/0.13.0.md
Normal file
@@ -0,0 +1,16 @@
|
||||
## 0.13.0
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
* Deleted the deprecated `GlobalValueNumberingImpl.qll` implementation.
|
||||
|
||||
### New Features
|
||||
|
||||
* Models-as-Data support has been added for C/C++. This feature allows flow sources, sinks and summaries to be expressed in compact strings as an alternative to modelling each source / sink / summary with explicit QL. See `dataflow/ExternalFlow.qll` for documentation and specification of the model format, and `models/implementations/ZMQ.qll` for a simple example of models. Importing models from `.yml` is not yet supported.
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* Source models have been added for the standard library function `getc` (and variations).
|
||||
* Source, sink and flow models for the ZeroMQ (ZMQ) networking library have been added.
|
||||
* Parameters of functions without definitions now have `ParameterNode`s.
|
||||
* The alias analysis used internally by various libraries has been improved to answer alias questions more conservatively. As a result, some queries may report fewer false positives.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.12.11
|
||||
lastReleaseVersion: 0.13.0
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-all
|
||||
version: 0.12.12-dev
|
||||
version: 0.13.1-dev
|
||||
groups: cpp
|
||||
dbscheme: semmlecode.cpp.dbscheme
|
||||
extractor: cpp
|
||||
|
||||
@@ -463,6 +463,25 @@ class StmtNode extends AstNode {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A node representing a child of a `Stmt` that is itself a `Stmt`.
|
||||
*/
|
||||
class ChildStmtNode extends StmtNode {
|
||||
Stmt childStmt;
|
||||
|
||||
ChildStmtNode() { exists(Stmt parent | parent.getAChild() = childStmt and childStmt = ast) }
|
||||
|
||||
override BaseAstNode getChildInternal(int childIndex) {
|
||||
result = super.getChildInternal(childIndex)
|
||||
or
|
||||
exists(int destructorIndex |
|
||||
result.getAst() = childStmt.getImplicitDestructorCall(destructorIndex) and
|
||||
childIndex =
|
||||
destructorIndex + max(int index | exists(childStmt.getChild(index)) or index = 0) + 1
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A node representing a `DeclStmt`.
|
||||
*/
|
||||
@@ -674,6 +693,13 @@ class FunctionNode extends FunctionOrGlobalOrNamespaceVariableNode {
|
||||
private string getChildAccessorWithoutConversions(Locatable parent, Element child) {
|
||||
shouldPrintDeclaration(getAnEnclosingDeclaration(parent)) and
|
||||
(
|
||||
exists(Stmt s, int i | s.getChild(i) = parent |
|
||||
exists(int n |
|
||||
s.getChild(i).(Stmt).getImplicitDestructorCall(n) = child and
|
||||
result = "getImplicitDestructorCall(" + n + ")"
|
||||
)
|
||||
)
|
||||
or
|
||||
exists(Stmt s | s = parent |
|
||||
namedStmtChildPredicates(s, child, result)
|
||||
or
|
||||
|
||||
@@ -790,6 +790,27 @@ private predicate simple_comparison_eq(Instruction test, Operand op, int k, Abst
|
||||
exists(switch.getSuccessor(case)) and
|
||||
case.getValue().toInt() = k
|
||||
)
|
||||
or
|
||||
// There's no implicit CompareInstruction in files compiled as C since C
|
||||
// doesn't have implicit boolean conversions. So instead we check whether
|
||||
// there's a branch on a value of pointer or integer type.
|
||||
exists(ConditionalBranchInstruction branch, IRType type |
|
||||
not test instanceof CompareInstruction and
|
||||
type = test.getResultIRType() and
|
||||
(type instanceof IRAddressType or type instanceof IRIntegerType) and
|
||||
test = branch.getCondition() and
|
||||
op.getDef() = test
|
||||
|
|
||||
// We'd like to also include a case such as:
|
||||
// ```
|
||||
// k = 1 and
|
||||
// value.(BooleanValue).getValue() = true
|
||||
// ```
|
||||
// but all we know is that the value is non-zero in the true branch.
|
||||
// So we can only conclude something in the false branch.
|
||||
k = 0 and
|
||||
value.(BooleanValue).getValue() = false
|
||||
)
|
||||
}
|
||||
|
||||
private predicate complex_eq(
|
||||
@@ -1156,5 +1177,14 @@ private predicate add_eq(
|
||||
)
|
||||
}
|
||||
|
||||
private class IntegerOrPointerConstantInstruction extends ConstantInstruction {
|
||||
IntegerOrPointerConstantInstruction() {
|
||||
this instanceof IntegerConstantInstruction or
|
||||
this instanceof PointerConstantInstruction
|
||||
}
|
||||
}
|
||||
|
||||
/** The int value of integer constant expression. */
|
||||
private int int_value(Instruction i) { result = i.(IntegerConstantInstruction).getValue().toInt() }
|
||||
private int int_value(Instruction i) {
|
||||
result = i.(IntegerOrPointerConstantInstruction).getValue().toInt()
|
||||
}
|
||||
|
||||
@@ -1596,12 +1596,23 @@ private Cpp::Stmt getAChainedBranch(Cpp::IfStmt s) {
|
||||
)
|
||||
}
|
||||
|
||||
private Instruction getInstruction(Node n) {
|
||||
result = n.asInstruction() or
|
||||
result = n.asOperand().getUse() or
|
||||
result = n.(SsaPhiNode).getPhiNode().getBasicBlock().getFirstInstruction() or
|
||||
n.(IndirectInstruction).hasInstructionAndIndirectionIndex(result, _) or
|
||||
result = getInstruction(n.(PostUpdateNode).getPreUpdateNode())
|
||||
private Instruction getAnInstruction(Node n) {
|
||||
result = n.asInstruction()
|
||||
or
|
||||
not n instanceof InstructionNode and
|
||||
result = n.asOperand().getUse()
|
||||
or
|
||||
result = n.(SsaPhiNode).getPhiNode().getBasicBlock().getFirstInstruction()
|
||||
or
|
||||
n.(IndirectInstruction).hasInstructionAndIndirectionIndex(result, _)
|
||||
or
|
||||
not n instanceof IndirectInstruction and
|
||||
exists(Operand operand |
|
||||
n.(IndirectOperand).hasOperandAndIndirectionIndex(operand, _) and
|
||||
result = operand.getUse()
|
||||
)
|
||||
or
|
||||
result = getAnInstruction(n.(PostUpdateNode).getPreUpdateNode())
|
||||
}
|
||||
|
||||
private newtype TDataFlowSecondLevelScope =
|
||||
@@ -1647,10 +1658,318 @@ class DataFlowSecondLevelScope extends TDataFlowSecondLevelScope {
|
||||
|
||||
/** Gets a data-flow node nested within this scope. */
|
||||
Node getANode() {
|
||||
getInstruction(result).getAst().(Cpp::ControlFlowNode).getEnclosingStmt().getParentStmt*() =
|
||||
getAnInstruction(result).getAst().(Cpp::ControlFlowNode).getEnclosingStmt().getParentStmt*() =
|
||||
this.getAStmt()
|
||||
}
|
||||
}
|
||||
|
||||
/** Gets the second-level scope containing the node `n`, if any. */
|
||||
DataFlowSecondLevelScope getSecondLevelScope(Node n) { result.getANode() = n }
|
||||
|
||||
/**
|
||||
* Module that defines flow through iterators.
|
||||
* For example,
|
||||
* ```cpp
|
||||
* auto it = v.begin();
|
||||
* *it = source();
|
||||
* ...
|
||||
* sink(v[0]);
|
||||
* ```
|
||||
*/
|
||||
module IteratorFlow {
|
||||
private import codeql.ssa.Ssa as SsaImpl
|
||||
private import semmle.code.cpp.models.interfaces.Iterator as Interface
|
||||
private import semmle.code.cpp.models.implementations.Iterator as Impl
|
||||
|
||||
/**
|
||||
* A variable of some type that can produce an iterator.
|
||||
*/
|
||||
class SourceVariable extends Ssa::SourceVariable {
|
||||
SourceVariable() {
|
||||
exists(Interface::GetIteratorFunction gets, Cpp::FunctionInput input, int i |
|
||||
input.isParameterDerefOrQualifierObject(i) and
|
||||
gets.getsIterator(input, _)
|
||||
|
|
||||
this.getType().stripType() = gets.getParameter(i).getType().stripType()
|
||||
or
|
||||
i = -1 and
|
||||
this.getType().stripType() = gets.getDeclaringType()
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private module SsaInput implements SsaImpl::InputSig<Location> {
|
||||
import Ssa::InputSigCommon
|
||||
|
||||
class SourceVariable = IteratorFlow::SourceVariable;
|
||||
|
||||
/** A call to function that dereferences an iterator. */
|
||||
private class IteratorPointerDereferenceCall extends CallInstruction {
|
||||
IteratorPointerDereferenceCall() {
|
||||
this.getStaticCallTarget() instanceof Impl::IteratorPointerDereferenceOperator
|
||||
}
|
||||
}
|
||||
|
||||
/** A call to a function that obtains an iterator. */
|
||||
private class GetsIteratorCall extends CallInstruction {
|
||||
GetsIteratorCall() { this.getStaticCallTarget() instanceof Impl::GetIteratorFunction }
|
||||
}
|
||||
|
||||
/** A call to `operator++` or `operator--` on an iterator. */
|
||||
private class IteratorCrementCall extends CallInstruction {
|
||||
IteratorCrementCall() { this.getStaticCallTarget() instanceof Impl::IteratorCrementOperator }
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an ultimate definition of `def`.
|
||||
*
|
||||
* Note: Unlike `def.getAnUltimateDefinition()` this predicate also
|
||||
* traverses back through iterator increment and decrement operations.
|
||||
*/
|
||||
private Ssa::Def getAnUltimateDefinition(Ssa::Def def) {
|
||||
result = def.getAnUltimateDefinition()
|
||||
or
|
||||
exists(IRBlock bb, int i, IteratorCrementCall crementCall, Ssa::SourceVariable sv |
|
||||
crementCall = def.getValue().asInstruction().(StoreInstruction).getSourceValue() and
|
||||
sv = def.getSourceVariable() and
|
||||
bb.getInstruction(i) = crementCall and
|
||||
Ssa::ssaDefReachesRead(sv, result.asDef(), bb, i)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `write` is an instruction that writes to address `address`
|
||||
*/
|
||||
private predicate isIteratorWrite(Instruction write, Operand address) {
|
||||
exists(Ssa::DefImpl writeDef, IRBlock bb, int i |
|
||||
writeDef.hasIndexInBlock(bb, i, _) and
|
||||
bb.getInstruction(i) = write and
|
||||
address = writeDef.getAddressOperand()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `writeToDeref` is a write to an iterator that was obtained
|
||||
* by `beginCall`. That is, the following instruction sequence holds:
|
||||
* ```cpp
|
||||
* it = container.begin(); // or a similar iterator-obtaining function call
|
||||
* ...
|
||||
* *it = value;
|
||||
* ```
|
||||
*/
|
||||
private predicate isIteratorStoreInstruction(
|
||||
GetsIteratorCall beginCall, Instruction writeToDeref
|
||||
) {
|
||||
exists(
|
||||
StoreInstruction beginStore, IRBlock bbStar, int iStar, Ssa::Def def,
|
||||
IteratorPointerDereferenceCall starCall, Ssa::Def ultimate, Operand address
|
||||
|
|
||||
isIteratorWrite(writeToDeref, address) and
|
||||
operandForFullyConvertedCall(address, starCall) and
|
||||
bbStar.getInstruction(iStar) = starCall and
|
||||
Ssa::ssaDefReachesRead(_, def.asDef(), bbStar, iStar) and
|
||||
ultimate = getAnUltimateDefinition*(def) and
|
||||
beginStore = ultimate.getValue().asInstruction() and
|
||||
operandForFullyConvertedCall(beginStore.getSourceValueOperand(), beginCall)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `(bb, i)` contains a write to an iterator that may have been obtained
|
||||
* by calling `begin` (or related functions) on the variable `v`.
|
||||
*/
|
||||
predicate variableWrite(IRBlock bb, int i, SourceVariable v, boolean certain) {
|
||||
certain = false and
|
||||
exists(GetsIteratorCall beginCall, Instruction writeToDeref, IRBlock bbQual, int iQual |
|
||||
isIteratorStoreInstruction(beginCall, writeToDeref) and
|
||||
bb.getInstruction(i) = writeToDeref and
|
||||
bbQual.getInstruction(iQual) = beginCall and
|
||||
Ssa::variableRead(bbQual, iQual, v, _)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `(bb, i)` reads the container variable `v`. */
|
||||
predicate variableRead(IRBlock bb, int i, SourceVariable v, boolean certain) {
|
||||
Ssa::variableRead(bb, i, v, certain)
|
||||
}
|
||||
}
|
||||
|
||||
private module IteratorSsa = SsaImpl::Make<Location, SsaInput>;
|
||||
|
||||
cached
|
||||
private newtype TSsaDef =
|
||||
TDef(IteratorSsa::DefinitionExt def) or
|
||||
TPhi(PhiNode phi)
|
||||
|
||||
abstract private class SsaDef extends TSsaDef {
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { none() }
|
||||
|
||||
/** Gets the underlying non-phi definition or use. */
|
||||
IteratorSsa::DefinitionExt asDef() { none() }
|
||||
|
||||
/** Gets the underlying phi node. */
|
||||
PhiNode asPhi() { none() }
|
||||
|
||||
/** Gets the location of this element. */
|
||||
abstract Location getLocation();
|
||||
}
|
||||
|
||||
private class Def extends TDef, SsaDef {
|
||||
IteratorSsa::DefinitionExt def;
|
||||
|
||||
Def() { this = TDef(def) }
|
||||
|
||||
final override IteratorSsa::DefinitionExt asDef() { result = def }
|
||||
|
||||
final override Location getLocation() { result = this.getImpl().getLocation() }
|
||||
|
||||
/** Gets the variable written to by this definition. */
|
||||
final SourceVariable getSourceVariable() { result = def.getSourceVariable() }
|
||||
|
||||
override string toString() { result = def.toString() }
|
||||
|
||||
/**
|
||||
* Holds if this definition (or use) has index `index` in block `block`,
|
||||
* and is a definition (or use) of the variable `sv`.
|
||||
*/
|
||||
predicate hasIndexInBlock(IRBlock block, int index, SourceVariable sv) {
|
||||
def.definesAt(sv, block, index, _)
|
||||
}
|
||||
|
||||
private Ssa::DefImpl getImpl() {
|
||||
exists(IRBlock bb, int i |
|
||||
this.hasIndexInBlock(bb, i, _) and
|
||||
result.hasIndexInBlock(bb, i)
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the value written by this definition (i.e., the "right-hand side"). */
|
||||
Node0Impl getValue() { result = this.getImpl().getValue() }
|
||||
|
||||
/** Gets the indirection index of this definition. */
|
||||
int getIndirectionIndex() { result = this.getImpl().getIndirectionIndex() }
|
||||
}
|
||||
|
||||
private class Phi extends TPhi, SsaDef {
|
||||
PhiNode phi;
|
||||
|
||||
Phi() { this = TPhi(phi) }
|
||||
|
||||
final override PhiNode asPhi() { result = phi }
|
||||
|
||||
final override Location getLocation() { result = phi.getBasicBlock().getLocation() }
|
||||
|
||||
override string toString() { result = phi.toString() }
|
||||
|
||||
SsaIteratorNode getNode() { result.getIteratorFlowNode() = phi }
|
||||
}
|
||||
|
||||
private class PhiNode extends IteratorSsa::DefinitionExt {
|
||||
PhiNode() {
|
||||
this instanceof IteratorSsa::PhiNode or
|
||||
this instanceof IteratorSsa::PhiReadNode
|
||||
}
|
||||
|
||||
SsaIteratorNode getNode() { result.getIteratorFlowNode() = this }
|
||||
}
|
||||
|
||||
cached
|
||||
private module IteratorSsaCached {
|
||||
cached
|
||||
predicate adjacentDefRead(IRBlock bb1, int i1, SourceVariable sv, IRBlock bb2, int i2) {
|
||||
IteratorSsa::adjacentDefReadExt(_, sv, bb1, i1, bb2, i2)
|
||||
or
|
||||
exists(PhiNode phi |
|
||||
IteratorSsa::lastRefRedefExt(_, sv, bb1, i1, phi) and
|
||||
phi.definesAt(sv, bb2, i2, _)
|
||||
)
|
||||
}
|
||||
|
||||
cached
|
||||
Node getAPriorDefinition(IteratorSsa::DefinitionExt next) {
|
||||
exists(IRBlock bb, int i, SourceVariable sv, IteratorSsa::DefinitionExt def |
|
||||
IteratorSsa::lastRefRedefExt(pragma[only_bind_into](def), pragma[only_bind_into](sv),
|
||||
pragma[only_bind_into](bb), pragma[only_bind_into](i), next) and
|
||||
nodeToDefOrUse(result, sv, bb, i, _)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/** The set of nodes necessary for iterator flow. */
|
||||
class IteratorFlowNode instanceof PhiNode {
|
||||
/** Gets a textual representation of this node. */
|
||||
string toString() { result = super.toString() }
|
||||
|
||||
/** Gets the type of this node. */
|
||||
DataFlowType getType() {
|
||||
exists(Ssa::SourceVariable sv |
|
||||
super.definesAt(sv, _, _, _) and
|
||||
result = sv.getType()
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets the `Declaration` that contains this block. */
|
||||
Declaration getFunction() { result = super.getBasicBlock().getEnclosingFunction() }
|
||||
|
||||
/** Gets the locatino of this node. */
|
||||
Location getLocation() { result = super.getBasicBlock().getLocation() }
|
||||
}
|
||||
|
||||
private import IteratorSsaCached
|
||||
|
||||
private predicate defToNode(Node node, Def def, boolean uncertain) {
|
||||
(
|
||||
nodeHasOperand(node, def.getValue().asOperand(), def.getIndirectionIndex())
|
||||
or
|
||||
nodeHasInstruction(node, def.getValue().asInstruction(), def.getIndirectionIndex())
|
||||
) and
|
||||
uncertain = false
|
||||
}
|
||||
|
||||
private predicate nodeToDefOrUse(
|
||||
Node node, SourceVariable sv, IRBlock bb, int i, boolean uncertain
|
||||
) {
|
||||
exists(Def def |
|
||||
def.hasIndexInBlock(bb, i, sv) and
|
||||
defToNode(node, def, uncertain)
|
||||
)
|
||||
or
|
||||
useToNode(bb, i, sv, node) and
|
||||
uncertain = false
|
||||
}
|
||||
|
||||
private predicate useToNode(IRBlock bb, int i, SourceVariable sv, Node nodeTo) {
|
||||
exists(PhiNode phi |
|
||||
phi.definesAt(sv, bb, i, _) and
|
||||
nodeTo = phi.getNode()
|
||||
)
|
||||
or
|
||||
exists(Ssa::UseImpl use |
|
||||
use.hasIndexInBlock(bb, i, sv) and
|
||||
nodeTo = use.getNode()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `nodeFrom` flows to `nodeTo` in a single step.
|
||||
*/
|
||||
predicate localFlowStep(Node nodeFrom, Node nodeTo) {
|
||||
exists(
|
||||
Node nFrom, SourceVariable sv, IRBlock bb1, int i1, IRBlock bb2, int i2, boolean uncertain
|
||||
|
|
||||
adjacentDefRead(bb1, i1, sv, bb2, i2) and
|
||||
nodeToDefOrUse(nFrom, sv, bb1, i1, uncertain) and
|
||||
useToNode(bb2, i2, sv, nodeTo)
|
||||
|
|
||||
if uncertain = true
|
||||
then
|
||||
nodeFrom =
|
||||
[
|
||||
nFrom,
|
||||
getAPriorDefinition(any(IteratorSsa::DefinitionExt next | next.definesAt(sv, bb1, i1, _)))
|
||||
]
|
||||
else nFrom = nodeFrom
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,6 +46,7 @@ private newtype TIRDataFlowNode =
|
||||
Ssa::isModifiableByCall(operand, indirectionIndex)
|
||||
} or
|
||||
TSsaPhiNode(Ssa::PhiNode phi) or
|
||||
TSsaIteratorNode(IteratorFlow::IteratorFlowNode n) or
|
||||
TRawIndirectOperand0(Node0Impl node, int indirectionIndex) {
|
||||
Ssa::hasRawIndirectOperand(node.asOperand(), indirectionIndex)
|
||||
} or
|
||||
@@ -653,6 +654,30 @@ class SsaPhiNode extends Node, TSsaPhiNode {
|
||||
predicate isPhiRead() { phi.isPhiRead() }
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL: do not use.
|
||||
*
|
||||
* Dataflow nodes necessary for iterator flow
|
||||
*/
|
||||
class SsaIteratorNode extends Node, TSsaIteratorNode {
|
||||
IteratorFlow::IteratorFlowNode node;
|
||||
|
||||
SsaIteratorNode() { this = TSsaIteratorNode(node) }
|
||||
|
||||
/** Gets the phi node associated with this node. */
|
||||
IteratorFlow::IteratorFlowNode getIteratorFlowNode() { result = node }
|
||||
|
||||
override Declaration getEnclosingCallable() { result = this.getFunction() }
|
||||
|
||||
override Declaration getFunction() { result = node.getFunction() }
|
||||
|
||||
override DataFlowType getType() { result = node.getType() }
|
||||
|
||||
final override Location getLocationImpl() { result = node.getLocation() }
|
||||
|
||||
override string toStringImpl() { result = node.toString() }
|
||||
}
|
||||
|
||||
/**
|
||||
* INTERNAL: do not use.
|
||||
*
|
||||
@@ -1190,11 +1215,11 @@ class UninitializedNode extends Node {
|
||||
LocalVariable v;
|
||||
|
||||
UninitializedNode() {
|
||||
exists(Ssa::Def def |
|
||||
exists(Ssa::Def def, Ssa::SourceVariable sv |
|
||||
def.getIndirectionIndex() = 0 and
|
||||
def.getValue().asInstruction() instanceof UninitializedInstruction and
|
||||
Ssa::nodeToDefOrUse(this, def, _) and
|
||||
v = def.getSourceVariable().getBaseVariable().(Ssa::BaseIRVariable).getIRVariable().getAst()
|
||||
Ssa::defToNode(this, def, sv, _, _, _) and
|
||||
v = sv.getBaseVariable().(Ssa::BaseIRVariable).getIRVariable().getAst()
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2151,6 +2176,8 @@ private module Cached {
|
||||
// Def-use/Use-use flow
|
||||
Ssa::ssaFlow(nodeFrom, nodeTo)
|
||||
or
|
||||
IteratorFlow::localFlowStep(nodeFrom, nodeTo)
|
||||
or
|
||||
// Operand -> Instruction flow
|
||||
simpleInstructionLocalFlowStep(nodeFrom.asOperand(), nodeTo.asInstruction())
|
||||
or
|
||||
|
||||
@@ -102,12 +102,20 @@ predicate hasRawIndirectInstruction(Instruction instr, int indirectionIndex) {
|
||||
}
|
||||
|
||||
cached
|
||||
private newtype TDefOrUseImpl =
|
||||
private newtype TDefImpl =
|
||||
TDefAddressImpl(BaseIRVariable v) or
|
||||
TDefImpl(BaseSourceVariableInstruction base, Operand address, int indirectionIndex) {
|
||||
TDirectDefImpl(BaseSourceVariableInstruction base, Operand address, int indirectionIndex) {
|
||||
isDef(_, _, address, base, _, indirectionIndex)
|
||||
} or
|
||||
TUseImpl(BaseSourceVariableInstruction base, Operand operand, int indirectionIndex) {
|
||||
TGlobalDefImpl(GlobalLikeVariable v, IRFunction f, int indirectionIndex) {
|
||||
// Represents the initial "definition" of a global variable when entering
|
||||
// a function body.
|
||||
isGlobalDefImpl(v, f, _, indirectionIndex)
|
||||
}
|
||||
|
||||
cached
|
||||
private newtype TUseImpl =
|
||||
TDirectUseImpl(BaseSourceVariableInstruction base, Operand operand, int indirectionIndex) {
|
||||
isUse(_, operand, base, _, indirectionIndex) and
|
||||
not isDef(true, _, operand, _, _, _)
|
||||
} or
|
||||
@@ -116,21 +124,6 @@ private newtype TDefOrUseImpl =
|
||||
// the assignment to a global variable isn't ruled out as dead.
|
||||
isGlobalUse(v, f, _, indirectionIndex)
|
||||
} or
|
||||
TGlobalDefImpl(GlobalLikeVariable v, IRFunction f, int indirectionIndex) {
|
||||
// Represents the initial "definition" of a global variable when entering
|
||||
// a function body.
|
||||
isGlobalDefImpl(v, f, _, indirectionIndex)
|
||||
} or
|
||||
TIteratorDef(
|
||||
Operand iteratorDerefAddress, BaseSourceVariableInstruction container, int indirectionIndex
|
||||
) {
|
||||
isIteratorDef(container, iteratorDerefAddress, _, _, indirectionIndex)
|
||||
} or
|
||||
TIteratorUse(
|
||||
Operand iteratorAddress, BaseSourceVariableInstruction container, int indirectionIndex
|
||||
) {
|
||||
isIteratorUse(container, iteratorAddress, _, indirectionIndex)
|
||||
} or
|
||||
TFinalParameterUse(Parameter p, int indirectionIndex) {
|
||||
underlyingTypeIsModifiableAt(p.getUnderlyingType(), indirectionIndex) and
|
||||
// Only create an SSA read for the final use of a parameter if there's
|
||||
@@ -177,7 +170,84 @@ private predicate underlyingTypeIsModifiableAt(Type underlying, int indirectionI
|
||||
|
||||
private Indirection getIndirectionForUnspecifiedType(Type t) { result.getType() = t }
|
||||
|
||||
abstract private class DefOrUseImpl extends TDefOrUseImpl {
|
||||
abstract class DefImpl extends TDefImpl {
|
||||
int indirectionIndex;
|
||||
|
||||
bindingset[indirectionIndex]
|
||||
DefImpl() { any() }
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
abstract string toString();
|
||||
|
||||
/** Gets the block of this definition or use. */
|
||||
final IRBlock getBlock() { this.hasIndexInBlock(result, _) }
|
||||
|
||||
/** Holds if this definition or use has index `index` in block `block`. */
|
||||
abstract predicate hasIndexInBlock(IRBlock block, int index);
|
||||
|
||||
/**
|
||||
* Holds if this definition (or use) has index `index` in block `block`,
|
||||
* and is a definition (or use) of the variable `sv`
|
||||
*/
|
||||
final predicate hasIndexInBlock(IRBlock block, int index, SourceVariable sv) {
|
||||
this.hasIndexInBlock(block, index) and
|
||||
sv = this.getSourceVariable()
|
||||
}
|
||||
|
||||
/** Gets the location of this element. */
|
||||
abstract Cpp::Location getLocation();
|
||||
|
||||
/** Gets the indirection index of this definition. */
|
||||
final int getIndirectionIndex() { result = indirectionIndex }
|
||||
|
||||
/**
|
||||
* Gets the index (i.e., the number of loads required) of this
|
||||
* definition or use.
|
||||
*
|
||||
* Note that this is _not_ the definition's (or use's) index in
|
||||
* the enclosing basic block. To obtain this index, use
|
||||
* `DefOrUseImpl::hasIndexInBlock/2` or `DefOrUseImpl::hasIndexInBlock/3`.
|
||||
*/
|
||||
abstract int getIndirection();
|
||||
|
||||
/**
|
||||
* Gets the instruction that computes the base of this definition or use.
|
||||
* This is always a `VariableAddressInstruction` or an `CallInstruction`.
|
||||
*/
|
||||
abstract BaseSourceVariableInstruction getBase();
|
||||
|
||||
/**
|
||||
* Gets the base source variable (i.e., the variable without
|
||||
* any indirection) of this definition or use.
|
||||
*/
|
||||
final BaseSourceVariable getBaseSourceVariable() {
|
||||
this.getBase().getBaseSourceVariable() = result
|
||||
}
|
||||
|
||||
/** Gets the variable that is defined or used. */
|
||||
SourceVariable getSourceVariable() {
|
||||
exists(BaseSourceVariable v, int indirection |
|
||||
sourceVariableHasBaseAndIndex(result, v, indirection) and
|
||||
defHasSourceVariable(this, v, indirection)
|
||||
)
|
||||
}
|
||||
|
||||
abstract predicate isCertain();
|
||||
|
||||
abstract Node0Impl getValue();
|
||||
|
||||
Operand getAddressOperand() { none() }
|
||||
}
|
||||
|
||||
abstract class UseImpl extends TUseImpl {
|
||||
int indirectionIndex;
|
||||
|
||||
bindingset[indirectionIndex]
|
||||
UseImpl() { any() }
|
||||
|
||||
/** Gets the node associated with this use. */
|
||||
abstract Node getNode();
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
abstract string toString();
|
||||
|
||||
@@ -207,7 +277,10 @@ abstract private class DefOrUseImpl extends TDefOrUseImpl {
|
||||
* the enclosing basic block. To obtain this index, use
|
||||
* `DefOrUseImpl::hasIndexInBlock/2` or `DefOrUseImpl::hasIndexInBlock/3`.
|
||||
*/
|
||||
abstract int getIndirectionIndex();
|
||||
abstract int getIndirection();
|
||||
|
||||
/** Gets the indirection index of this use. */
|
||||
final int getIndirectionIndex() { result = indirectionIndex }
|
||||
|
||||
/**
|
||||
* Gets the instruction that computes the base of this definition or use.
|
||||
@@ -225,17 +298,17 @@ abstract private class DefOrUseImpl extends TDefOrUseImpl {
|
||||
|
||||
/** Gets the variable that is defined or used. */
|
||||
SourceVariable getSourceVariable() {
|
||||
exists(BaseSourceVariable v, int ind |
|
||||
sourceVariableHasBaseAndIndex(result, v, ind) and
|
||||
defOrUseHasSourceVariable(this, v, ind)
|
||||
exists(BaseSourceVariable v, int indirection |
|
||||
sourceVariableHasBaseAndIndex(result, v, indirection) and
|
||||
useHasSourceVariable(this, v, indirection)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private predicate defOrUseHasSourceVariable(DefOrUseImpl defOrUse, BaseSourceVariable bv, int ind) {
|
||||
defHasSourceVariable(defOrUse, bv, ind)
|
||||
or
|
||||
useHasSourceVariable(defOrUse, bv, ind)
|
||||
/**
|
||||
* Holds if this use is guaranteed to read the
|
||||
* associated variable.
|
||||
*/
|
||||
abstract predicate isCertain();
|
||||
}
|
||||
|
||||
pragma[noinline]
|
||||
@@ -256,32 +329,17 @@ private predicate sourceVariableHasBaseAndIndex(SourceVariable v, BaseSourceVari
|
||||
v.getIndirection() = ind
|
||||
}
|
||||
|
||||
abstract class DefImpl extends DefOrUseImpl {
|
||||
int ind;
|
||||
|
||||
bindingset[ind]
|
||||
DefImpl() { any() }
|
||||
|
||||
override int getIndirectionIndex() { result = ind }
|
||||
|
||||
override string toString() { result = "Def of " + this.getSourceVariable() }
|
||||
|
||||
abstract int getIndirection();
|
||||
|
||||
abstract predicate isCertain();
|
||||
|
||||
abstract Node0Impl getValue();
|
||||
}
|
||||
|
||||
/** An initial definition of an `IRVariable`'s address. */
|
||||
private class DefAddressImpl extends DefImpl, TDefAddressImpl {
|
||||
BaseIRVariable v;
|
||||
|
||||
DefAddressImpl() {
|
||||
this = TDefAddressImpl(v) and
|
||||
ind = 0
|
||||
indirectionIndex = 0
|
||||
}
|
||||
|
||||
override string toString() { result = "Def of &" + v.toString() }
|
||||
|
||||
final override int getIndirection() { result = 0 }
|
||||
|
||||
final override predicate isCertain() { any() }
|
||||
@@ -303,91 +361,45 @@ private class DefAddressImpl extends DefImpl, TDefAddressImpl {
|
||||
final override BaseSourceVariableInstruction getBase() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An SSA definition that has an associated `Operand` representing the address
|
||||
* that is being written to.
|
||||
*/
|
||||
abstract private class OperandBasedDef extends DefImpl {
|
||||
private class DirectDef extends DefImpl, TDirectDefImpl {
|
||||
Operand address;
|
||||
BaseSourceVariableInstruction base;
|
||||
|
||||
bindingset[ind]
|
||||
OperandBasedDef() { any() }
|
||||
|
||||
Operand getAddressOperand() { result = address }
|
||||
DirectDef() { this = TDirectDefImpl(base, address, indirectionIndex) }
|
||||
|
||||
override Cpp::Location getLocation() { result = this.getAddressOperand().getUse().getLocation() }
|
||||
|
||||
final override predicate hasIndexInBlock(IRBlock block, int index) {
|
||||
this.getAddressOperand().getUse() = block.getInstruction(index)
|
||||
}
|
||||
}
|
||||
|
||||
private class DirectDef extends OperandBasedDef, TDefImpl {
|
||||
BaseSourceVariableInstruction base;
|
||||
override string toString() { result = "Def of " + this.getSourceVariable() }
|
||||
|
||||
DirectDef() { this = TDefImpl(base, address, ind) }
|
||||
override Operand getAddressOperand() { result = address }
|
||||
|
||||
override BaseSourceVariableInstruction getBase() { result = base }
|
||||
|
||||
override int getIndirection() { isDef(_, _, address, base, result, ind) }
|
||||
override int getIndirection() { isDef(_, _, address, base, result, indirectionIndex) }
|
||||
|
||||
override Node0Impl getValue() { isDef(_, result, address, base, _, _) }
|
||||
|
||||
override predicate isCertain() { isDef(true, _, address, base, _, ind) }
|
||||
override predicate isCertain() { isDef(true, _, address, base, _, indirectionIndex) }
|
||||
}
|
||||
|
||||
private class IteratorDef extends OperandBasedDef, TIteratorDef {
|
||||
BaseSourceVariableInstruction container;
|
||||
|
||||
IteratorDef() { this = TIteratorDef(address, container, ind) }
|
||||
|
||||
override BaseSourceVariableInstruction getBase() { result = container }
|
||||
|
||||
override int getIndirection() { isIteratorDef(container, address, _, result, ind) }
|
||||
|
||||
override Node0Impl getValue() { isIteratorDef(container, address, result, _, _) }
|
||||
|
||||
override predicate isCertain() { none() }
|
||||
}
|
||||
|
||||
abstract class UseImpl extends DefOrUseImpl {
|
||||
int ind;
|
||||
|
||||
bindingset[ind]
|
||||
UseImpl() { any() }
|
||||
|
||||
/** Gets the node associated with this use. */
|
||||
abstract Node getNode();
|
||||
|
||||
override string toString() { result = "Use of " + this.getSourceVariable() }
|
||||
|
||||
/** Gets the indirection index of this use. */
|
||||
final override int getIndirectionIndex() { result = ind }
|
||||
|
||||
/** Gets the number of loads that precedence this use. */
|
||||
abstract int getIndirection();
|
||||
|
||||
/**
|
||||
* Holds if this use is guaranteed to read the
|
||||
* associated variable.
|
||||
*/
|
||||
abstract predicate isCertain();
|
||||
}
|
||||
|
||||
abstract private class OperandBasedUse extends UseImpl {
|
||||
private class DirectUseImpl extends UseImpl, TDirectUseImpl {
|
||||
Operand operand;
|
||||
BaseSourceVariableInstruction base;
|
||||
|
||||
bindingset[ind]
|
||||
OperandBasedUse() { any() }
|
||||
DirectUseImpl() { this = TDirectUseImpl(base, operand, indirectionIndex) }
|
||||
|
||||
override string toString() { result = "Use of " + this.getSourceVariable() }
|
||||
|
||||
final override predicate hasIndexInBlock(IRBlock block, int index) {
|
||||
// See the comment in `ssa0`'s `OperandBasedUse` for an explanation of this
|
||||
// predicate's implementation.
|
||||
if base.getAst() = any(Cpp::PostfixCrementOperation c).getOperand()
|
||||
then
|
||||
exists(Operand op, int indirectionIndex, int indirection |
|
||||
indirectionIndex = this.getIndirectionIndex() and
|
||||
exists(Operand op, int indirection |
|
||||
indirection = this.getIndirection() and
|
||||
op =
|
||||
min(Operand cand, int i |
|
||||
@@ -406,26 +418,12 @@ abstract private class OperandBasedUse extends UseImpl {
|
||||
final Operand getOperand() { result = operand }
|
||||
|
||||
final override Cpp::Location getLocation() { result = operand.getLocation() }
|
||||
}
|
||||
|
||||
private class DirectUse extends OperandBasedUse, TUseImpl {
|
||||
DirectUse() { this = TUseImpl(base, operand, ind) }
|
||||
override int getIndirection() { isUse(_, operand, base, result, indirectionIndex) }
|
||||
|
||||
override int getIndirection() { isUse(_, operand, base, result, ind) }
|
||||
override predicate isCertain() { isUse(true, operand, base, _, indirectionIndex) }
|
||||
|
||||
override predicate isCertain() { isUse(true, operand, base, _, ind) }
|
||||
|
||||
override Node getNode() { nodeHasOperand(result, operand, ind) }
|
||||
}
|
||||
|
||||
private class IteratorUse extends OperandBasedUse, TIteratorUse {
|
||||
IteratorUse() { this = TIteratorUse(operand, base, ind) }
|
||||
|
||||
override int getIndirection() { isIteratorUse(base, operand, result, ind) }
|
||||
|
||||
override predicate isCertain() { none() }
|
||||
|
||||
override Node getNode() { nodeHasOperand(result, operand, ind) }
|
||||
override Node getNode() { nodeHasOperand(result, operand, indirectionIndex) }
|
||||
}
|
||||
|
||||
pragma[nomagic]
|
||||
@@ -439,15 +437,17 @@ private predicate finalParameterNodeHasParameterAndIndex(
|
||||
class FinalParameterUse extends UseImpl, TFinalParameterUse {
|
||||
Parameter p;
|
||||
|
||||
FinalParameterUse() { this = TFinalParameterUse(p, ind) }
|
||||
FinalParameterUse() { this = TFinalParameterUse(p, indirectionIndex) }
|
||||
|
||||
override string toString() { result = "Use of " + p.toString() }
|
||||
|
||||
Parameter getParameter() { result = p }
|
||||
|
||||
int getArgumentIndex() { result = p.getIndex() }
|
||||
|
||||
override Node getNode() { finalParameterNodeHasParameterAndIndex(result, p, ind) }
|
||||
override Node getNode() { finalParameterNodeHasParameterAndIndex(result, p, indirectionIndex) }
|
||||
|
||||
override int getIndirection() { result = ind + 1 }
|
||||
override int getIndirection() { result = indirectionIndex + 1 }
|
||||
|
||||
override predicate isCertain() { any() }
|
||||
|
||||
@@ -544,11 +544,13 @@ class GlobalUse extends UseImpl, TGlobalUse {
|
||||
GlobalLikeVariable global;
|
||||
IRFunction f;
|
||||
|
||||
GlobalUse() { this = TGlobalUse(global, f, ind) }
|
||||
GlobalUse() { this = TGlobalUse(global, f, indirectionIndex) }
|
||||
|
||||
override string toString() { result = "Use of " + global }
|
||||
|
||||
override FinalGlobalValue getNode() { result.getGlobalUse() = this }
|
||||
|
||||
override int getIndirection() { isGlobalUse(global, f, result, ind) }
|
||||
override int getIndirection() { isGlobalUse(global, f, result, indirectionIndex) }
|
||||
|
||||
/** Gets the global variable associated with this use. */
|
||||
GlobalLikeVariable getVariable() { result = global }
|
||||
@@ -598,10 +600,9 @@ class GlobalUse extends UseImpl, TGlobalUse {
|
||||
*
|
||||
* See the QLDoc for `GlobalUse` for how this is used.
|
||||
*/
|
||||
class GlobalDefImpl extends DefOrUseImpl, TGlobalDefImpl {
|
||||
class GlobalDefImpl extends DefImpl, TGlobalDefImpl {
|
||||
GlobalLikeVariable global;
|
||||
IRFunction f;
|
||||
int indirectionIndex;
|
||||
|
||||
GlobalDefImpl() { this = TGlobalDefImpl(global, f, indirectionIndex) }
|
||||
|
||||
@@ -611,9 +612,6 @@ class GlobalDefImpl extends DefOrUseImpl, TGlobalDefImpl {
|
||||
/** Gets the `IRFunction` whose body is evaluated after this definition. */
|
||||
IRFunction getIRFunction() { result = f }
|
||||
|
||||
/** Gets the global variable associated with this definition. */
|
||||
override int getIndirectionIndex() { result = indirectionIndex }
|
||||
|
||||
/** Holds if this definition or use has index `index` in block `block`. */
|
||||
final override predicate hasIndexInBlock(IRBlock block, int index) {
|
||||
exists(EnterFunctionInstruction enter |
|
||||
@@ -627,7 +625,11 @@ class GlobalDefImpl extends DefOrUseImpl, TGlobalDefImpl {
|
||||
sourceVariableIsGlobal(result, global, f, this.getIndirection())
|
||||
}
|
||||
|
||||
int getIndirection() { result = indirectionIndex }
|
||||
override int getIndirection() { result = indirectionIndex }
|
||||
|
||||
override Node0Impl getValue() { none() }
|
||||
|
||||
override predicate isCertain() { any() }
|
||||
|
||||
/**
|
||||
* Gets the type of this definition after specifiers have been deeply
|
||||
@@ -648,60 +650,30 @@ class GlobalDefImpl extends DefOrUseImpl, TGlobalDefImpl {
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `defOrUse1` is a definition which is first read by `use`,
|
||||
* or if `defOrUse1` is a use and `use` is a next subsequent use.
|
||||
*
|
||||
* In both cases, `use` can either be an explicit use written in the
|
||||
* source file, or it can be a phi node as computed by the SSA library.
|
||||
* Holds if there is a definition or access at index `i1` in basic block `bb1`
|
||||
* and the next subsequent read is at index `i2` in basic block `bb2`.
|
||||
*/
|
||||
predicate adjacentDefRead(DefOrUse defOrUse1, UseOrPhi use) {
|
||||
exists(IRBlock bb1, int i1, SourceVariable v |
|
||||
defOrUse1
|
||||
.asDefOrUse()
|
||||
.hasIndexInBlock(pragma[only_bind_out](bb1), pragma[only_bind_out](i1),
|
||||
pragma[only_bind_out](v))
|
||||
|
|
||||
exists(IRBlock bb2, int i2, DefinitionExt def |
|
||||
adjacentDefReadExt(pragma[only_bind_into](def), pragma[only_bind_into](bb1),
|
||||
pragma[only_bind_into](i1), pragma[only_bind_into](bb2), pragma[only_bind_into](i2)) and
|
||||
def.getSourceVariable() = v and
|
||||
use.asDefOrUse().(UseImpl).hasIndexInBlock(bb2, i2, v)
|
||||
)
|
||||
or
|
||||
exists(PhiNode phi |
|
||||
lastRefRedefExt(_, bb1, i1, phi) and
|
||||
use.asPhi() = phi and
|
||||
phi.getSourceVariable() = pragma[only_bind_into](v)
|
||||
)
|
||||
predicate adjacentDefRead(IRBlock bb1, int i1, SourceVariable sv, IRBlock bb2, int i2) {
|
||||
adjacentDefReadExt(_, sv, bb1, i1, bb2, i2)
|
||||
or
|
||||
exists(PhiNode phi |
|
||||
lastRefRedefExt(_, sv, bb1, i1, phi) and
|
||||
phi.definesAt(sv, bb2, i2, _)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `globalDef` represents the initial definition of a global variable that
|
||||
* flows to `useOrPhi`.
|
||||
*/
|
||||
private predicate globalDefToUse(GlobalDef globalDef, UseOrPhi useOrPhi) {
|
||||
exists(IRBlock bb1, int i1, SourceVariable v |
|
||||
globalDef
|
||||
.hasIndexInBlock(pragma[only_bind_out](bb1), pragma[only_bind_out](i1),
|
||||
pragma[only_bind_out](v))
|
||||
|
|
||||
exists(IRBlock bb2, int i2 |
|
||||
adjacentDefReadExt(_, pragma[only_bind_into](bb1), pragma[only_bind_into](i1),
|
||||
pragma[only_bind_into](bb2), pragma[only_bind_into](i2)) and
|
||||
useOrPhi.asDefOrUse().hasIndexInBlock(bb2, i2, v)
|
||||
)
|
||||
or
|
||||
exists(PhiNode phi |
|
||||
lastRefRedefExt(_, bb1, i1, phi) and
|
||||
useOrPhi.asPhi() = phi and
|
||||
phi.getSourceVariable() = pragma[only_bind_into](v)
|
||||
)
|
||||
predicate useToNode(IRBlock bb, int i, SourceVariable sv, Node nodeTo) {
|
||||
exists(Phi phi |
|
||||
phi.asPhi().definesAt(sv, bb, i, _) and
|
||||
nodeTo = phi.getNode()
|
||||
)
|
||||
or
|
||||
exists(UseImpl use |
|
||||
use.hasIndexInBlock(bb, i, sv) and
|
||||
nodeTo = use.getNode()
|
||||
)
|
||||
}
|
||||
|
||||
private predicate useToNode(UseOrPhi use, Node nodeTo) { use.getNode() = nodeTo }
|
||||
|
||||
pragma[noinline]
|
||||
predicate outNodeHasAddressAndIndex(
|
||||
IndirectArgumentOutNode out, Operand address, int indirectionIndex
|
||||
@@ -710,11 +682,19 @@ predicate outNodeHasAddressAndIndex(
|
||||
out.getIndirectionIndex() = indirectionIndex
|
||||
}
|
||||
|
||||
private predicate defToNode(Node nodeFrom, Def def, boolean uncertain) {
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*
|
||||
* Holds if `node` is the node that corresponds to the definition of `def`.
|
||||
*/
|
||||
predicate defToNode(Node node, Def def, SourceVariable sv, IRBlock bb, int i, boolean uncertain) {
|
||||
def.hasIndexInBlock(bb, i, sv) and
|
||||
(
|
||||
nodeHasOperand(nodeFrom, def.getValue().asOperand(), def.getIndirectionIndex())
|
||||
nodeHasOperand(node, def.getValue().asOperand(), def.getIndirectionIndex())
|
||||
or
|
||||
nodeHasInstruction(nodeFrom, def.getValue().asInstruction(), def.getIndirectionIndex())
|
||||
nodeHasInstruction(node, def.getValue().asInstruction(), def.getIndirectionIndex())
|
||||
or
|
||||
node.(InitialGlobalValue).getGlobalDef() = def
|
||||
) and
|
||||
if def.isCertain() then uncertain = false else uncertain = true
|
||||
}
|
||||
@@ -722,14 +702,16 @@ private predicate defToNode(Node nodeFrom, Def def, boolean uncertain) {
|
||||
/**
|
||||
* INTERNAL: Do not use.
|
||||
*
|
||||
* Holds if `nodeFrom` is the node that correspond to the definition or use `defOrUse`.
|
||||
* Holds if `node` is the node that corresponds to the definition or use at
|
||||
* index `i` in block `bb` of `sv`.
|
||||
*
|
||||
* `uncertain` is `true` if this is an uncertain definition.
|
||||
*/
|
||||
predicate nodeToDefOrUse(Node nodeFrom, SsaDefOrUse defOrUse, boolean uncertain) {
|
||||
// Node -> Def
|
||||
defToNode(nodeFrom, defOrUse, uncertain)
|
||||
predicate nodeToDefOrUse(Node node, SourceVariable sv, IRBlock bb, int i, boolean uncertain) {
|
||||
defToNode(node, _, sv, bb, i, uncertain)
|
||||
or
|
||||
// Node -> Use
|
||||
useToNode(defOrUse, nodeFrom) and
|
||||
useToNode(bb, i, sv, node) and
|
||||
uncertain = false
|
||||
}
|
||||
|
||||
@@ -738,9 +720,9 @@ predicate nodeToDefOrUse(Node nodeFrom, SsaDefOrUse defOrUse, boolean uncertain)
|
||||
* only holds when there is no use-use relation out of `nTo`.
|
||||
*/
|
||||
private predicate indirectConversionFlowStep(Node nFrom, Node nTo) {
|
||||
not exists(UseOrPhi defOrUse |
|
||||
nodeToDefOrUse(nTo, defOrUse, _) and
|
||||
adjacentDefRead(defOrUse, _)
|
||||
not exists(SourceVariable sv, IRBlock bb2, int i2 |
|
||||
nodeToDefOrUse(nTo, sv, bb2, i2, _) and
|
||||
adjacentDefRead(bb2, i2, sv, _, _)
|
||||
) and
|
||||
(
|
||||
exists(Operand op1, Operand op2, int indirectionIndex, Instruction instr |
|
||||
@@ -774,60 +756,39 @@ private predicate indirectConversionFlowStep(Node nFrom, Node nTo) {
|
||||
* So this predicate recurses back along conversions and `PointerArithmeticInstruction`s to find the
|
||||
* first use that has provides use-use flow, and uses that target as the target of the `nodeFrom`.
|
||||
*/
|
||||
private predicate adjustForPointerArith(PostUpdateNode pun, UseOrPhi use) {
|
||||
exists(DefOrUse defOrUse, Node adjusted |
|
||||
private predicate adjustForPointerArith(PostUpdateNode pun, SourceVariable sv, IRBlock bb2, int i2) {
|
||||
exists(IRBlock bb1, int i1, Node adjusted |
|
||||
indirectConversionFlowStep*(adjusted, pun.getPreUpdateNode()) and
|
||||
nodeToDefOrUse(adjusted, defOrUse, _) and
|
||||
adjacentDefRead(defOrUse, use)
|
||||
nodeToDefOrUse(adjusted, sv, bb1, i1, _) and
|
||||
adjacentDefRead(bb1, i1, sv, bb2, i2)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `nodeFrom` flows to `nodeTo` because there is `def-use` or
|
||||
* `use-use` flow from `defOrUse` to `use`.
|
||||
* Holds if there should be flow from `nodeFrom` to `nodeTo` because
|
||||
* `nodeFrom` is a definition or use of `sv` at index `i1` at basic
|
||||
* block `bb1`.
|
||||
*
|
||||
* `uncertain` is `true` if the `defOrUse` is an uncertain definition.
|
||||
* `uncertain` is `true` if `(bb1, i1)` is a definition, and that definition
|
||||
* is _not_ guaranteed to overwrite the entire allocation.
|
||||
*/
|
||||
private predicate localSsaFlow(
|
||||
SsaDefOrUse defOrUse, Node nodeFrom, UseOrPhi use, Node nodeTo, boolean uncertain
|
||||
private predicate ssaFlowImpl(
|
||||
IRBlock bb1, int i1, SourceVariable sv, Node nodeFrom, Node nodeTo, boolean uncertain
|
||||
) {
|
||||
nodeToDefOrUse(nodeFrom, defOrUse, uncertain) and
|
||||
adjacentDefRead(defOrUse, use) and
|
||||
useToNode(use, nodeTo) and
|
||||
exists(IRBlock bb2, int i2 |
|
||||
nodeToDefOrUse(nodeFrom, sv, bb1, i1, uncertain) and
|
||||
adjacentDefRead(bb1, i1, sv, bb2, i2) and
|
||||
useToNode(bb2, i2, sv, nodeTo)
|
||||
) and
|
||||
nodeFrom != nodeTo
|
||||
}
|
||||
|
||||
private predicate ssaFlowImpl(SsaDefOrUse defOrUse, Node nodeFrom, Node nodeTo, boolean uncertain) {
|
||||
exists(UseOrPhi use |
|
||||
localSsaFlow(defOrUse, nodeFrom, use, nodeTo, uncertain)
|
||||
or
|
||||
// Initial global variable value to a first use
|
||||
nodeFrom.(InitialGlobalValue).getGlobalDef() = defOrUse and
|
||||
globalDefToUse(defOrUse, use) and
|
||||
useToNode(use, nodeTo) and
|
||||
uncertain = false
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `def` is the corresponding definition of
|
||||
* the SSA library's `definition`.
|
||||
*/
|
||||
private DefinitionExt ssaDefinition(Def def) {
|
||||
exists(IRBlock block, int i, SourceVariable sv |
|
||||
def.hasIndexInBlock(block, i, sv) and
|
||||
result.definesAt(sv, block, i, _)
|
||||
)
|
||||
}
|
||||
|
||||
/** Gets a node that represents the prior definition of `node`. */
|
||||
private Node getAPriorDefinition(SsaDefOrUse defOrUse) {
|
||||
exists(IRBlock bb, int i, SourceVariable sv, DefinitionExt def, DefOrUse defOrUse0 |
|
||||
lastRefRedefExt(pragma[only_bind_into](def), pragma[only_bind_into](bb),
|
||||
pragma[only_bind_into](i), ssaDefinition(defOrUse)) and
|
||||
def.getSourceVariable() = sv and
|
||||
defOrUse0.hasIndexInBlock(bb, i, sv) and
|
||||
nodeToDefOrUse(result, defOrUse0, _)
|
||||
private Node getAPriorDefinition(DefinitionExt next) {
|
||||
exists(IRBlock bb, int i, SourceVariable sv |
|
||||
lastRefRedefExt(_, pragma[only_bind_into](sv), pragma[only_bind_into](bb),
|
||||
pragma[only_bind_into](i), next) and
|
||||
nodeToDefOrUse(result, sv, bb, i, _)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -879,12 +840,16 @@ private predicate modeledFlowBarrier(Node n) {
|
||||
|
||||
/** Holds if there is def-use or use-use flow from `nodeFrom` to `nodeTo`. */
|
||||
predicate ssaFlow(Node nodeFrom, Node nodeTo) {
|
||||
exists(Node nFrom, boolean uncertain, SsaDefOrUse defOrUse |
|
||||
ssaFlowImpl(defOrUse, nFrom, nodeTo, uncertain) and
|
||||
exists(Node nFrom, boolean uncertain, IRBlock bb, int i, SourceVariable sv |
|
||||
ssaFlowImpl(bb, i, sv, nFrom, nodeTo, uncertain) and
|
||||
not modeledFlowBarrier(nFrom) and
|
||||
nodeFrom != nodeTo
|
||||
|
|
||||
if uncertain = true then nodeFrom = [nFrom, getAPriorDefinition(defOrUse)] else nodeFrom = nFrom
|
||||
if uncertain = true
|
||||
then
|
||||
nodeFrom =
|
||||
[nFrom, getAPriorDefinition(any(DefinitionExt next | next.definesAt(sv, bb, i, _)))]
|
||||
else nodeFrom = nFrom
|
||||
)
|
||||
}
|
||||
|
||||
@@ -929,15 +894,15 @@ private predicate isArgumentOfCallable(DataFlowCall call, Node n) {
|
||||
* Holds if there is use-use flow from `pun`'s pre-update node to `n`.
|
||||
*/
|
||||
private predicate postUpdateNodeToFirstUse(PostUpdateNode pun, Node n) {
|
||||
exists(UseOrPhi use |
|
||||
adjustForPointerArith(pun, use) and
|
||||
useToNode(use, n)
|
||||
exists(SourceVariable sv, IRBlock bb2, int i2 |
|
||||
adjustForPointerArith(pun, sv, bb2, i2) and
|
||||
useToNode(bb2, i2, sv, n)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate stepUntilNotInCall(DataFlowCall call, Node n1, Node n2) {
|
||||
isArgumentOfCallable(call, n1) and
|
||||
exists(Node mid | localSsaFlow(_, n1, _, mid, _) |
|
||||
exists(Node mid | ssaFlowImpl(_, _, _, n1, mid, _) |
|
||||
isArgumentOfCallable(call, mid) and
|
||||
stepUntilNotInCall(call, mid, n2)
|
||||
or
|
||||
@@ -984,35 +949,13 @@ predicate postUpdateFlow(PostUpdateNode pun, Node nodeTo) {
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `use` is a use of `sv` and is a next adjacent use of `phi` in
|
||||
* index `i1` in basic block `bb1`.
|
||||
*
|
||||
* This predicate exists to prevent an early join of `adjacentDefRead` with `definesAt`.
|
||||
*/
|
||||
pragma[nomagic]
|
||||
private predicate fromPhiNodeToUse(PhiNode phi, SourceVariable sv, IRBlock bb1, int i1, UseOrPhi use) {
|
||||
exists(IRBlock bb2, int i2 |
|
||||
use.asDefOrUse().hasIndexInBlock(bb2, i2, sv) and
|
||||
adjacentDefReadExt(pragma[only_bind_into](phi), pragma[only_bind_into](bb1),
|
||||
pragma[only_bind_into](i1), pragma[only_bind_into](bb2), pragma[only_bind_into](i2))
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `nodeTo` receives flow from the phi node `nodeFrom`. */
|
||||
predicate fromPhiNode(SsaPhiNode nodeFrom, Node nodeTo) {
|
||||
exists(PhiNode phi, SourceVariable sv, IRBlock bb1, int i1, UseOrPhi use |
|
||||
exists(PhiNode phi, SourceVariable sv, IRBlock bb1, int i1, IRBlock bb2, int i2 |
|
||||
phi = nodeFrom.getPhiNode() and
|
||||
phi.definesAt(sv, bb1, i1, _) and
|
||||
useToNode(use, nodeTo)
|
||||
|
|
||||
fromPhiNodeToUse(phi, sv, bb1, i1, use)
|
||||
or
|
||||
exists(PhiNode phiTo |
|
||||
phi != phiTo and
|
||||
lastRefRedefExt(phi, bb1, i1, phiTo) and
|
||||
nodeTo.(SsaPhiNode).getPhiNode() = phiTo
|
||||
)
|
||||
adjacentDefRead(bb1, i1, sv, bb2, i2) and
|
||||
useToNode(bb2, i2, sv, nodeTo)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1077,8 +1020,10 @@ module SsaCached {
|
||||
* path between them without any read of `def`.
|
||||
*/
|
||||
cached
|
||||
predicate adjacentDefReadExt(DefinitionExt def, IRBlock bb1, int i1, IRBlock bb2, int i2) {
|
||||
SsaImpl::adjacentDefReadExt(def, _, bb1, i1, bb2, i2)
|
||||
predicate adjacentDefReadExt(
|
||||
DefinitionExt def, SourceVariable sv, IRBlock bb1, int i1, IRBlock bb2, int i2
|
||||
) {
|
||||
SsaImpl::adjacentDefReadExt(def, sv, bb1, i1, bb2, i2)
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1087,32 +1032,38 @@ module SsaCached {
|
||||
* without passing through another read or write.
|
||||
*/
|
||||
cached
|
||||
predicate lastRefRedefExt(DefinitionExt def, IRBlock bb, int i, DefinitionExt next) {
|
||||
SsaImpl::lastRefRedefExt(def, _, bb, i, next)
|
||||
predicate lastRefRedefExt(
|
||||
DefinitionExt def, SourceVariable sv, IRBlock bb, int i, DefinitionExt next
|
||||
) {
|
||||
SsaImpl::lastRefRedefExt(def, sv, bb, i, next)
|
||||
}
|
||||
|
||||
cached
|
||||
Definition phiHasInputFromBlock(PhiNode phi, IRBlock bb) {
|
||||
SsaImpl::phiHasInputFromBlock(phi, result, bb)
|
||||
}
|
||||
|
||||
cached
|
||||
predicate ssaDefReachesRead(SourceVariable v, Definition def, IRBlock bb, int i) {
|
||||
SsaImpl::ssaDefReachesRead(v, def, bb, i)
|
||||
}
|
||||
|
||||
predicate variableRead = SsaInput::variableRead/4;
|
||||
|
||||
predicate variableWrite = SsaInput::variableWrite/4;
|
||||
}
|
||||
|
||||
cached
|
||||
private newtype TSsaDefOrUse =
|
||||
TDefOrUse(DefOrUseImpl defOrUse) {
|
||||
defOrUse instanceof UseImpl
|
||||
or
|
||||
// Like in the pruning stage, we only include definition that's live after the
|
||||
// write as the final definitions computed by SSA.
|
||||
exists(DefinitionExt def, SourceVariable sv, IRBlock bb, int i |
|
||||
def.definesAt(sv, bb, i, _) and
|
||||
defOrUse.(DefImpl).hasIndexInBlock(bb, i, sv)
|
||||
)
|
||||
} or
|
||||
TPhi(PhiNode phi) or
|
||||
TGlobalDef(GlobalDefImpl global)
|
||||
private newtype TSsaDef =
|
||||
TDef(DefinitionExt def) or
|
||||
TPhi(PhiNode phi)
|
||||
|
||||
abstract private class SsaDefOrUse extends TSsaDefOrUse {
|
||||
abstract private class SsaDef extends TSsaDef {
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { none() }
|
||||
|
||||
/** Gets the underlying non-phi definition or use. */
|
||||
DefOrUseImpl asDefOrUse() { none() }
|
||||
DefinitionExt asDef() { none() }
|
||||
|
||||
/** Gets the underlying phi node. */
|
||||
PhiNode asPhi() { none() }
|
||||
@@ -1121,52 +1072,97 @@ abstract private class SsaDefOrUse extends TSsaDefOrUse {
|
||||
abstract Location getLocation();
|
||||
}
|
||||
|
||||
class DefOrUse extends TDefOrUse, SsaDefOrUse {
|
||||
DefOrUseImpl defOrUse;
|
||||
abstract class Def extends SsaDef, TDef {
|
||||
DefinitionExt def;
|
||||
|
||||
DefOrUse() { this = TDefOrUse(defOrUse) }
|
||||
Def() { this = TDef(def) }
|
||||
|
||||
final override DefOrUseImpl asDefOrUse() { result = defOrUse }
|
||||
final override DefinitionExt asDef() { result = def }
|
||||
|
||||
final override Location getLocation() { result = defOrUse.getLocation() }
|
||||
/** Gets the source variable underlying this SSA definition. */
|
||||
final SourceVariable getSourceVariable() { result = def.getSourceVariable() }
|
||||
|
||||
final SourceVariable getSourceVariable() { result = defOrUse.getSourceVariable() }
|
||||
|
||||
override string toString() { result = defOrUse.toString() }
|
||||
override string toString() { result = def.toString() }
|
||||
|
||||
/**
|
||||
* Holds if this definition (or use) has index `index` in block `block`,
|
||||
* and is a definition (or use) of the variable `sv`.
|
||||
*/
|
||||
predicate hasIndexInBlock(IRBlock block, int index, SourceVariable sv) {
|
||||
defOrUse.hasIndexInBlock(block, index, sv)
|
||||
def.definesAt(sv, block, index, _)
|
||||
}
|
||||
|
||||
/** Gets the value written by this definition, if any. */
|
||||
Node0Impl getValue() { none() }
|
||||
|
||||
/**
|
||||
* Holds if this definition is guaranteed to overwrite the entire
|
||||
* destination's allocation.
|
||||
*/
|
||||
abstract predicate isCertain();
|
||||
|
||||
/** Gets the address operand written to by this definition. */
|
||||
Operand getAddressOperand() { none() }
|
||||
|
||||
/** Gets the address written to by this definition. */
|
||||
final Instruction getAddress() { result = this.getAddressOperand().getDef() }
|
||||
|
||||
/** Gets the indirection index of this definition. */
|
||||
abstract int getIndirectionIndex();
|
||||
|
||||
/**
|
||||
* Gets the indirection level that this definition is writing to.
|
||||
* For instance, `x = y` is a definition of `x` at indirection level 1 and
|
||||
* `*x = y` is a definition of `x` at indirection level 2.
|
||||
*/
|
||||
abstract int getIndirection();
|
||||
|
||||
/**
|
||||
* Gets a definition that ultimately defines this SSA definition and is not
|
||||
* itself a phi node.
|
||||
*/
|
||||
Def getAnUltimateDefinition() { result.asDef() = def.getAnUltimateDefinition() }
|
||||
}
|
||||
|
||||
class GlobalDef extends TGlobalDef, SsaDefOrUse {
|
||||
private predicate isGlobal(DefinitionExt def, GlobalDefImpl global) {
|
||||
exists(SourceVariable sv, IRBlock bb, int i |
|
||||
def.definesAt(sv, bb, i, _) and
|
||||
global.hasIndexInBlock(bb, i, sv)
|
||||
)
|
||||
}
|
||||
|
||||
private class NonGlobalDef extends Def {
|
||||
NonGlobalDef() { not isGlobal(def, _) }
|
||||
|
||||
final override Location getLocation() { result = this.getImpl().getLocation() }
|
||||
|
||||
private DefImpl getImpl() {
|
||||
exists(SourceVariable sv, IRBlock bb, int i |
|
||||
this.hasIndexInBlock(bb, i, sv) and
|
||||
result.hasIndexInBlock(bb, i, sv)
|
||||
)
|
||||
}
|
||||
|
||||
override Node0Impl getValue() { result = this.getImpl().getValue() }
|
||||
|
||||
override predicate isCertain() { this.getImpl().isCertain() }
|
||||
|
||||
override Operand getAddressOperand() { result = this.getImpl().getAddressOperand() }
|
||||
|
||||
override int getIndirectionIndex() { result = this.getImpl().getIndirectionIndex() }
|
||||
|
||||
override int getIndirection() { result = this.getImpl().getIndirection() }
|
||||
}
|
||||
|
||||
class GlobalDef extends Def {
|
||||
GlobalDefImpl global;
|
||||
|
||||
GlobalDef() { this = TGlobalDef(global) }
|
||||
|
||||
/** Gets the location of this definition. */
|
||||
final override Location getLocation() { result = global.getLocation() }
|
||||
GlobalDef() { isGlobal(def, global) }
|
||||
|
||||
/** Gets a textual representation of this definition. */
|
||||
override string toString() { result = global.toString() }
|
||||
|
||||
/**
|
||||
* Holds if this definition has index `index` in block `block`, and
|
||||
* is a definition of the variable `sv`.
|
||||
*/
|
||||
predicate hasIndexInBlock(IRBlock block, int index, SourceVariable sv) {
|
||||
global.hasIndexInBlock(block, index, sv)
|
||||
}
|
||||
|
||||
/** Gets the indirection index of this definition. */
|
||||
int getIndirection() { result = global.getIndirection() }
|
||||
|
||||
/** Gets the indirection index of this definition. */
|
||||
int getIndirectionIndex() { result = global.getIndirectionIndex() }
|
||||
final override Location getLocation() { result = global.getLocation() }
|
||||
|
||||
/**
|
||||
* Gets the type of this definition after specifiers have been deeply stripped
|
||||
@@ -1184,9 +1180,15 @@ class GlobalDef extends TGlobalDef, SsaDefOrUse {
|
||||
|
||||
/** Gets the global variable associated with this definition. */
|
||||
GlobalLikeVariable getVariable() { result = global.getVariable() }
|
||||
|
||||
override predicate isCertain() { any() }
|
||||
|
||||
final override int getIndirectionIndex() { result = global.getIndirectionIndex() }
|
||||
|
||||
final override int getIndirection() { result = global.getIndirection() }
|
||||
}
|
||||
|
||||
class Phi extends TPhi, SsaDefOrUse {
|
||||
class Phi extends TPhi, SsaDef {
|
||||
PhiNode phi;
|
||||
|
||||
Phi() { this = TPhi(phi) }
|
||||
@@ -1198,64 +1200,19 @@ class Phi extends TPhi, SsaDefOrUse {
|
||||
override string toString() { result = "Phi" }
|
||||
|
||||
SsaPhiNode getNode() { result.getPhiNode() = phi }
|
||||
}
|
||||
|
||||
class UseOrPhi extends SsaDefOrUse {
|
||||
UseOrPhi() {
|
||||
this.asDefOrUse() instanceof UseImpl
|
||||
or
|
||||
this instanceof Phi
|
||||
}
|
||||
predicate hasInputFromBlock(Definition inp, IRBlock bb) { inp = phiHasInputFromBlock(phi, bb) }
|
||||
|
||||
final override Location getLocation() {
|
||||
result = this.asDefOrUse().getLocation() or result = this.(Phi).getLocation()
|
||||
}
|
||||
|
||||
final Node getNode() {
|
||||
result = this.(Phi).getNode()
|
||||
or
|
||||
result = this.asDefOrUse().(UseImpl).getNode()
|
||||
}
|
||||
}
|
||||
|
||||
class Def extends DefOrUse {
|
||||
override DefImpl defOrUse;
|
||||
|
||||
Operand getAddressOperand() { result = defOrUse.(OperandBasedDef).getAddressOperand() }
|
||||
|
||||
Instruction getAddress() { result = this.getAddressOperand().getDef() }
|
||||
|
||||
/**
|
||||
* Gets the indirection index of this definition.
|
||||
*
|
||||
* This predicate ensures that joins go from `defOrUse` to the result
|
||||
* instead of the other way around.
|
||||
*/
|
||||
pragma[inline]
|
||||
int getIndirectionIndex() {
|
||||
pragma[only_bind_into](result) = pragma[only_bind_out](defOrUse).getIndirectionIndex()
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the indirection level that this definition is writing to.
|
||||
* For instance, `x = y` is a definition of `x` at indirection level 1 and
|
||||
* `*x = y` is a definition of `x` at indirection level 2.
|
||||
*
|
||||
* This predicate ensures that joins go from `defOrUse` to the result
|
||||
* instead of the other way around.
|
||||
*/
|
||||
pragma[inline]
|
||||
int getIndirection() {
|
||||
pragma[only_bind_into](result) = pragma[only_bind_out](defOrUse).getIndirection()
|
||||
}
|
||||
|
||||
Node0Impl getValue() { result = defOrUse.getValue() }
|
||||
|
||||
predicate isCertain() { defOrUse.isCertain() }
|
||||
final Definition getAnInput() { this.hasInputFromBlock(result, _) }
|
||||
}
|
||||
|
||||
private module SsaImpl = SsaImplCommon::Make<Location, SsaInput>;
|
||||
|
||||
/**
|
||||
* An static single assignment (SSA) phi node.
|
||||
*
|
||||
* This is either a normal phi node or a phi-read node.
|
||||
*/
|
||||
class PhiNode extends SsaImpl::DefinitionExt {
|
||||
PhiNode() {
|
||||
this instanceof SsaImpl::PhiNode or
|
||||
@@ -1269,10 +1226,30 @@ class PhiNode extends SsaImpl::DefinitionExt {
|
||||
* on reads instead of writes.
|
||||
*/
|
||||
predicate isPhiRead() { this instanceof SsaImpl::PhiReadNode }
|
||||
|
||||
/** Holds if `inp` is an input to this phi node along the edge originating in `bb`. */
|
||||
predicate hasInputFromBlock(Definition inp, IRBlock bb) {
|
||||
inp = SsaCached::phiHasInputFromBlock(this, bb)
|
||||
}
|
||||
|
||||
/** Gets a definition that is an input to this phi node. */
|
||||
final Definition getAnInput() { this.hasInputFromBlock(result, _) }
|
||||
}
|
||||
|
||||
class DefinitionExt = SsaImpl::DefinitionExt;
|
||||
/** An static single assignment (SSA) definition. */
|
||||
class DefinitionExt extends SsaImpl::DefinitionExt {
|
||||
private Definition getAPhiInputOrPriorDefinition() { result = this.(PhiNode).getAnInput() }
|
||||
|
||||
class UncertainWriteDefinition = SsaImpl::UncertainWriteDefinition;
|
||||
/**
|
||||
* Gets a definition that ultimately defines this SSA definition and is
|
||||
* not itself a phi node.
|
||||
*/
|
||||
final DefinitionExt getAnUltimateDefinition() {
|
||||
result = this.getAPhiInputOrPriorDefinition*() and
|
||||
not result instanceof PhiNode
|
||||
}
|
||||
}
|
||||
|
||||
class Definition = SsaImpl::Definition;
|
||||
|
||||
import SsaCached
|
||||
|
||||
@@ -246,14 +246,6 @@ private module IteratorIndirections {
|
||||
baseType = super.getValueType()
|
||||
}
|
||||
|
||||
override predicate isAdditionalDereference(Instruction deref, Operand address) {
|
||||
exists(CallInstruction call |
|
||||
operandForFullyConvertedCall(getAUse(deref), call) and
|
||||
this = call.getStaticCallTarget().getClassAndName("operator*") and
|
||||
address = call.getThisArgumentOperand()
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isAdditionalWrite(Node0Impl value, Operand address, boolean certain) {
|
||||
exists(CallInstruction call | call.getArgumentOperand(0) = value.asOperand() |
|
||||
this = call.getStaticCallTarget().getClassAndName("operator=") and
|
||||
@@ -262,16 +254,6 @@ private module IteratorIndirections {
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isAdditionalTaintStep(Node node1, Node node2) {
|
||||
exists(CallInstruction call |
|
||||
// Taint through `operator+=` and `operator-=` on iterators.
|
||||
call.getStaticCallTarget() instanceof Iterator::IteratorAssignArithmeticOperator and
|
||||
node2.(IndirectArgumentOutNode).getPreUpdateNode() = node1 and
|
||||
node1.(IndirectOperand).hasOperandAndIndirectionIndex(call.getArgumentOperand(0), _) and
|
||||
node1.getType().getUnspecifiedType() = this
|
||||
)
|
||||
}
|
||||
|
||||
override predicate isAdditionalConversionFlow(Operand opFrom, Instruction instrTo) {
|
||||
// This is a bit annoying: Consider the following snippet:
|
||||
// ```
|
||||
@@ -589,230 +571,6 @@ private class BaseCallInstruction extends BaseSourceVariableInstruction, CallIns
|
||||
|
||||
cached
|
||||
private module Cached {
|
||||
private import semmle.code.cpp.models.interfaces.Iterator as Interfaces
|
||||
private import semmle.code.cpp.models.implementations.Iterator as Iterator
|
||||
private import semmle.code.cpp.models.interfaces.FunctionInputsAndOutputs as IO
|
||||
|
||||
/**
|
||||
* Holds if `next` is a instruction with a memory result that potentially
|
||||
* updates the memory produced by `prev`.
|
||||
*/
|
||||
private predicate memorySucc(Instruction prev, Instruction next) {
|
||||
prev = next.(ChiInstruction).getTotal()
|
||||
or
|
||||
// Phi inputs can be inexact.
|
||||
prev = next.(PhiInstruction).getAnInputOperand().getAnyDef()
|
||||
or
|
||||
prev = next.(CopyInstruction).getSourceValue()
|
||||
or
|
||||
exists(ReadSideEffectInstruction read |
|
||||
next = read.getPrimaryInstruction() and
|
||||
isAdditionalConversionFlow(_, next) and
|
||||
prev = read.getSideEffectOperand().getAnyDef()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `iteratorDerefAddress` is an address of an iterator dereference (i.e., `*it`)
|
||||
* that is used for a write operation that writes the value `value`. The `memory` instruction
|
||||
* represents the memory that the IR's SSA analysis determined was read by the call to `operator*`.
|
||||
*
|
||||
* The `numberOfLoads` integer represents the number of dereferences this write corresponds to
|
||||
* on the underlying container that produced the iterator.
|
||||
*/
|
||||
private predicate isChiAfterIteratorDef(
|
||||
Instruction memory, Operand iteratorDerefAddress, Node0Impl value, int numberOfLoads
|
||||
) {
|
||||
exists(
|
||||
BaseSourceVariableInstruction iteratorBase, ReadSideEffectInstruction read,
|
||||
Operand iteratorAddress
|
||||
|
|
||||
numberOfLoads >= 0 and
|
||||
isDef(_, value, iteratorDerefAddress, iteratorBase, numberOfLoads + 2, 0) and
|
||||
isUse(_, iteratorAddress, iteratorBase, numberOfLoads + 1, 0) and
|
||||
iteratorBase.getResultType() instanceof Interfaces::Iterator and
|
||||
isDereference(iteratorAddress.getDef(), read.getArgumentDef().getAUse(), _) and
|
||||
memory = read.getSideEffectOperand().getAnyDef()
|
||||
)
|
||||
}
|
||||
|
||||
private predicate isSource(Instruction instr, Operand iteratorAddress, int numberOfLoads) {
|
||||
getAUse(instr) = iteratorAddress and
|
||||
exists(BaseSourceVariableInstruction iteratorBase |
|
||||
iteratorBase.getResultType() instanceof Interfaces::Iterator and
|
||||
not iteratorBase.getResultType() instanceof Cpp::PointerType and
|
||||
isUse(_, iteratorAddress, iteratorBase, numberOfLoads - 1, 0)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate isSink(Instruction instr, CallInstruction call) {
|
||||
getAUse(instr).(ArgumentOperand).getCall() = call and
|
||||
// Only include operations that may modify the object that the iterator points to.
|
||||
// The following is a non-exhaustive list of things that may modify the value of the
|
||||
// iterator, but never the value of what the iterator points to.
|
||||
// The more things we can exclude here, the faster the small dataflow-like analysis
|
||||
// done by `convertsIntoArgument` will converge.
|
||||
not exists(Function f | f = call.getStaticCallTarget() |
|
||||
f instanceof Iterator::IteratorCrementOperator or
|
||||
f instanceof Iterator::IteratorBinaryArithmeticOperator or
|
||||
f instanceof Iterator::IteratorAssignArithmeticOperator or
|
||||
f instanceof Iterator::IteratorCrementMemberOperator or
|
||||
f instanceof Iterator::IteratorBinaryArithmeticMemberOperator or
|
||||
f instanceof Iterator::IteratorAssignArithmeticMemberOperator or
|
||||
f instanceof Iterator::IteratorAssignmentMemberOperator
|
||||
)
|
||||
}
|
||||
|
||||
private predicate convertsIntoArgumentFwd(Instruction instr) {
|
||||
isSource(instr, _, _)
|
||||
or
|
||||
exists(Instruction prev | convertsIntoArgumentFwd(prev) |
|
||||
conversionFlow(unique( | | getAUse(prev)), instr, false, _)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate convertsIntoArgumentRev(Instruction instr) {
|
||||
convertsIntoArgumentFwd(instr) and
|
||||
(
|
||||
isSink(instr, _)
|
||||
or
|
||||
exists(Instruction next | convertsIntoArgumentRev(next) |
|
||||
conversionFlow(unique( | | getAUse(instr)), next, false, _)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate convertsIntoArgument(
|
||||
Operand iteratorAddress, CallInstruction call, int numberOfLoads
|
||||
) {
|
||||
exists(Instruction iteratorAddressDef |
|
||||
isSource(iteratorAddressDef, iteratorAddress, numberOfLoads) and
|
||||
isSink(iteratorAddressDef, call) and
|
||||
convertsIntoArgumentRev(pragma[only_bind_into](iteratorAddressDef))
|
||||
)
|
||||
}
|
||||
|
||||
private predicate isChiAfterIteratorArgument(
|
||||
Instruction memory, Operand iteratorAddress, int numberOfLoads
|
||||
) {
|
||||
// Ideally, `iteratorAddress` would be an `ArgumentOperand`, but there might be
|
||||
// various conversions applied to it before it becomes an argument.
|
||||
// So we do a small amount of flow to find the call that the iterator is passed to.
|
||||
exists(CallInstruction call | convertsIntoArgument(iteratorAddress, call, numberOfLoads) |
|
||||
exists(ReadSideEffectInstruction read |
|
||||
read.getPrimaryInstruction() = call and
|
||||
read.getSideEffectOperand().getAnyDef() = memory
|
||||
)
|
||||
or
|
||||
exists(LoadInstruction load |
|
||||
iteratorAddress.getDef() = load and
|
||||
memory = load.getSourceValueOperand().getAnyDef()
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `iterator` is a `StoreInstruction` that stores the result of some function
|
||||
* returning an iterator into an address computed started at `containerBase`.
|
||||
*
|
||||
* For example, given a declaration like `std::vector<int>::iterator it = v.begin()`,
|
||||
* the `iterator` will be the `StoreInstruction` generated by the write to `it`, and
|
||||
* `containerBase` will be the address of `v`.
|
||||
*/
|
||||
private predicate isChiAfterBegin(
|
||||
BaseSourceVariableInstruction containerBase, StoreInstruction iterator
|
||||
) {
|
||||
exists(
|
||||
CallInstruction getIterator, Iterator::GetIteratorFunction getIteratorFunction,
|
||||
IO::FunctionInput input, int i
|
||||
|
|
||||
getIterator = iterator.getSourceValue() and
|
||||
getIteratorFunction = getIterator.getStaticCallTarget() and
|
||||
getIteratorFunction.getsIterator(input, _) and
|
||||
isDef(_, any(Node0Impl n | n.asInstruction() = iterator), _, _, 1, 0) and
|
||||
input.isParameterDerefOrQualifierObject(i) and
|
||||
isUse(_, getIterator.getArgumentOperand(i), containerBase, 0, 0)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `iteratorAddress` is an address of an iterator that is used for
|
||||
* a read operation. The `memory` instruction represents the memory that
|
||||
* the IR's SSA analysis determined was read by the call to `operator*`.
|
||||
*
|
||||
* Finally, the `numberOfLoads` integer represents the number of dereferences
|
||||
* this read corresponds to on the underlying container that produced the iterator.
|
||||
*/
|
||||
private predicate isChiBeforeIteratorUse(
|
||||
Operand iteratorAddress, Instruction memory, int numberOfLoads
|
||||
) {
|
||||
exists(
|
||||
BaseSourceVariableInstruction iteratorBase, LoadInstruction load,
|
||||
ReadSideEffectInstruction read, Operand iteratorDerefAddress
|
||||
|
|
||||
numberOfLoads >= 0 and
|
||||
isUse(_, iteratorAddress, iteratorBase, numberOfLoads + 1, 0) and
|
||||
isUse(_, iteratorDerefAddress, iteratorBase, numberOfLoads + 2, 0) and
|
||||
iteratorBase.getResultType() instanceof Interfaces::Iterator and
|
||||
load.getSourceAddressOperand() = iteratorDerefAddress and
|
||||
read.getPrimaryInstruction() = load.getSourceAddress() and
|
||||
memory = read.getSideEffectOperand().getAnyDef()
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `iteratorDerefAddress` is an address of an iterator dereference (i.e., `*it`)
|
||||
* that is used for a write operation that writes the value `value` to a container that
|
||||
* created the iterator. `container` represents the base of the address of the container
|
||||
* that was used to create the iterator.
|
||||
*/
|
||||
cached
|
||||
predicate isIteratorDef(
|
||||
BaseSourceVariableInstruction container, Operand iteratorDerefAddress, Node0Impl value,
|
||||
int numberOfLoads, int indirectionIndex
|
||||
) {
|
||||
exists(Instruction memory, Instruction begin, int upper, int ind |
|
||||
isChiAfterIteratorDef(memory, iteratorDerefAddress, value, numberOfLoads) and
|
||||
memorySucc*(begin, memory) and
|
||||
isChiAfterBegin(container, begin) and
|
||||
upper = countIndirectionsForCppType(getResultLanguageType(container)) and
|
||||
ind = numberOfLoads + [1 .. upper] and
|
||||
indirectionIndex = ind - (numberOfLoads + 1)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `iteratorAddress` is an address of an iterator that is used for a
|
||||
* read operation to read a value from a container that created the iterator.
|
||||
* `container` represents the base of the address of the container that was used
|
||||
* to create the iterator.
|
||||
*/
|
||||
cached
|
||||
predicate isIteratorUse(
|
||||
BaseSourceVariableInstruction container, Operand iteratorAddress, int numberOfLoads,
|
||||
int indirectionIndex
|
||||
) {
|
||||
// Direct use
|
||||
exists(Instruction begin, Instruction memory, int upper, int ind |
|
||||
isChiBeforeIteratorUse(iteratorAddress, memory, numberOfLoads) and
|
||||
memorySucc*(begin, memory) and
|
||||
isChiAfterBegin(container, begin) and
|
||||
upper = countIndirectionsForCppType(getResultLanguageType(container)) and
|
||||
ind = numberOfLoads + [1 .. upper] and
|
||||
indirectionIndex = ind - (numberOfLoads + 1)
|
||||
)
|
||||
or
|
||||
// Use through function output
|
||||
exists(Instruction memory, Instruction begin, int upper, int ind |
|
||||
isChiAfterIteratorArgument(memory, iteratorAddress, numberOfLoads) and
|
||||
memorySucc*(begin, memory) and
|
||||
isChiAfterBegin(container, begin) and
|
||||
upper = countIndirectionsForCppType(getResultLanguageType(container)) and
|
||||
ind = numberOfLoads + [1 .. upper] and
|
||||
indirectionIndex = ind - (numberOfLoads - 1)
|
||||
)
|
||||
}
|
||||
|
||||
/** Holds if `op` is the only use of its defining instruction, and that op is used in a conversation */
|
||||
private predicate isConversion(Operand op) {
|
||||
exists(Instruction def, Operand use |
|
||||
|
||||
@@ -17,18 +17,11 @@ private import Imports::IRType
|
||||
* The variable may be a user-declared variable (`IRUserVariable`) or a temporary variable generated
|
||||
* by the AST-to-IR translation (`IRTempVariable`).
|
||||
*/
|
||||
class IRVariable extends TIRVariable {
|
||||
abstract private class AbstractIRVariable extends TIRVariable {
|
||||
Language::Declaration func;
|
||||
|
||||
IRVariable() {
|
||||
this = TIRUserVariable(_, _, func) or
|
||||
this = TIRTempVariable(func, _, _, _) or
|
||||
this = TIRStringLiteral(func, _, _, _) or
|
||||
this = TIRDynamicInitializationFlag(func, _, _)
|
||||
}
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { none() }
|
||||
abstract string toString();
|
||||
|
||||
/**
|
||||
* Holds if this variable's value cannot be changed within a function. Currently used for string
|
||||
@@ -49,13 +42,13 @@ class IRVariable extends TIRVariable {
|
||||
/**
|
||||
* Gets the type of the variable.
|
||||
*/
|
||||
Language::LanguageType getLanguageType() { none() }
|
||||
abstract Language::LanguageType getLanguageType();
|
||||
|
||||
/**
|
||||
* Gets the AST node that declared this variable, or that introduced this
|
||||
* variable as part of the AST-to-IR translation.
|
||||
*/
|
||||
Language::AST getAst() { none() }
|
||||
abstract Language::AST getAst();
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated Language::AST getAST() { result = this.getAst() }
|
||||
@@ -64,7 +57,7 @@ class IRVariable extends TIRVariable {
|
||||
* Gets an identifier string for the variable. This identifier is unique
|
||||
* within the function.
|
||||
*/
|
||||
string getUniqueId() { none() }
|
||||
abstract string getUniqueId();
|
||||
|
||||
/**
|
||||
* Gets the source location of this variable.
|
||||
@@ -74,7 +67,7 @@ class IRVariable extends TIRVariable {
|
||||
/**
|
||||
* Gets the IR for the function that references this variable.
|
||||
*/
|
||||
final IRFunction getEnclosingIRFunction() { result.getFunction() = func }
|
||||
final IRFunction getEnclosingIRFunction() { result.getFunction() = this.getEnclosingFunction() }
|
||||
|
||||
/**
|
||||
* Gets the function that references this variable.
|
||||
@@ -82,10 +75,18 @@ class IRVariable extends TIRVariable {
|
||||
final Language::Declaration getEnclosingFunction() { result = func }
|
||||
}
|
||||
|
||||
/**
|
||||
* A variable referenced by the IR for a function.
|
||||
*
|
||||
* The variable may be a user-declared variable (`IRUserVariable`) or a temporary variable generated
|
||||
* by the AST-to-IR translation (`IRTempVariable`).
|
||||
*/
|
||||
final class IRVariable = AbstractIRVariable;
|
||||
|
||||
/**
|
||||
* A user-declared variable referenced by the IR for a function.
|
||||
*/
|
||||
class IRUserVariable extends IRVariable, TIRUserVariable {
|
||||
class IRUserVariable extends AbstractIRVariable, TIRUserVariable {
|
||||
Language::Variable var;
|
||||
Language::LanguageType type;
|
||||
|
||||
@@ -114,26 +115,29 @@ class IRUserVariable extends IRVariable, TIRUserVariable {
|
||||
* A variable (user-declared or temporary) that is allocated on the stack. This includes all
|
||||
* parameters, non-static local variables, and temporary variables.
|
||||
*/
|
||||
class IRAutomaticVariable extends IRVariable {
|
||||
IRAutomaticVariable() {
|
||||
exists(Language::Variable var |
|
||||
this = TIRUserVariable(var, _, func) and
|
||||
Language::isVariableAutomatic(var)
|
||||
)
|
||||
or
|
||||
this = TIRTempVariable(func, _, _, _)
|
||||
}
|
||||
abstract private class AbstractIRAutomaticVariable extends AbstractIRVariable { }
|
||||
|
||||
/**
|
||||
* A variable (user-declared or temporary) that is allocated on the stack. This includes all
|
||||
* parameters, non-static local variables, and temporary variables.
|
||||
*/
|
||||
final class IRAutomaticVariable = AbstractIRAutomaticVariable;
|
||||
|
||||
/**
|
||||
* A user-declared variable that is allocated on the stack. This includes all parameters and
|
||||
* non-static local variables.
|
||||
*/
|
||||
private class AbstractIRAutomaticUserVariable extends IRUserVariable, AbstractIRAutomaticVariable {
|
||||
override Language::AutomaticVariable var;
|
||||
|
||||
final override Language::AutomaticVariable getVariable() { result = var }
|
||||
}
|
||||
|
||||
/**
|
||||
* A user-declared variable that is allocated on the stack. This includes all parameters and
|
||||
* non-static local variables.
|
||||
*/
|
||||
class IRAutomaticUserVariable extends IRUserVariable, IRAutomaticVariable {
|
||||
override Language::AutomaticVariable var;
|
||||
|
||||
final override Language::AutomaticVariable getVariable() { result = var }
|
||||
}
|
||||
final class IRAutomaticUserVariable = AbstractIRAutomaticUserVariable;
|
||||
|
||||
/**
|
||||
* A user-declared variable that is not allocated on the stack. This includes all global variables,
|
||||
@@ -151,16 +155,10 @@ class IRStaticUserVariable extends IRUserVariable {
|
||||
* A variable that is not user-declared. This includes temporary variables generated as part of IR
|
||||
* construction, as well as string literals.
|
||||
*/
|
||||
class IRGeneratedVariable extends IRVariable {
|
||||
abstract private class AbstractIRGeneratedVariable extends AbstractIRVariable {
|
||||
Language::AST ast;
|
||||
Language::LanguageType type;
|
||||
|
||||
IRGeneratedVariable() {
|
||||
this = TIRTempVariable(func, ast, _, type) or
|
||||
this = TIRStringLiteral(func, ast, type, _) or
|
||||
this = TIRDynamicInitializationFlag(func, ast, type)
|
||||
}
|
||||
|
||||
final override Language::LanguageType getLanguageType() { result = type }
|
||||
|
||||
final override Language::AST getAst() { result = ast }
|
||||
@@ -196,12 +194,20 @@ class IRGeneratedVariable extends IRVariable {
|
||||
string getBaseString() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A variable that is not user-declared. This includes temporary variables generated as part of IR
|
||||
* construction, as well as string literals.
|
||||
*/
|
||||
final class IRGeneratedVariable = AbstractIRGeneratedVariable;
|
||||
|
||||
/**
|
||||
* A temporary variable introduced by IR construction. The most common examples are the variable
|
||||
* generated to hold the return value of a function, or the variable generated to hold the result of
|
||||
* a condition operator (`a ? b : c`).
|
||||
*/
|
||||
class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVariable {
|
||||
class IRTempVariable extends AbstractIRGeneratedVariable, AbstractIRAutomaticVariable,
|
||||
TIRTempVariable
|
||||
{
|
||||
TempVariableTag tag;
|
||||
|
||||
IRTempVariable() { this = TIRTempVariable(func, ast, tag, type) }
|
||||
@@ -241,7 +247,7 @@ class IRThrowVariable extends IRTempVariable {
|
||||
* A temporary variable generated to hold the contents of all arguments passed to the `...` of a
|
||||
* function that accepts a variable number of arguments.
|
||||
*/
|
||||
class IREllipsisVariable extends IRTempVariable, IRParameter {
|
||||
class IREllipsisVariable extends IRTempVariable, AbstractIRParameter {
|
||||
IREllipsisVariable() { tag = EllipsisTempVar() }
|
||||
|
||||
final override string toString() { result = "#ellipsis" }
|
||||
@@ -252,7 +258,7 @@ class IREllipsisVariable extends IRTempVariable, IRParameter {
|
||||
/**
|
||||
* A temporary variable generated to hold the `this` pointer.
|
||||
*/
|
||||
class IRThisVariable extends IRTempVariable, IRParameter {
|
||||
class IRThisVariable extends IRTempVariable, AbstractIRParameter {
|
||||
IRThisVariable() { tag = ThisTempVar() }
|
||||
|
||||
final override string toString() { result = "#this" }
|
||||
@@ -264,7 +270,7 @@ class IRThisVariable extends IRTempVariable, IRParameter {
|
||||
* A variable generated to represent the contents of a string literal. This variable acts much like
|
||||
* a read-only global variable.
|
||||
*/
|
||||
class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral {
|
||||
class IRStringLiteral extends AbstractIRGeneratedVariable, TIRStringLiteral {
|
||||
Language::StringLiteral literal;
|
||||
|
||||
IRStringLiteral() { this = TIRStringLiteral(func, ast, type, literal) }
|
||||
@@ -288,7 +294,7 @@ class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral {
|
||||
* used to model the runtime initialization of static local variables in C++, as well as static
|
||||
* fields in C#.
|
||||
*/
|
||||
class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitializationFlag {
|
||||
class IRDynamicInitializationFlag extends AbstractIRGeneratedVariable, TIRDynamicInitializationFlag {
|
||||
Language::Variable var;
|
||||
|
||||
IRDynamicInitializationFlag() {
|
||||
@@ -314,24 +320,24 @@ class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitial
|
||||
* An IR variable which acts like a function parameter, including positional parameters and the
|
||||
* temporary variables generated for `this` and ellipsis parameters.
|
||||
*/
|
||||
class IRParameter extends IRAutomaticVariable {
|
||||
IRParameter() {
|
||||
this.(IRAutomaticUserVariable).getVariable() instanceof Language::Parameter
|
||||
or
|
||||
this = TIRTempVariable(_, _, ThisTempVar(), _)
|
||||
or
|
||||
this = TIRTempVariable(_, _, EllipsisTempVar(), _)
|
||||
}
|
||||
|
||||
abstract private class AbstractIRParameter extends AbstractIRAutomaticVariable {
|
||||
/**
|
||||
* Gets the zero-based index of this parameter. The `this` parameter has index -1.
|
||||
*/
|
||||
int getIndex() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An IR variable which acts like a function parameter, including positional parameters and the
|
||||
* temporary variables generated for `this` and ellipsis parameters.
|
||||
*/
|
||||
final class IRParameter = AbstractIRParameter;
|
||||
|
||||
/**
|
||||
* An IR variable representing a positional parameter.
|
||||
*/
|
||||
class IRPositionalParameter extends IRParameter, IRAutomaticUserVariable {
|
||||
class IRPositionalParameter extends AbstractIRParameter, AbstractIRAutomaticUserVariable {
|
||||
IRPositionalParameter() { this.getVariable() instanceof Language::Parameter }
|
||||
|
||||
final override int getIndex() { result = this.getVariable().(Language::Parameter).getIndex() }
|
||||
}
|
||||
|
||||
@@ -247,8 +247,7 @@ class Instruction extends Construction::TStageInstruction {
|
||||
* Gets the type of the result produced by this instruction. If the instruction does not produce
|
||||
* a result, its result type will be `IRVoidType`.
|
||||
*/
|
||||
cached
|
||||
final IRType getResultIRType() { result = this.getResultLanguageType().getIRType() }
|
||||
final IRType getResultIRType() { result = Construction::getInstructionResultIRType(this) }
|
||||
|
||||
/**
|
||||
* Gets the type of the result produced by this instruction. If the
|
||||
@@ -995,9 +994,8 @@ class ConstantInstruction extends ConstantValueInstruction {
|
||||
*/
|
||||
class IntegerConstantInstruction extends ConstantInstruction {
|
||||
IntegerConstantInstruction() {
|
||||
exists(IRType resultType |
|
||||
resultType = this.getResultIRType() and
|
||||
(resultType instanceof IRIntegerType or resultType instanceof IRBooleanType)
|
||||
exists(IRType resultType | resultType = this.getResultIRType() |
|
||||
resultType instanceof IRIntegerType or resultType instanceof IRBooleanType
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1009,6 +1007,17 @@ class FloatConstantInstruction extends ConstantInstruction {
|
||||
FloatConstantInstruction() { this.getResultIRType() instanceof IRFloatingPointType }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction whose result is a constant value of a pointer type.
|
||||
*/
|
||||
class PointerConstantInstruction extends ConstantInstruction {
|
||||
PointerConstantInstruction() {
|
||||
exists(IRType resultType | resultType = this.getResultIRType() |
|
||||
resultType instanceof IRAddressType or resultType instanceof IRFunctionAddressType
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction whose result is the address of a string literal.
|
||||
*/
|
||||
|
||||
@@ -429,6 +429,11 @@ private module Cached {
|
||||
instr = unreachedInstruction(_) and result = Language::getVoidType()
|
||||
}
|
||||
|
||||
cached
|
||||
IRType getInstructionResultIRType(Instruction instr) {
|
||||
result = instr.getResultLanguageType().getIRType()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `opcode` is the opcode that specifies the operation performed by `instr`.
|
||||
*
|
||||
|
||||
@@ -17,18 +17,11 @@ private import Imports::IRType
|
||||
* The variable may be a user-declared variable (`IRUserVariable`) or a temporary variable generated
|
||||
* by the AST-to-IR translation (`IRTempVariable`).
|
||||
*/
|
||||
class IRVariable extends TIRVariable {
|
||||
abstract private class AbstractIRVariable extends TIRVariable {
|
||||
Language::Declaration func;
|
||||
|
||||
IRVariable() {
|
||||
this = TIRUserVariable(_, _, func) or
|
||||
this = TIRTempVariable(func, _, _, _) or
|
||||
this = TIRStringLiteral(func, _, _, _) or
|
||||
this = TIRDynamicInitializationFlag(func, _, _)
|
||||
}
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { none() }
|
||||
abstract string toString();
|
||||
|
||||
/**
|
||||
* Holds if this variable's value cannot be changed within a function. Currently used for string
|
||||
@@ -49,13 +42,13 @@ class IRVariable extends TIRVariable {
|
||||
/**
|
||||
* Gets the type of the variable.
|
||||
*/
|
||||
Language::LanguageType getLanguageType() { none() }
|
||||
abstract Language::LanguageType getLanguageType();
|
||||
|
||||
/**
|
||||
* Gets the AST node that declared this variable, or that introduced this
|
||||
* variable as part of the AST-to-IR translation.
|
||||
*/
|
||||
Language::AST getAst() { none() }
|
||||
abstract Language::AST getAst();
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated Language::AST getAST() { result = this.getAst() }
|
||||
@@ -64,7 +57,7 @@ class IRVariable extends TIRVariable {
|
||||
* Gets an identifier string for the variable. This identifier is unique
|
||||
* within the function.
|
||||
*/
|
||||
string getUniqueId() { none() }
|
||||
abstract string getUniqueId();
|
||||
|
||||
/**
|
||||
* Gets the source location of this variable.
|
||||
@@ -74,7 +67,7 @@ class IRVariable extends TIRVariable {
|
||||
/**
|
||||
* Gets the IR for the function that references this variable.
|
||||
*/
|
||||
final IRFunction getEnclosingIRFunction() { result.getFunction() = func }
|
||||
final IRFunction getEnclosingIRFunction() { result.getFunction() = this.getEnclosingFunction() }
|
||||
|
||||
/**
|
||||
* Gets the function that references this variable.
|
||||
@@ -82,10 +75,18 @@ class IRVariable extends TIRVariable {
|
||||
final Language::Declaration getEnclosingFunction() { result = func }
|
||||
}
|
||||
|
||||
/**
|
||||
* A variable referenced by the IR for a function.
|
||||
*
|
||||
* The variable may be a user-declared variable (`IRUserVariable`) or a temporary variable generated
|
||||
* by the AST-to-IR translation (`IRTempVariable`).
|
||||
*/
|
||||
final class IRVariable = AbstractIRVariable;
|
||||
|
||||
/**
|
||||
* A user-declared variable referenced by the IR for a function.
|
||||
*/
|
||||
class IRUserVariable extends IRVariable, TIRUserVariable {
|
||||
class IRUserVariable extends AbstractIRVariable, TIRUserVariable {
|
||||
Language::Variable var;
|
||||
Language::LanguageType type;
|
||||
|
||||
@@ -114,26 +115,29 @@ class IRUserVariable extends IRVariable, TIRUserVariable {
|
||||
* A variable (user-declared or temporary) that is allocated on the stack. This includes all
|
||||
* parameters, non-static local variables, and temporary variables.
|
||||
*/
|
||||
class IRAutomaticVariable extends IRVariable {
|
||||
IRAutomaticVariable() {
|
||||
exists(Language::Variable var |
|
||||
this = TIRUserVariable(var, _, func) and
|
||||
Language::isVariableAutomatic(var)
|
||||
)
|
||||
or
|
||||
this = TIRTempVariable(func, _, _, _)
|
||||
}
|
||||
abstract private class AbstractIRAutomaticVariable extends AbstractIRVariable { }
|
||||
|
||||
/**
|
||||
* A variable (user-declared or temporary) that is allocated on the stack. This includes all
|
||||
* parameters, non-static local variables, and temporary variables.
|
||||
*/
|
||||
final class IRAutomaticVariable = AbstractIRAutomaticVariable;
|
||||
|
||||
/**
|
||||
* A user-declared variable that is allocated on the stack. This includes all parameters and
|
||||
* non-static local variables.
|
||||
*/
|
||||
private class AbstractIRAutomaticUserVariable extends IRUserVariable, AbstractIRAutomaticVariable {
|
||||
override Language::AutomaticVariable var;
|
||||
|
||||
final override Language::AutomaticVariable getVariable() { result = var }
|
||||
}
|
||||
|
||||
/**
|
||||
* A user-declared variable that is allocated on the stack. This includes all parameters and
|
||||
* non-static local variables.
|
||||
*/
|
||||
class IRAutomaticUserVariable extends IRUserVariable, IRAutomaticVariable {
|
||||
override Language::AutomaticVariable var;
|
||||
|
||||
final override Language::AutomaticVariable getVariable() { result = var }
|
||||
}
|
||||
final class IRAutomaticUserVariable = AbstractIRAutomaticUserVariable;
|
||||
|
||||
/**
|
||||
* A user-declared variable that is not allocated on the stack. This includes all global variables,
|
||||
@@ -151,16 +155,10 @@ class IRStaticUserVariable extends IRUserVariable {
|
||||
* A variable that is not user-declared. This includes temporary variables generated as part of IR
|
||||
* construction, as well as string literals.
|
||||
*/
|
||||
class IRGeneratedVariable extends IRVariable {
|
||||
abstract private class AbstractIRGeneratedVariable extends AbstractIRVariable {
|
||||
Language::AST ast;
|
||||
Language::LanguageType type;
|
||||
|
||||
IRGeneratedVariable() {
|
||||
this = TIRTempVariable(func, ast, _, type) or
|
||||
this = TIRStringLiteral(func, ast, type, _) or
|
||||
this = TIRDynamicInitializationFlag(func, ast, type)
|
||||
}
|
||||
|
||||
final override Language::LanguageType getLanguageType() { result = type }
|
||||
|
||||
final override Language::AST getAst() { result = ast }
|
||||
@@ -196,12 +194,20 @@ class IRGeneratedVariable extends IRVariable {
|
||||
string getBaseString() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A variable that is not user-declared. This includes temporary variables generated as part of IR
|
||||
* construction, as well as string literals.
|
||||
*/
|
||||
final class IRGeneratedVariable = AbstractIRGeneratedVariable;
|
||||
|
||||
/**
|
||||
* A temporary variable introduced by IR construction. The most common examples are the variable
|
||||
* generated to hold the return value of a function, or the variable generated to hold the result of
|
||||
* a condition operator (`a ? b : c`).
|
||||
*/
|
||||
class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVariable {
|
||||
class IRTempVariable extends AbstractIRGeneratedVariable, AbstractIRAutomaticVariable,
|
||||
TIRTempVariable
|
||||
{
|
||||
TempVariableTag tag;
|
||||
|
||||
IRTempVariable() { this = TIRTempVariable(func, ast, tag, type) }
|
||||
@@ -241,7 +247,7 @@ class IRThrowVariable extends IRTempVariable {
|
||||
* A temporary variable generated to hold the contents of all arguments passed to the `...` of a
|
||||
* function that accepts a variable number of arguments.
|
||||
*/
|
||||
class IREllipsisVariable extends IRTempVariable, IRParameter {
|
||||
class IREllipsisVariable extends IRTempVariable, AbstractIRParameter {
|
||||
IREllipsisVariable() { tag = EllipsisTempVar() }
|
||||
|
||||
final override string toString() { result = "#ellipsis" }
|
||||
@@ -252,7 +258,7 @@ class IREllipsisVariable extends IRTempVariable, IRParameter {
|
||||
/**
|
||||
* A temporary variable generated to hold the `this` pointer.
|
||||
*/
|
||||
class IRThisVariable extends IRTempVariable, IRParameter {
|
||||
class IRThisVariable extends IRTempVariable, AbstractIRParameter {
|
||||
IRThisVariable() { tag = ThisTempVar() }
|
||||
|
||||
final override string toString() { result = "#this" }
|
||||
@@ -264,7 +270,7 @@ class IRThisVariable extends IRTempVariable, IRParameter {
|
||||
* A variable generated to represent the contents of a string literal. This variable acts much like
|
||||
* a read-only global variable.
|
||||
*/
|
||||
class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral {
|
||||
class IRStringLiteral extends AbstractIRGeneratedVariable, TIRStringLiteral {
|
||||
Language::StringLiteral literal;
|
||||
|
||||
IRStringLiteral() { this = TIRStringLiteral(func, ast, type, literal) }
|
||||
@@ -288,7 +294,7 @@ class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral {
|
||||
* used to model the runtime initialization of static local variables in C++, as well as static
|
||||
* fields in C#.
|
||||
*/
|
||||
class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitializationFlag {
|
||||
class IRDynamicInitializationFlag extends AbstractIRGeneratedVariable, TIRDynamicInitializationFlag {
|
||||
Language::Variable var;
|
||||
|
||||
IRDynamicInitializationFlag() {
|
||||
@@ -314,24 +320,24 @@ class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitial
|
||||
* An IR variable which acts like a function parameter, including positional parameters and the
|
||||
* temporary variables generated for `this` and ellipsis parameters.
|
||||
*/
|
||||
class IRParameter extends IRAutomaticVariable {
|
||||
IRParameter() {
|
||||
this.(IRAutomaticUserVariable).getVariable() instanceof Language::Parameter
|
||||
or
|
||||
this = TIRTempVariable(_, _, ThisTempVar(), _)
|
||||
or
|
||||
this = TIRTempVariable(_, _, EllipsisTempVar(), _)
|
||||
}
|
||||
|
||||
abstract private class AbstractIRParameter extends AbstractIRAutomaticVariable {
|
||||
/**
|
||||
* Gets the zero-based index of this parameter. The `this` parameter has index -1.
|
||||
*/
|
||||
int getIndex() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An IR variable which acts like a function parameter, including positional parameters and the
|
||||
* temporary variables generated for `this` and ellipsis parameters.
|
||||
*/
|
||||
final class IRParameter = AbstractIRParameter;
|
||||
|
||||
/**
|
||||
* An IR variable representing a positional parameter.
|
||||
*/
|
||||
class IRPositionalParameter extends IRParameter, IRAutomaticUserVariable {
|
||||
class IRPositionalParameter extends AbstractIRParameter, AbstractIRAutomaticUserVariable {
|
||||
IRPositionalParameter() { this.getVariable() instanceof Language::Parameter }
|
||||
|
||||
final override int getIndex() { result = this.getVariable().(Language::Parameter).getIndex() }
|
||||
}
|
||||
|
||||
@@ -247,8 +247,7 @@ class Instruction extends Construction::TStageInstruction {
|
||||
* Gets the type of the result produced by this instruction. If the instruction does not produce
|
||||
* a result, its result type will be `IRVoidType`.
|
||||
*/
|
||||
cached
|
||||
final IRType getResultIRType() { result = this.getResultLanguageType().getIRType() }
|
||||
final IRType getResultIRType() { result = Construction::getInstructionResultIRType(this) }
|
||||
|
||||
/**
|
||||
* Gets the type of the result produced by this instruction. If the
|
||||
@@ -995,9 +994,8 @@ class ConstantInstruction extends ConstantValueInstruction {
|
||||
*/
|
||||
class IntegerConstantInstruction extends ConstantInstruction {
|
||||
IntegerConstantInstruction() {
|
||||
exists(IRType resultType |
|
||||
resultType = this.getResultIRType() and
|
||||
(resultType instanceof IRIntegerType or resultType instanceof IRBooleanType)
|
||||
exists(IRType resultType | resultType = this.getResultIRType() |
|
||||
resultType instanceof IRIntegerType or resultType instanceof IRBooleanType
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1009,6 +1007,17 @@ class FloatConstantInstruction extends ConstantInstruction {
|
||||
FloatConstantInstruction() { this.getResultIRType() instanceof IRFloatingPointType }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction whose result is a constant value of a pointer type.
|
||||
*/
|
||||
class PointerConstantInstruction extends ConstantInstruction {
|
||||
PointerConstantInstruction() {
|
||||
exists(IRType resultType | resultType = this.getResultIRType() |
|
||||
resultType instanceof IRAddressType or resultType instanceof IRFunctionAddressType
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction whose result is the address of a string literal.
|
||||
*/
|
||||
|
||||
@@ -377,6 +377,10 @@ CppType getInstructionResultType(TStageInstruction instr) {
|
||||
result = getVoidType()
|
||||
}
|
||||
|
||||
IRType getInstructionResultIRType(Instruction instr) {
|
||||
result = instr.getResultLanguageType().getIRType()
|
||||
}
|
||||
|
||||
predicate getInstructionOpcode(Opcode opcode, TStageInstruction instr) {
|
||||
getInstructionTranslatedElement(instr).hasInstruction(opcode, getInstructionTag(instr), _)
|
||||
or
|
||||
|
||||
@@ -538,6 +538,11 @@ class TranslatedResultCopy extends TranslatedExpr, TTranslatedResultCopy {
|
||||
final override predicate producesExprResult() { any() }
|
||||
|
||||
private TranslatedCoreExpr getOperand() { result.getExpr() = expr }
|
||||
|
||||
override predicate handlesDestructorsExplicitly() {
|
||||
// The destructor calls will already have been generated by the translation of `expr`.
|
||||
any()
|
||||
}
|
||||
}
|
||||
|
||||
class TranslatedCommaExpr extends TranslatedNonConstantExpr {
|
||||
|
||||
@@ -1163,6 +1163,8 @@ class TranslatedForStmt extends TranslatedLoop {
|
||||
class TranslatedRangeBasedForStmt extends TranslatedStmt, ConditionContext {
|
||||
override RangeBasedForStmt stmt;
|
||||
|
||||
override predicate handlesDestructorsExplicitly() { any() }
|
||||
|
||||
override TranslatedElement getChildInternal(int id) {
|
||||
id = 0 and result = this.getInitialization()
|
||||
or
|
||||
@@ -1216,6 +1218,19 @@ class TranslatedRangeBasedForStmt extends TranslatedStmt, ConditionContext {
|
||||
or
|
||||
child = this.getUpdate() and
|
||||
result = this.getCondition().getFirstInstruction(kind)
|
||||
or
|
||||
exists(int destructorId |
|
||||
destructorId >= this.getFirstDestructorCallIndex() and
|
||||
child = this.getChild(destructorId) and
|
||||
result = this.getChild(destructorId + 1).getFirstInstruction(kind)
|
||||
)
|
||||
or
|
||||
exists(int lastDestructorIndex |
|
||||
lastDestructorIndex =
|
||||
max(int n | exists(this.getChild(n)) and n >= this.getFirstDestructorCallIndex()) and
|
||||
child = this.getChild(lastDestructorIndex) and
|
||||
result = this.getParent().getChildSuccessor(this, kind)
|
||||
)
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
@@ -1231,7 +1246,9 @@ class TranslatedRangeBasedForStmt extends TranslatedStmt, ConditionContext {
|
||||
|
||||
override Instruction getChildFalseSuccessor(TranslatedCondition child, EdgeKind kind) {
|
||||
child = this.getCondition() and
|
||||
result = this.getParent().getChildSuccessor(this, kind)
|
||||
if this.hasAnImplicitDestructorCall()
|
||||
then result = this.getChild(this.getFirstDestructorCallIndex()).getFirstInstruction(kind)
|
||||
else result = this.getParent().getChildSuccessor(this, kind)
|
||||
}
|
||||
|
||||
private TranslatedDeclStmt getRangeVariableDeclStmt() {
|
||||
@@ -1276,6 +1293,11 @@ class TranslatedJumpStmt extends TranslatedStmt {
|
||||
override JumpStmt stmt;
|
||||
|
||||
override Instruction getFirstInstruction(EdgeKind kind) {
|
||||
// The first instruction is a destructor call, if any.
|
||||
result = this.getChildInternal(0).getFirstInstruction(kind)
|
||||
or
|
||||
// Otherwise, the first (and only) instruction is a `NoOp`
|
||||
not exists(this.getChildInternal(0)) and
|
||||
result = this.getInstruction(OnlyInstructionTag()) and
|
||||
kind instanceof GotoEdge
|
||||
}
|
||||
@@ -1284,7 +1306,20 @@ class TranslatedJumpStmt extends TranslatedStmt {
|
||||
result = this.getInstruction(OnlyInstructionTag())
|
||||
}
|
||||
|
||||
override TranslatedElement getChildInternal(int id) { none() }
|
||||
private TranslatedCall getTranslatedImplicitDestructorCall(int id) {
|
||||
result.getExpr() = stmt.getImplicitDestructorCall(id)
|
||||
}
|
||||
|
||||
override TranslatedElement getLastChild() {
|
||||
result =
|
||||
this.getTranslatedImplicitDestructorCall(max(int id |
|
||||
exists(stmt.getImplicitDestructorCall(id))
|
||||
))
|
||||
}
|
||||
|
||||
override TranslatedElement getChildInternal(int id) {
|
||||
result = this.getTranslatedImplicitDestructorCall(id)
|
||||
}
|
||||
|
||||
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
|
||||
tag = OnlyInstructionTag() and
|
||||
@@ -1297,7 +1332,19 @@ class TranslatedJumpStmt extends TranslatedStmt {
|
||||
result = getTranslatedStmt(stmt.getTarget()).getFirstInstruction(kind)
|
||||
}
|
||||
|
||||
override Instruction getChildSuccessorInternal(TranslatedElement child, EdgeKind kind) { none() }
|
||||
final override predicate handlesDestructorsExplicitly() { any() }
|
||||
|
||||
override Instruction getChildSuccessorInternal(TranslatedElement child, EdgeKind kind) {
|
||||
exists(int id | child = this.getChildInternal(id) |
|
||||
// Transition to the next destructor call, if any.
|
||||
result = this.getChildInternal(id + 1).getFirstInstruction(kind)
|
||||
or
|
||||
// And otherwise, exit this element by flowing to the target of the jump.
|
||||
not exists(this.getChildInternal(id + 1)) and
|
||||
kind instanceof GotoEdge and
|
||||
result = this.getInstruction(OnlyInstructionTag())
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private EdgeKind getCaseEdge(SwitchCase switchCase) {
|
||||
|
||||
@@ -17,18 +17,11 @@ private import Imports::IRType
|
||||
* The variable may be a user-declared variable (`IRUserVariable`) or a temporary variable generated
|
||||
* by the AST-to-IR translation (`IRTempVariable`).
|
||||
*/
|
||||
class IRVariable extends TIRVariable {
|
||||
abstract private class AbstractIRVariable extends TIRVariable {
|
||||
Language::Declaration func;
|
||||
|
||||
IRVariable() {
|
||||
this = TIRUserVariable(_, _, func) or
|
||||
this = TIRTempVariable(func, _, _, _) or
|
||||
this = TIRStringLiteral(func, _, _, _) or
|
||||
this = TIRDynamicInitializationFlag(func, _, _)
|
||||
}
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { none() }
|
||||
abstract string toString();
|
||||
|
||||
/**
|
||||
* Holds if this variable's value cannot be changed within a function. Currently used for string
|
||||
@@ -49,13 +42,13 @@ class IRVariable extends TIRVariable {
|
||||
/**
|
||||
* Gets the type of the variable.
|
||||
*/
|
||||
Language::LanguageType getLanguageType() { none() }
|
||||
abstract Language::LanguageType getLanguageType();
|
||||
|
||||
/**
|
||||
* Gets the AST node that declared this variable, or that introduced this
|
||||
* variable as part of the AST-to-IR translation.
|
||||
*/
|
||||
Language::AST getAst() { none() }
|
||||
abstract Language::AST getAst();
|
||||
|
||||
/** DEPRECATED: Alias for getAst */
|
||||
deprecated Language::AST getAST() { result = this.getAst() }
|
||||
@@ -64,7 +57,7 @@ class IRVariable extends TIRVariable {
|
||||
* Gets an identifier string for the variable. This identifier is unique
|
||||
* within the function.
|
||||
*/
|
||||
string getUniqueId() { none() }
|
||||
abstract string getUniqueId();
|
||||
|
||||
/**
|
||||
* Gets the source location of this variable.
|
||||
@@ -74,7 +67,7 @@ class IRVariable extends TIRVariable {
|
||||
/**
|
||||
* Gets the IR for the function that references this variable.
|
||||
*/
|
||||
final IRFunction getEnclosingIRFunction() { result.getFunction() = func }
|
||||
final IRFunction getEnclosingIRFunction() { result.getFunction() = this.getEnclosingFunction() }
|
||||
|
||||
/**
|
||||
* Gets the function that references this variable.
|
||||
@@ -82,10 +75,18 @@ class IRVariable extends TIRVariable {
|
||||
final Language::Declaration getEnclosingFunction() { result = func }
|
||||
}
|
||||
|
||||
/**
|
||||
* A variable referenced by the IR for a function.
|
||||
*
|
||||
* The variable may be a user-declared variable (`IRUserVariable`) or a temporary variable generated
|
||||
* by the AST-to-IR translation (`IRTempVariable`).
|
||||
*/
|
||||
final class IRVariable = AbstractIRVariable;
|
||||
|
||||
/**
|
||||
* A user-declared variable referenced by the IR for a function.
|
||||
*/
|
||||
class IRUserVariable extends IRVariable, TIRUserVariable {
|
||||
class IRUserVariable extends AbstractIRVariable, TIRUserVariable {
|
||||
Language::Variable var;
|
||||
Language::LanguageType type;
|
||||
|
||||
@@ -114,26 +115,29 @@ class IRUserVariable extends IRVariable, TIRUserVariable {
|
||||
* A variable (user-declared or temporary) that is allocated on the stack. This includes all
|
||||
* parameters, non-static local variables, and temporary variables.
|
||||
*/
|
||||
class IRAutomaticVariable extends IRVariable {
|
||||
IRAutomaticVariable() {
|
||||
exists(Language::Variable var |
|
||||
this = TIRUserVariable(var, _, func) and
|
||||
Language::isVariableAutomatic(var)
|
||||
)
|
||||
or
|
||||
this = TIRTempVariable(func, _, _, _)
|
||||
}
|
||||
abstract private class AbstractIRAutomaticVariable extends AbstractIRVariable { }
|
||||
|
||||
/**
|
||||
* A variable (user-declared or temporary) that is allocated on the stack. This includes all
|
||||
* parameters, non-static local variables, and temporary variables.
|
||||
*/
|
||||
final class IRAutomaticVariable = AbstractIRAutomaticVariable;
|
||||
|
||||
/**
|
||||
* A user-declared variable that is allocated on the stack. This includes all parameters and
|
||||
* non-static local variables.
|
||||
*/
|
||||
private class AbstractIRAutomaticUserVariable extends IRUserVariable, AbstractIRAutomaticVariable {
|
||||
override Language::AutomaticVariable var;
|
||||
|
||||
final override Language::AutomaticVariable getVariable() { result = var }
|
||||
}
|
||||
|
||||
/**
|
||||
* A user-declared variable that is allocated on the stack. This includes all parameters and
|
||||
* non-static local variables.
|
||||
*/
|
||||
class IRAutomaticUserVariable extends IRUserVariable, IRAutomaticVariable {
|
||||
override Language::AutomaticVariable var;
|
||||
|
||||
final override Language::AutomaticVariable getVariable() { result = var }
|
||||
}
|
||||
final class IRAutomaticUserVariable = AbstractIRAutomaticUserVariable;
|
||||
|
||||
/**
|
||||
* A user-declared variable that is not allocated on the stack. This includes all global variables,
|
||||
@@ -151,16 +155,10 @@ class IRStaticUserVariable extends IRUserVariable {
|
||||
* A variable that is not user-declared. This includes temporary variables generated as part of IR
|
||||
* construction, as well as string literals.
|
||||
*/
|
||||
class IRGeneratedVariable extends IRVariable {
|
||||
abstract private class AbstractIRGeneratedVariable extends AbstractIRVariable {
|
||||
Language::AST ast;
|
||||
Language::LanguageType type;
|
||||
|
||||
IRGeneratedVariable() {
|
||||
this = TIRTempVariable(func, ast, _, type) or
|
||||
this = TIRStringLiteral(func, ast, type, _) or
|
||||
this = TIRDynamicInitializationFlag(func, ast, type)
|
||||
}
|
||||
|
||||
final override Language::LanguageType getLanguageType() { result = type }
|
||||
|
||||
final override Language::AST getAst() { result = ast }
|
||||
@@ -196,12 +194,20 @@ class IRGeneratedVariable extends IRVariable {
|
||||
string getBaseString() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* A variable that is not user-declared. This includes temporary variables generated as part of IR
|
||||
* construction, as well as string literals.
|
||||
*/
|
||||
final class IRGeneratedVariable = AbstractIRGeneratedVariable;
|
||||
|
||||
/**
|
||||
* A temporary variable introduced by IR construction. The most common examples are the variable
|
||||
* generated to hold the return value of a function, or the variable generated to hold the result of
|
||||
* a condition operator (`a ? b : c`).
|
||||
*/
|
||||
class IRTempVariable extends IRGeneratedVariable, IRAutomaticVariable, TIRTempVariable {
|
||||
class IRTempVariable extends AbstractIRGeneratedVariable, AbstractIRAutomaticVariable,
|
||||
TIRTempVariable
|
||||
{
|
||||
TempVariableTag tag;
|
||||
|
||||
IRTempVariable() { this = TIRTempVariable(func, ast, tag, type) }
|
||||
@@ -241,7 +247,7 @@ class IRThrowVariable extends IRTempVariable {
|
||||
* A temporary variable generated to hold the contents of all arguments passed to the `...` of a
|
||||
* function that accepts a variable number of arguments.
|
||||
*/
|
||||
class IREllipsisVariable extends IRTempVariable, IRParameter {
|
||||
class IREllipsisVariable extends IRTempVariable, AbstractIRParameter {
|
||||
IREllipsisVariable() { tag = EllipsisTempVar() }
|
||||
|
||||
final override string toString() { result = "#ellipsis" }
|
||||
@@ -252,7 +258,7 @@ class IREllipsisVariable extends IRTempVariable, IRParameter {
|
||||
/**
|
||||
* A temporary variable generated to hold the `this` pointer.
|
||||
*/
|
||||
class IRThisVariable extends IRTempVariable, IRParameter {
|
||||
class IRThisVariable extends IRTempVariable, AbstractIRParameter {
|
||||
IRThisVariable() { tag = ThisTempVar() }
|
||||
|
||||
final override string toString() { result = "#this" }
|
||||
@@ -264,7 +270,7 @@ class IRThisVariable extends IRTempVariable, IRParameter {
|
||||
* A variable generated to represent the contents of a string literal. This variable acts much like
|
||||
* a read-only global variable.
|
||||
*/
|
||||
class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral {
|
||||
class IRStringLiteral extends AbstractIRGeneratedVariable, TIRStringLiteral {
|
||||
Language::StringLiteral literal;
|
||||
|
||||
IRStringLiteral() { this = TIRStringLiteral(func, ast, type, literal) }
|
||||
@@ -288,7 +294,7 @@ class IRStringLiteral extends IRGeneratedVariable, TIRStringLiteral {
|
||||
* used to model the runtime initialization of static local variables in C++, as well as static
|
||||
* fields in C#.
|
||||
*/
|
||||
class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitializationFlag {
|
||||
class IRDynamicInitializationFlag extends AbstractIRGeneratedVariable, TIRDynamicInitializationFlag {
|
||||
Language::Variable var;
|
||||
|
||||
IRDynamicInitializationFlag() {
|
||||
@@ -314,24 +320,24 @@ class IRDynamicInitializationFlag extends IRGeneratedVariable, TIRDynamicInitial
|
||||
* An IR variable which acts like a function parameter, including positional parameters and the
|
||||
* temporary variables generated for `this` and ellipsis parameters.
|
||||
*/
|
||||
class IRParameter extends IRAutomaticVariable {
|
||||
IRParameter() {
|
||||
this.(IRAutomaticUserVariable).getVariable() instanceof Language::Parameter
|
||||
or
|
||||
this = TIRTempVariable(_, _, ThisTempVar(), _)
|
||||
or
|
||||
this = TIRTempVariable(_, _, EllipsisTempVar(), _)
|
||||
}
|
||||
|
||||
abstract private class AbstractIRParameter extends AbstractIRAutomaticVariable {
|
||||
/**
|
||||
* Gets the zero-based index of this parameter. The `this` parameter has index -1.
|
||||
*/
|
||||
int getIndex() { none() }
|
||||
}
|
||||
|
||||
/**
|
||||
* An IR variable which acts like a function parameter, including positional parameters and the
|
||||
* temporary variables generated for `this` and ellipsis parameters.
|
||||
*/
|
||||
final class IRParameter = AbstractIRParameter;
|
||||
|
||||
/**
|
||||
* An IR variable representing a positional parameter.
|
||||
*/
|
||||
class IRPositionalParameter extends IRParameter, IRAutomaticUserVariable {
|
||||
class IRPositionalParameter extends AbstractIRParameter, AbstractIRAutomaticUserVariable {
|
||||
IRPositionalParameter() { this.getVariable() instanceof Language::Parameter }
|
||||
|
||||
final override int getIndex() { result = this.getVariable().(Language::Parameter).getIndex() }
|
||||
}
|
||||
|
||||
@@ -247,8 +247,7 @@ class Instruction extends Construction::TStageInstruction {
|
||||
* Gets the type of the result produced by this instruction. If the instruction does not produce
|
||||
* a result, its result type will be `IRVoidType`.
|
||||
*/
|
||||
cached
|
||||
final IRType getResultIRType() { result = this.getResultLanguageType().getIRType() }
|
||||
final IRType getResultIRType() { result = Construction::getInstructionResultIRType(this) }
|
||||
|
||||
/**
|
||||
* Gets the type of the result produced by this instruction. If the
|
||||
@@ -995,9 +994,8 @@ class ConstantInstruction extends ConstantValueInstruction {
|
||||
*/
|
||||
class IntegerConstantInstruction extends ConstantInstruction {
|
||||
IntegerConstantInstruction() {
|
||||
exists(IRType resultType |
|
||||
resultType = this.getResultIRType() and
|
||||
(resultType instanceof IRIntegerType or resultType instanceof IRBooleanType)
|
||||
exists(IRType resultType | resultType = this.getResultIRType() |
|
||||
resultType instanceof IRIntegerType or resultType instanceof IRBooleanType
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -1009,6 +1007,17 @@ class FloatConstantInstruction extends ConstantInstruction {
|
||||
FloatConstantInstruction() { this.getResultIRType() instanceof IRFloatingPointType }
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction whose result is a constant value of a pointer type.
|
||||
*/
|
||||
class PointerConstantInstruction extends ConstantInstruction {
|
||||
PointerConstantInstruction() {
|
||||
exists(IRType resultType | resultType = this.getResultIRType() |
|
||||
resultType instanceof IRAddressType or resultType instanceof IRFunctionAddressType
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An instruction whose result is the address of a string literal.
|
||||
*/
|
||||
|
||||
@@ -429,6 +429,11 @@ private module Cached {
|
||||
instr = unreachedInstruction(_) and result = Language::getVoidType()
|
||||
}
|
||||
|
||||
cached
|
||||
IRType getInstructionResultIRType(Instruction instr) {
|
||||
result = instr.getResultLanguageType().getIRType()
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `opcode` is the opcode that specifies the operation performed by `instr`.
|
||||
*
|
||||
|
||||
@@ -560,7 +560,7 @@ private class IteratorAssignmentMemberOperatorModel extends IteratorAssignmentMe
|
||||
TaintFunction, SideEffectFunction, AliasFunction
|
||||
{
|
||||
override predicate hasTaintFlow(FunctionInput input, FunctionOutput output) {
|
||||
input.isParameterDeref(0) and
|
||||
(input.isParameterDeref(0) or input.isParameter(0)) and
|
||||
output.isQualifierObject()
|
||||
}
|
||||
|
||||
@@ -579,17 +579,34 @@ private class IteratorAssignmentMemberOperatorModel extends IteratorAssignmentMe
|
||||
override predicate parameterEscapesOnlyViaReturn(int index) { index = -1 }
|
||||
}
|
||||
|
||||
/**
|
||||
* A `begin` member function, or a related function, that returns an iterator.
|
||||
*/
|
||||
class BeginFunction extends MemberFunction {
|
||||
BeginFunction() {
|
||||
this.hasName(["begin", "cbegin", "rbegin", "crbegin", "before_begin", "cbefore_begin"]) and
|
||||
this.getType().getUnspecifiedType() instanceof Iterator
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An `end` member function, or a related function, that returns an iterator.
|
||||
*/
|
||||
class EndFunction extends MemberFunction {
|
||||
EndFunction() {
|
||||
this.hasName(["end", "cend", "rend", "crend"]) and
|
||||
this.getType().getUnspecifiedType() instanceof Iterator
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A `begin` or `end` member function, or a related member function, that
|
||||
* returns an iterator.
|
||||
*/
|
||||
class BeginOrEndFunction extends MemberFunction {
|
||||
BeginOrEndFunction() {
|
||||
this.hasName([
|
||||
"begin", "cbegin", "rbegin", "crbegin", "end", "cend", "rend", "crend", "before_begin",
|
||||
"cbefore_begin"
|
||||
]) and
|
||||
this.getType().getUnspecifiedType() instanceof Iterator
|
||||
this instanceof BeginFunction or
|
||||
this instanceof EndFunction
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,616 +0,0 @@
|
||||
/**
|
||||
* DEPRECATED: This library has been replaced with a newer version which
|
||||
* provides better performance and precision. Use
|
||||
* `semmle.code.cpp.valuenumbering.GlobalValueNumbering` instead.
|
||||
*
|
||||
* Provides an implementation of Global Value Numbering.
|
||||
* See https://en.wikipedia.org/wiki/Global_value_numbering
|
||||
*
|
||||
* The predicate `globalValueNumber` converts an expression into a `GVN`,
|
||||
* which is an abstract type representing the value of the expression. If
|
||||
* two expressions have the same `GVN` then they compute the same value.
|
||||
* For example:
|
||||
*
|
||||
* ```
|
||||
* void f(int x, int y) {
|
||||
* g(x+y, x+y);
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* In this example, both arguments in the call to `g` compute the same value,
|
||||
* so both arguments have the same `GVN`. In other words, we can find
|
||||
* this call with the following query:
|
||||
*
|
||||
* ```
|
||||
* from FunctionCall call, GVN v
|
||||
* where v = globalValueNumber(call.getArgument(0))
|
||||
* and v = globalValueNumber(call.getArgument(1))
|
||||
* select call
|
||||
* ```
|
||||
*
|
||||
* The analysis is conservative, so two expressions might have different
|
||||
* `GVN`s even though the actually always compute the same value. The most
|
||||
* common reason for this is that the analysis cannot prove that there
|
||||
* are no side-effects that might cause the computed value to change.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Note to developers: the correctness of this module depends on the
|
||||
* definitions of GVN, globalValueNumber, and analyzableExpr being kept in
|
||||
* sync with each other. If you change this module then make sure that the
|
||||
* change is symmetric across all three.
|
||||
*/
|
||||
|
||||
import cpp
|
||||
private import semmle.code.cpp.controlflow.SSA
|
||||
|
||||
/**
|
||||
* Holds if the result is a control flow node that might change the
|
||||
* value of any global variable. This is used in the implementation
|
||||
* of `GVN_OtherVariable`, because we need to be quite conservative when
|
||||
* we assign a value number to a global variable. For example:
|
||||
*
|
||||
* ```
|
||||
* x = g+1;
|
||||
* dosomething();
|
||||
* y = g+1;
|
||||
* ```
|
||||
*
|
||||
* It is not safe to assign the same value number to both instances
|
||||
* of `g+1` in this example, because the call to `dosomething` might
|
||||
* change the value of `g`.
|
||||
*/
|
||||
private ControlFlowNode nodeWithPossibleSideEffect() {
|
||||
result instanceof Call
|
||||
or
|
||||
// If the lhs of an assignment is not analyzable by SSA, then
|
||||
// we need to treat the assignment as having a possible side-effect.
|
||||
result instanceof Assignment and not result instanceof SsaDefinition
|
||||
or
|
||||
result instanceof CrementOperation and not result instanceof SsaDefinition
|
||||
or
|
||||
exists(LocalVariable v |
|
||||
result = v.getInitializer().getExpr() and not result instanceof SsaDefinition
|
||||
)
|
||||
or
|
||||
result instanceof AsmStmt
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the entry node of the control flow graph of which `node` is a
|
||||
* member.
|
||||
*/
|
||||
cached
|
||||
private ControlFlowNode getControlFlowEntry(ControlFlowNode node) {
|
||||
result = node.getControlFlowScope().getEntryPoint() and
|
||||
result.getASuccessor*() = node
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if there is a control flow edge from `src` to `dst` or
|
||||
* if `dst` is an expression with a possible side-effect. The idea
|
||||
* is to treat side effects as entry points in the control flow
|
||||
* graph so that we can use the dominator tree to find the most recent
|
||||
* side-effect.
|
||||
*/
|
||||
private predicate sideEffectCfg(ControlFlowNode src, ControlFlowNode dst) {
|
||||
src.getASuccessor() = dst
|
||||
or
|
||||
// Add an edge from the entry point to any node that might have a side
|
||||
// effect.
|
||||
dst = nodeWithPossibleSideEffect() and
|
||||
src = getControlFlowEntry(dst)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `dominator` is the immediate dominator of `node` in
|
||||
* the side-effect CFG.
|
||||
*/
|
||||
private predicate iDomEffect(ControlFlowNode dominator, ControlFlowNode node) =
|
||||
idominance(functionEntry/1, sideEffectCfg/2)(_, dominator, node)
|
||||
|
||||
/**
|
||||
* Gets the most recent side effect. To be more precise, `result` is a
|
||||
* dominator of `node` and no side-effects can occur between `result` and
|
||||
* `node`.
|
||||
*
|
||||
* `sideEffectCFG` has an edge from the function entry to every node with a
|
||||
* side-effect. This means that every node with a side-effect has the
|
||||
* function entry as its immediate dominator. So if node `x` dominates node
|
||||
* `y` then there can be no side effects between `x` and `y` unless `x` is
|
||||
* the function entry. So the optimal choice for `result` has the function
|
||||
* entry as its immediate dominator.
|
||||
*
|
||||
* Example:
|
||||
*
|
||||
* ```
|
||||
* 000: int f(int a, int b, int *p) {
|
||||
* 001: int r = 0;
|
||||
* 002: if (a) {
|
||||
* 003: if (b) {
|
||||
* 004: sideEffect1();
|
||||
* 005: }
|
||||
* 006: } else {
|
||||
* 007: sideEffect2();
|
||||
* 008: }
|
||||
* 009: if (a) {
|
||||
* 010: r++; // Not a side-effect, because r is an SSA variable.
|
||||
* 011: }
|
||||
* 012: if (b) {
|
||||
* 013: r++; // Not a side-effect, because r is an SSA variable.
|
||||
* 014: }
|
||||
* 015: return *p;
|
||||
* 016: }
|
||||
* ```
|
||||
*
|
||||
* Suppose we want to find the most recent side-effect for the dereference
|
||||
* of `p` on line 015. The `sideEffectCFG` has an edge from the function
|
||||
* entry (line 000) to the side effects at lines 004 and 007. Therefore,
|
||||
* the immediate dominator tree looks like this:
|
||||
*
|
||||
* 000 - 001 - 002 - 003
|
||||
* - 004
|
||||
* - 007
|
||||
* - 009 - 010
|
||||
* - 012 - 013
|
||||
* - 015
|
||||
*
|
||||
* The immediate dominator path to line 015 is 000 - 009 - 012 - 015.
|
||||
* Therefore, the most recent side effect for line 015 is line 009.
|
||||
*/
|
||||
cached
|
||||
private ControlFlowNode mostRecentSideEffect(ControlFlowNode node) {
|
||||
exists(ControlFlowNode entry |
|
||||
functionEntry(entry) and
|
||||
iDomEffect(entry, result) and
|
||||
iDomEffect*(result, node)
|
||||
)
|
||||
}
|
||||
|
||||
/** Used to represent the "global value number" of an expression. */
|
||||
cached
|
||||
private newtype GvnBase =
|
||||
GVN_IntConst(int val, Type t) { mk_IntConst(val, t, _) } or
|
||||
GVN_FloatConst(float val, Type t) { mk_FloatConst(val, t, _) } or
|
||||
// If the local variable does not have a defining value, then
|
||||
// we use the SsaDefinition as its global value number.
|
||||
GVN_UndefinedStackVariable(StackVariable x, SsaDefinition def) {
|
||||
mk_UndefinedStackVariable(x, def, _)
|
||||
} or
|
||||
// Variables with no SSA information. As a crude (but safe)
|
||||
// approximation, we use `mostRecentSideEffect` to compute a definition
|
||||
// location for the variable. This ensures that two instances of the same
|
||||
// global variable will only get the same value number if they are
|
||||
// guaranteed to have the same value.
|
||||
GVN_OtherVariable(Variable x, ControlFlowNode dominator) { mk_OtherVariable(x, dominator, _) } or
|
||||
deprecated GVN_FieldAccess(GVN s, Field f) {
|
||||
mk_DotFieldAccess(s, f, _) or
|
||||
mk_PointerFieldAccess_with_deref(s, f, _) or
|
||||
mk_ImplicitThisFieldAccess_with_deref(s, f, _)
|
||||
} or
|
||||
// Dereference a pointer. The value might have changed since the last
|
||||
// time the pointer was dereferenced, so we need to include a definition
|
||||
// location. As a crude (but safe) approximation, we use
|
||||
// `mostRecentSideEffect` to compute a definition location.
|
||||
deprecated GVN_Deref(GVN p, ControlFlowNode dominator) {
|
||||
mk_Deref(p, dominator, _) or
|
||||
mk_PointerFieldAccess(p, _, dominator, _) or
|
||||
mk_ImplicitThisFieldAccess_with_qualifier(p, _, dominator, _)
|
||||
} or
|
||||
GVN_ThisExpr(Function fcn) {
|
||||
mk_ThisExpr(fcn, _) or
|
||||
mk_ImplicitThisFieldAccess(fcn, _, _, _)
|
||||
} or
|
||||
deprecated GVN_Conversion(Type t, GVN child) { mk_Conversion(t, child, _) } or
|
||||
deprecated GVN_BinaryOp(GVN lhs, GVN rhs, string opname) { mk_BinaryOp(lhs, rhs, opname, _) } or
|
||||
deprecated GVN_UnaryOp(GVN child, string opname) { mk_UnaryOp(child, opname, _) } or
|
||||
deprecated GVN_ArrayAccess(GVN x, GVN i, ControlFlowNode dominator) {
|
||||
mk_ArrayAccess(x, i, dominator, _)
|
||||
} or
|
||||
// Any expression that is not handled by the cases above is
|
||||
// given a unique number based on the expression itself.
|
||||
GVN_Unanalyzable(Expr e) { not analyzableExpr(e) }
|
||||
|
||||
/**
|
||||
* A Global Value Number. A GVN is an abstract representation of the value
|
||||
* computed by an expression. The relationship between `Expr` and `GVN` is
|
||||
* many-to-one: every `Expr` has exactly one `GVN`, but multiple
|
||||
* expressions can have the same `GVN`. If two expressions have the same
|
||||
* `GVN`, it means that they compute the same value at run time. The `GVN`
|
||||
* is an opaque value, so you cannot deduce what the run-time value of an
|
||||
* expression will be from its `GVN`. The only use for the `GVN` of an
|
||||
* expression is to find other expressions that compute the same value.
|
||||
* Use the predicate `globalValueNumber` to get the `GVN` for an `Expr`.
|
||||
*
|
||||
* Note: `GVN` has `toString` and `getLocation` methods, so that it can be
|
||||
* displayed in a results list. These work by picking an arbitrary
|
||||
* expression with this `GVN` and using its `toString` and `getLocation`
|
||||
* methods.
|
||||
*/
|
||||
deprecated class GVN extends GvnBase {
|
||||
GVN() { this instanceof GvnBase }
|
||||
|
||||
/** Gets an expression that has this GVN. */
|
||||
Expr getAnExpr() { this = globalValueNumber(result) }
|
||||
|
||||
/** Gets the kind of the GVN. This can be useful for debugging. */
|
||||
string getKind() {
|
||||
if this instanceof GVN_IntConst
|
||||
then result = "IntConst"
|
||||
else
|
||||
if this instanceof GVN_FloatConst
|
||||
then result = "FloatConst"
|
||||
else
|
||||
if this instanceof GVN_UndefinedStackVariable
|
||||
then result = "UndefinedStackVariable"
|
||||
else
|
||||
if this instanceof GVN_OtherVariable
|
||||
then result = "OtherVariable"
|
||||
else
|
||||
if this instanceof GVN_FieldAccess
|
||||
then result = "FieldAccess"
|
||||
else
|
||||
if this instanceof GVN_Deref
|
||||
then result = "Deref"
|
||||
else
|
||||
if this instanceof GVN_ThisExpr
|
||||
then result = "ThisExpr"
|
||||
else
|
||||
if this instanceof GVN_Conversion
|
||||
then result = "Conversion"
|
||||
else
|
||||
if this instanceof GVN_BinaryOp
|
||||
then result = "BinaryOp"
|
||||
else
|
||||
if this instanceof GVN_UnaryOp
|
||||
then result = "UnaryOp"
|
||||
else
|
||||
if this instanceof GVN_ArrayAccess
|
||||
then result = "ArrayAccess"
|
||||
else
|
||||
if this instanceof GVN_Unanalyzable
|
||||
then result = "Unanalyzable"
|
||||
else result = "error"
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an example of an expression with this GVN.
|
||||
* This is useful for things like implementing toString().
|
||||
*/
|
||||
private Expr exampleExpr() {
|
||||
// Pick the expression with the minimum source location string. This is
|
||||
// just an arbitrary way to pick an expression with this `GVN`.
|
||||
result = min(Expr e | this = globalValueNumber(e) | e order by e.getLocation().toString())
|
||||
}
|
||||
|
||||
/** Gets a textual representation of this element. */
|
||||
string toString() { result = this.exampleExpr().toString() }
|
||||
|
||||
/** Gets the primary location of this element. */
|
||||
Location getLocation() { result = this.exampleExpr().getLocation() }
|
||||
}
|
||||
|
||||
private predicate analyzableIntConst(Expr e) {
|
||||
strictcount(e.getValue().toInt()) = 1 and
|
||||
strictcount(e.getUnspecifiedType()) = 1
|
||||
}
|
||||
|
||||
private predicate mk_IntConst(int val, Type t, Expr e) {
|
||||
analyzableIntConst(e) and
|
||||
val = e.getValue().toInt() and
|
||||
t = e.getUnspecifiedType()
|
||||
}
|
||||
|
||||
private predicate analyzableFloatConst(Expr e) {
|
||||
strictcount(e.getValue().toFloat()) = 1 and
|
||||
strictcount(e.getUnspecifiedType()) = 1 and
|
||||
not analyzableIntConst(e)
|
||||
}
|
||||
|
||||
private predicate mk_FloatConst(float val, Type t, Expr e) {
|
||||
analyzableFloatConst(e) and
|
||||
val = e.getValue().toFloat() and
|
||||
t = e.getUnspecifiedType()
|
||||
}
|
||||
|
||||
private predicate analyzableStackVariable(VariableAccess access) {
|
||||
strictcount(SsaDefinition def | def.getAUse(_) = access | def) = 1 and
|
||||
strictcount(SsaDefinition def, Variable v | def.getAUse(v) = access | v) = 1 and
|
||||
count(SsaDefinition def, Variable v |
|
||||
def.getAUse(v) = access
|
||||
|
|
||||
def.getDefiningValue(v).getFullyConverted()
|
||||
) <= 1 and
|
||||
not analyzableConst(access)
|
||||
}
|
||||
|
||||
// Note: this predicate only has a result if the access has no
|
||||
// defining value. If there is a defining value, then there is no
|
||||
// need to generate a fresh `GVN` for the access because `globalValueNumber`
|
||||
// will follow the chain and use the GVN of the defining value.
|
||||
private predicate mk_UndefinedStackVariable(
|
||||
StackVariable x, SsaDefinition def, VariableAccess access
|
||||
) {
|
||||
analyzableStackVariable(access) and
|
||||
access = def.getAUse(x) and
|
||||
not exists(def.getDefiningValue(x))
|
||||
}
|
||||
|
||||
private predicate analyzableDotFieldAccess(DotFieldAccess access) {
|
||||
strictcount(access.getTarget()) = 1 and
|
||||
strictcount(access.getQualifier().getFullyConverted()) = 1 and
|
||||
not analyzableConst(access)
|
||||
}
|
||||
|
||||
deprecated private predicate mk_DotFieldAccess(GVN qualifier, Field target, DotFieldAccess access) {
|
||||
analyzableDotFieldAccess(access) and
|
||||
target = access.getTarget() and
|
||||
qualifier = globalValueNumber(access.getQualifier().getFullyConverted())
|
||||
}
|
||||
|
||||
private predicate analyzablePointerFieldAccess(PointerFieldAccess access) {
|
||||
strictcount(mostRecentSideEffect(access)) = 1 and
|
||||
strictcount(access.getTarget()) = 1 and
|
||||
strictcount(access.getQualifier().getFullyConverted()) = 1 and
|
||||
not analyzableConst(access)
|
||||
}
|
||||
|
||||
deprecated private predicate mk_PointerFieldAccess(
|
||||
GVN qualifier, Field target, ControlFlowNode dominator, PointerFieldAccess access
|
||||
) {
|
||||
analyzablePointerFieldAccess(access) and
|
||||
dominator = mostRecentSideEffect(access) and
|
||||
target = access.getTarget() and
|
||||
qualifier = globalValueNumber(access.getQualifier().getFullyConverted())
|
||||
}
|
||||
|
||||
/**
|
||||
* `obj->field` is equivalent to `(*obj).field`, so we need to wrap an
|
||||
* extra `GVN_Deref` around the qualifier.
|
||||
*/
|
||||
deprecated private predicate mk_PointerFieldAccess_with_deref(
|
||||
GVN new_qualifier, Field target, PointerFieldAccess access
|
||||
) {
|
||||
exists(GVN qualifier, ControlFlowNode dominator |
|
||||
mk_PointerFieldAccess(qualifier, target, dominator, access) and
|
||||
new_qualifier = GVN_Deref(qualifier, dominator)
|
||||
)
|
||||
}
|
||||
|
||||
private predicate analyzableImplicitThisFieldAccess(ImplicitThisFieldAccess access) {
|
||||
strictcount(mostRecentSideEffect(access)) = 1 and
|
||||
strictcount(access.getTarget()) = 1 and
|
||||
strictcount(access.getEnclosingFunction()) = 1 and
|
||||
not analyzableConst(access)
|
||||
}
|
||||
|
||||
private predicate mk_ImplicitThisFieldAccess(
|
||||
Function fcn, Field target, ControlFlowNode dominator, ImplicitThisFieldAccess access
|
||||
) {
|
||||
analyzableImplicitThisFieldAccess(access) and
|
||||
dominator = mostRecentSideEffect(access) and
|
||||
target = access.getTarget() and
|
||||
fcn = access.getEnclosingFunction()
|
||||
}
|
||||
|
||||
deprecated private predicate mk_ImplicitThisFieldAccess_with_qualifier(
|
||||
GVN qualifier, Field target, ControlFlowNode dominator, ImplicitThisFieldAccess access
|
||||
) {
|
||||
exists(Function fcn |
|
||||
mk_ImplicitThisFieldAccess(fcn, target, dominator, access) and
|
||||
qualifier = GVN_ThisExpr(fcn)
|
||||
)
|
||||
}
|
||||
|
||||
deprecated private predicate mk_ImplicitThisFieldAccess_with_deref(
|
||||
GVN new_qualifier, Field target, ImplicitThisFieldAccess access
|
||||
) {
|
||||
exists(GVN qualifier, ControlFlowNode dominator |
|
||||
mk_ImplicitThisFieldAccess_with_qualifier(qualifier, target, dominator, access) and
|
||||
new_qualifier = GVN_Deref(qualifier, dominator)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `access` is an access of a variable that does
|
||||
* not have SSA information. (For example, because the variable
|
||||
* is global.)
|
||||
*/
|
||||
private predicate analyzableOtherVariable(VariableAccess access) {
|
||||
not access instanceof FieldAccess and
|
||||
not exists(SsaDefinition def | access = def.getAUse(_)) and
|
||||
strictcount(access.getTarget()) = 1 and
|
||||
strictcount(mostRecentSideEffect(access)) = 1 and
|
||||
not analyzableConst(access)
|
||||
}
|
||||
|
||||
private predicate mk_OtherVariable(Variable x, ControlFlowNode dominator, VariableAccess access) {
|
||||
analyzableOtherVariable(access) and
|
||||
x = access.getTarget() and
|
||||
dominator = mostRecentSideEffect(access)
|
||||
}
|
||||
|
||||
private predicate analyzableConversion(Conversion conv) {
|
||||
strictcount(conv.getUnspecifiedType()) = 1 and
|
||||
strictcount(conv.getExpr()) = 1 and
|
||||
not analyzableConst(conv)
|
||||
}
|
||||
|
||||
deprecated private predicate mk_Conversion(Type t, GVN child, Conversion conv) {
|
||||
analyzableConversion(conv) and
|
||||
t = conv.getUnspecifiedType() and
|
||||
child = globalValueNumber(conv.getExpr())
|
||||
}
|
||||
|
||||
private predicate analyzableBinaryOp(BinaryOperation op) {
|
||||
op.isPure() and
|
||||
strictcount(op.getLeftOperand().getFullyConverted()) = 1 and
|
||||
strictcount(op.getRightOperand().getFullyConverted()) = 1 and
|
||||
strictcount(op.getOperator()) = 1 and
|
||||
not analyzableConst(op)
|
||||
}
|
||||
|
||||
deprecated private predicate mk_BinaryOp(GVN lhs, GVN rhs, string opname, BinaryOperation op) {
|
||||
analyzableBinaryOp(op) and
|
||||
lhs = globalValueNumber(op.getLeftOperand().getFullyConverted()) and
|
||||
rhs = globalValueNumber(op.getRightOperand().getFullyConverted()) and
|
||||
opname = op.getOperator()
|
||||
}
|
||||
|
||||
private predicate analyzableUnaryOp(UnaryOperation op) {
|
||||
not op instanceof PointerDereferenceExpr and
|
||||
op.isPure() and
|
||||
strictcount(op.getOperand().getFullyConverted()) = 1 and
|
||||
strictcount(op.getOperator()) = 1 and
|
||||
not analyzableConst(op)
|
||||
}
|
||||
|
||||
deprecated private predicate mk_UnaryOp(GVN child, string opname, UnaryOperation op) {
|
||||
analyzableUnaryOp(op) and
|
||||
child = globalValueNumber(op.getOperand().getFullyConverted()) and
|
||||
opname = op.getOperator()
|
||||
}
|
||||
|
||||
private predicate analyzableThisExpr(ThisExpr thisExpr) {
|
||||
strictcount(thisExpr.getEnclosingFunction()) = 1 and
|
||||
not analyzableConst(thisExpr)
|
||||
}
|
||||
|
||||
private predicate mk_ThisExpr(Function fcn, ThisExpr thisExpr) {
|
||||
analyzableThisExpr(thisExpr) and
|
||||
fcn = thisExpr.getEnclosingFunction()
|
||||
}
|
||||
|
||||
private predicate analyzableArrayAccess(ArrayExpr ae) {
|
||||
strictcount(ae.getArrayBase().getFullyConverted()) = 1 and
|
||||
strictcount(ae.getArrayOffset().getFullyConverted()) = 1 and
|
||||
strictcount(mostRecentSideEffect(ae)) = 1 and
|
||||
not analyzableConst(ae)
|
||||
}
|
||||
|
||||
deprecated private predicate mk_ArrayAccess(
|
||||
GVN base, GVN offset, ControlFlowNode dominator, ArrayExpr ae
|
||||
) {
|
||||
analyzableArrayAccess(ae) and
|
||||
base = globalValueNumber(ae.getArrayBase().getFullyConverted()) and
|
||||
offset = globalValueNumber(ae.getArrayOffset().getFullyConverted()) and
|
||||
dominator = mostRecentSideEffect(ae)
|
||||
}
|
||||
|
||||
private predicate analyzablePointerDereferenceExpr(PointerDereferenceExpr deref) {
|
||||
strictcount(deref.getOperand().getFullyConverted()) = 1 and
|
||||
strictcount(mostRecentSideEffect(deref)) = 1 and
|
||||
not analyzableConst(deref)
|
||||
}
|
||||
|
||||
deprecated private predicate mk_Deref(GVN p, ControlFlowNode dominator, PointerDereferenceExpr deref) {
|
||||
analyzablePointerDereferenceExpr(deref) and
|
||||
p = globalValueNumber(deref.getOperand().getFullyConverted()) and
|
||||
dominator = mostRecentSideEffect(deref)
|
||||
}
|
||||
|
||||
/** Gets the global value number of expression `e`. */
|
||||
cached
|
||||
deprecated GVN globalValueNumber(Expr e) {
|
||||
exists(int val, Type t |
|
||||
mk_IntConst(val, t, e) and
|
||||
result = GVN_IntConst(val, t)
|
||||
)
|
||||
or
|
||||
exists(float val, Type t |
|
||||
mk_FloatConst(val, t, e) and
|
||||
result = GVN_FloatConst(val, t)
|
||||
)
|
||||
or
|
||||
// Local variable with a defining value.
|
||||
exists(StackVariable x, SsaDefinition def |
|
||||
analyzableStackVariable(e) and
|
||||
e = def.getAUse(x) and
|
||||
result = globalValueNumber(def.getDefiningValue(x).getFullyConverted())
|
||||
)
|
||||
or
|
||||
// Local variable without a defining value.
|
||||
exists(StackVariable x, SsaDefinition def |
|
||||
mk_UndefinedStackVariable(x, def, e) and
|
||||
result = GVN_UndefinedStackVariable(x, def)
|
||||
)
|
||||
or
|
||||
// Variable with no SSA information.
|
||||
exists(Variable x, ControlFlowNode dominator |
|
||||
mk_OtherVariable(x, dominator, e) and
|
||||
result = GVN_OtherVariable(x, dominator)
|
||||
)
|
||||
or
|
||||
exists(GVN qualifier, Field target |
|
||||
mk_DotFieldAccess(qualifier, target, e) and
|
||||
result = GVN_FieldAccess(qualifier, target)
|
||||
)
|
||||
or
|
||||
exists(GVN qualifier, Field target |
|
||||
mk_PointerFieldAccess_with_deref(qualifier, target, e) and
|
||||
result = GVN_FieldAccess(qualifier, target)
|
||||
)
|
||||
or
|
||||
exists(GVN qualifier, Field target |
|
||||
mk_ImplicitThisFieldAccess_with_deref(qualifier, target, e) and
|
||||
result = GVN_FieldAccess(qualifier, target)
|
||||
)
|
||||
or
|
||||
exists(Function fcn |
|
||||
mk_ThisExpr(fcn, e) and
|
||||
result = GVN_ThisExpr(fcn)
|
||||
)
|
||||
or
|
||||
exists(Type t, GVN child |
|
||||
mk_Conversion(t, child, e) and
|
||||
result = GVN_Conversion(t, child)
|
||||
)
|
||||
or
|
||||
exists(GVN lhs, GVN rhs, string opname |
|
||||
mk_BinaryOp(lhs, rhs, opname, e) and
|
||||
result = GVN_BinaryOp(lhs, rhs, opname)
|
||||
)
|
||||
or
|
||||
exists(GVN child, string opname |
|
||||
mk_UnaryOp(child, opname, e) and
|
||||
result = GVN_UnaryOp(child, opname)
|
||||
)
|
||||
or
|
||||
exists(GVN x, GVN i, ControlFlowNode dominator |
|
||||
mk_ArrayAccess(x, i, dominator, e) and
|
||||
result = GVN_ArrayAccess(x, i, dominator)
|
||||
)
|
||||
or
|
||||
exists(GVN p, ControlFlowNode dominator |
|
||||
mk_Deref(p, dominator, e) and
|
||||
result = GVN_Deref(p, dominator)
|
||||
)
|
||||
or
|
||||
not analyzableExpr(e) and result = GVN_Unanalyzable(e)
|
||||
}
|
||||
|
||||
private predicate analyzableConst(Expr e) {
|
||||
analyzableIntConst(e) or
|
||||
analyzableFloatConst(e)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if the expression is explicitly handled by `globalValueNumber`.
|
||||
* Unanalyzable expressions still need to be given a global value number,
|
||||
* but it will be a unique number that is not shared with any other
|
||||
* expression.
|
||||
*/
|
||||
private predicate analyzableExpr(Expr e) {
|
||||
analyzableConst(e) or
|
||||
analyzableStackVariable(e) or
|
||||
analyzableDotFieldAccess(e) or
|
||||
analyzablePointerFieldAccess(e) or
|
||||
analyzableImplicitThisFieldAccess(e) or
|
||||
analyzableOtherVariable(e) or
|
||||
analyzableConversion(e) or
|
||||
analyzableBinaryOp(e) or
|
||||
analyzableUnaryOp(e) or
|
||||
analyzableThisExpr(e) or
|
||||
analyzableArrayAccess(e) or
|
||||
analyzablePointerDereferenceExpr(e)
|
||||
}
|
||||
@@ -1,3 +1,11 @@
|
||||
## 0.9.11
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The "Uncontrolled data used in path expression" query (`cpp/path-injection`) query produces fewer near-duplicate results.
|
||||
* The "Global variable may be used before initialization" query (`cpp/global-use-before-init`) no longer raises an alert on global variables that are initialized when they are declared.
|
||||
* The "Inconsistent null check of pointer" query (`cpp/inconsistent-nullness-testing`) query no longer raises an alert when the guarded check is in a macro expansion.
|
||||
|
||||
## 0.9.10
|
||||
|
||||
No user-facing changes.
|
||||
|
||||
@@ -88,6 +88,11 @@ module TaintedPathConfig implements DataFlow::ConfigSig {
|
||||
hasUpperBoundsCheck(checkedVar)
|
||||
)
|
||||
}
|
||||
|
||||
predicate isBarrierOut(DataFlow::Node node) {
|
||||
// make sinks barriers so that we only report the closest instance
|
||||
isSink(node)
|
||||
}
|
||||
}
|
||||
|
||||
module TaintedPath = TaintTracking::Global<TaintedPathConfig>;
|
||||
|
||||
@@ -30,6 +30,12 @@ This is because the temporary container is not bound to a rvalue reference.
|
||||
</p>
|
||||
<sample src="IteratorToExpiredContainerExtendedLifetime.cpp" />
|
||||
|
||||
<p>
|
||||
To fix <code>lifetime_of_temp_not_extended</code>, consider rewriting the code so that the lifetime of the temporary object is extended.
|
||||
In <code>fixed_lifetime_of_temp_not_extended</code>, the lifetime of the temporary object has been extended by storing it in an rvalue reference.
|
||||
</p>
|
||||
<sample src="IteratorToExpiredContainerExtendedLifetime-fixed.cpp" />
|
||||
|
||||
</example>
|
||||
<references>
|
||||
|
||||
@@ -2,9 +2,10 @@
|
||||
* @name Iterator to expired container
|
||||
* @description Using an iterator owned by a container whose lifetime has expired may lead to unexpected behavior.
|
||||
* @kind problem
|
||||
* @precision high
|
||||
* @precision medium
|
||||
* @id cpp/iterator-to-expired-container
|
||||
* @problem.severity warning
|
||||
* @security-severity 8.8
|
||||
* @tags reliability
|
||||
* security
|
||||
* external/cwe/cwe-416
|
||||
@@ -61,14 +62,38 @@ DataFlow::Node getADestroyedNode(DataFlow::Node n) {
|
||||
)
|
||||
}
|
||||
|
||||
predicate destroyedToBeginSink(DataFlow::Node sink, FunctionCall fc) {
|
||||
predicate destroyedToBeginSink(DataFlow::Node sink) {
|
||||
exists(CallInstruction call |
|
||||
call = sink.asOperand().(ThisArgumentOperand).getCall() and
|
||||
fc = call.getUnconvertedResultExpression() and
|
||||
call.getStaticCallTarget() instanceof BeginOrEndFunction
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `node1` is the node corresponding to a qualifier of a destructor
|
||||
* call and `node2` is a node that is destroyed as a result of `node1` being
|
||||
* destroyed.
|
||||
*/
|
||||
private predicate qualifierToDestroyed(DataFlow::Node node1, DataFlow::Node node2) {
|
||||
tempToDestructorSink(node1, _) and
|
||||
node2 = getADestroyedNode(node1)
|
||||
}
|
||||
|
||||
/**
|
||||
* A configuration to track flow from a destroyed node to a qualifier of
|
||||
* a `begin` or `end` function call.
|
||||
*
|
||||
* This configuration exists to prevent a cartesian product between all sinks and
|
||||
* all states in `Config::isSink`.
|
||||
*/
|
||||
module Config0 implements DataFlow::ConfigSig {
|
||||
predicate isSource(DataFlow::Node source) { qualifierToDestroyed(_, source) }
|
||||
|
||||
predicate isSink(DataFlow::Node sink) { destroyedToBeginSink(sink) }
|
||||
}
|
||||
|
||||
module Flow0 = DataFlow::Global<Config0>;
|
||||
|
||||
/**
|
||||
* A configuration to track flow from a temporary variable to the qualifier of
|
||||
* a destructor call, and subsequently to a qualifier of a call to `begin` or
|
||||
@@ -78,12 +103,15 @@ module Config implements DataFlow::StateConfigSig {
|
||||
newtype FlowState =
|
||||
additional TempToDestructor() or
|
||||
additional DestroyedToBegin(DataFlow::Node n) {
|
||||
exists(DataFlow::Node thisOperand |
|
||||
tempToDestructorSink(thisOperand, _) and
|
||||
n = getADestroyedNode(thisOperand)
|
||||
)
|
||||
any(Flow0::PathNode pn | pn.isSource()).getNode() = n
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds if `sink` is a qualifier to a call to `begin`, and `mid` is an
|
||||
* object that is destroyed.
|
||||
*/
|
||||
private predicate relevant(DataFlow::Node mid, DataFlow::Node sink) { Flow0::flow(mid, sink) }
|
||||
|
||||
predicate isSource(DataFlow::Node source, FlowState state) {
|
||||
source.asInstruction().(VariableAddressInstruction).getIRVariable() instanceof IRTempVariable and
|
||||
state = TempToDestructor()
|
||||
@@ -92,16 +120,16 @@ module Config implements DataFlow::StateConfigSig {
|
||||
predicate isAdditionalFlowStep(
|
||||
DataFlow::Node node1, FlowState state1, DataFlow::Node node2, FlowState state2
|
||||
) {
|
||||
tempToDestructorSink(node1, _) and
|
||||
state1 = TempToDestructor() and
|
||||
state2 = DestroyedToBegin(node2) and
|
||||
node2 = getADestroyedNode(node1)
|
||||
qualifierToDestroyed(node1, node2)
|
||||
}
|
||||
|
||||
predicate isSink(DataFlow::Node sink, FlowState state) {
|
||||
// Note: This is a non-trivial cartesian product!
|
||||
// Hopefully, both of these sets are quite small in practice
|
||||
destroyedToBeginSink(sink, _) and state instanceof DestroyedToBegin
|
||||
exists(DataFlow::Node mid |
|
||||
relevant(mid, sink) and
|
||||
state = DestroyedToBegin(mid)
|
||||
)
|
||||
}
|
||||
|
||||
DataFlow::FlowFeature getAFeature() {
|
||||
@@ -121,9 +149,9 @@ module Config implements DataFlow::StateConfigSig {
|
||||
|
||||
module Flow = DataFlow::GlobalWithState<Config>;
|
||||
|
||||
from Flow::PathNode source, Flow::PathNode sink, FunctionCall beginOrEnd, DataFlow::Node mid
|
||||
from Flow::PathNode source, Flow::PathNode sink, DataFlow::Node mid
|
||||
where
|
||||
Flow::flowPath(source, sink) and
|
||||
destroyedToBeginSink(sink.getNode(), beginOrEnd) and
|
||||
destroyedToBeginSink(sink.getNode()) and
|
||||
sink.getState() = Config::DestroyedToBegin(mid)
|
||||
select mid, "This object is destroyed before $@ is called.", beginOrEnd, beginOrEnd.toString()
|
||||
select mid, "This object is destroyed at the end of the full-expression."
|
||||
@@ -0,0 +1,6 @@
|
||||
void fixed_lifetime_of_temp_not_extended() {
|
||||
auto&& v = get_vector();
|
||||
for(auto x : log_and_return_argument(v)) {
|
||||
use(x); // GOOD: The lifetime of the container returned by `get_vector()` has been extended to the lifetime of `v`.
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,12 @@
|
||||
When the <code>std::string</code> object is destroyed, the pointer returned by <code>c_str</code> is no
|
||||
longer valid. If the pointer is used after the <code>std::string</code> object is destroyed, then the behavior is undefined.
|
||||
</p>
|
||||
|
||||
<p>Typically, this problem occurs when a <code>std::string</code> is returned by a function call (or overloaded operator)
|
||||
by value, and the result is not immediately stored in a variable by value or reference in a way that extends the lifetime of
|
||||
the temporary object. The resulting temporary <code>std::string</code> object is destroyed at the end of the containing expression
|
||||
statement, along with any memory returned by a call to <code>c_str</code>.
|
||||
</p>
|
||||
</overview>
|
||||
|
||||
<recommendation>
|
||||
@@ -39,6 +45,8 @@ points to valid memory.
|
||||
<references>
|
||||
|
||||
<li><a href="https://wiki.sei.cmu.edu/confluence/display/cplusplus/MEM50-CPP.+Do+not+access+freed+memory">MEM50-CPP. Do not access freed memory</a>.</li>
|
||||
<li>Microsoft Learn: <a href="https://learn.microsoft.com/en-us/cpp/cpp/temporary-objects?view=msvc-170">Temporary objects</a>.</li>
|
||||
<li>cppreference.com: <a href="https://en.cppreference.com/w/cpp/language/reference_initialization#Lifetime_of_a_temporary">Lifetime of a temporary</a>.</li>
|
||||
|
||||
</references>
|
||||
</qhelp>
|
||||
|
||||
@@ -23,4 +23,5 @@ where
|
||||
(c.getTarget() instanceof StdStringCStr or c.getTarget() instanceof StdStringData) and
|
||||
isTemporary(c.getQualifier().getFullyConverted())
|
||||
select c,
|
||||
"The underlying string object is destroyed after the call to '" + c.getTarget() + "' returns."
|
||||
"The underlying temporary string object is destroyed after the call to '" + c.getTarget() +
|
||||
"' returns."
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
---
|
||||
category: newQuery
|
||||
---
|
||||
* Added a new query, `cpp/iterator-to-expired-container`, to detect the creation of iterators owned by a temporary objects that are about to be destroyed.
|
||||
@@ -1,5 +1,7 @@
|
||||
---
|
||||
category: minorAnalysis
|
||||
---
|
||||
## 0.9.11
|
||||
|
||||
### Minor Analysis Improvements
|
||||
|
||||
* The "Uncontrolled data used in path expression" query (`cpp/path-injection`) query produces fewer near-duplicate results.
|
||||
* The "Global variable may be used before initialization" query (`cpp/global-use-before-init`) no longer raises an alert on global variables that are initialized when they are declared.
|
||||
* The "Inconsistent null check of pointer" query (`cpp/inconsistent-nullness-testing`) query no longer raises an alert when the guarded check is in a macro expansion.
|
||||
* The "Inconsistent null check of pointer" query (`cpp/inconsistent-nullness-testing`) query no longer raises an alert when the guarded check is in a macro expansion.
|
||||
@@ -1,2 +1,2 @@
|
||||
---
|
||||
lastReleaseVersion: 0.9.10
|
||||
lastReleaseVersion: 0.9.11
|
||||
|
||||
11
cpp/ql/src/experimental/Best Practices/GuardedFree.cpp
Normal file
11
cpp/ql/src/experimental/Best Practices/GuardedFree.cpp
Normal file
@@ -0,0 +1,11 @@
|
||||
void test()
|
||||
{
|
||||
char *foo = malloc(100);
|
||||
|
||||
// BAD
|
||||
if (foo)
|
||||
free(foo);
|
||||
|
||||
// GOOD
|
||||
free(foo);
|
||||
}
|
||||
18
cpp/ql/src/experimental/Best Practices/GuardedFree.qhelp
Normal file
18
cpp/ql/src/experimental/Best Practices/GuardedFree.qhelp
Normal file
@@ -0,0 +1,18 @@
|
||||
<!DOCTYPE qhelp SYSTEM "qhelp.dtd">
|
||||
<qhelp>
|
||||
<overview>
|
||||
<p>The <code>free</code> function, which deallocates heap memory, may accept a NULL pointer and take no action. Therefore, it is unnecessary to check its argument for the value of NULL before a function call to <code>free</code>. As such, these guards may hinder performance and readability.</p>
|
||||
</overview>
|
||||
<recommendation>
|
||||
<p>A function call to <code>free</code> should not depend upon the value of its argument. Delete the <code>if</code> condition preceeding a function call to <code>free</code> when its only purpose is to check the value of the pointer to be freed.</p>
|
||||
</recommendation>
|
||||
<example>
|
||||
<sample src = "GuardedFree.cpp" />
|
||||
</example>
|
||||
<references>
|
||||
<li>
|
||||
The Open Group Base Specifications Issue 7, 2018 Edition:
|
||||
<a href="https://pubs.opengroup.org/onlinepubs/9699919799/functions/free.html">free - free allocated memory</a>
|
||||
</li>
|
||||
</references>
|
||||
</qhelp>
|
||||
26
cpp/ql/src/experimental/Best Practices/GuardedFree.ql
Normal file
26
cpp/ql/src/experimental/Best Practices/GuardedFree.ql
Normal file
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* @name Guarded Free
|
||||
* @description NULL-condition guards before function calls to the memory-deallocation
|
||||
* function free(3) are unnecessary, because passing NULL to free(3) is a no-op.
|
||||
* @kind problem
|
||||
* @problem.severity recommendation
|
||||
* @precision very-high
|
||||
* @id cpp/guarded-free
|
||||
* @tags maintainability
|
||||
* readability
|
||||
* experimental
|
||||
*/
|
||||
|
||||
import cpp
|
||||
import semmle.code.cpp.controlflow.Guards
|
||||
|
||||
class FreeCall extends FunctionCall {
|
||||
FreeCall() { this.getTarget().hasGlobalName("free") }
|
||||
}
|
||||
|
||||
from GuardCondition gc, FreeCall fc, Variable v, BasicBlock bb
|
||||
where
|
||||
gc.ensuresEq(v.getAnAccess(), 0, bb, false) and
|
||||
fc.getArgument(0) = v.getAnAccess() and
|
||||
bb = fc.getEnclosingStmt()
|
||||
select gc, "unnecessary NULL check before call to $@", fc, "free"
|
||||
@@ -24,7 +24,7 @@ predicate exprMayBeString(Expr exp) {
|
||||
fctmp.getAnArgument().(VariableAccess).getTarget() = exp.(VariableAccess).getTarget() or
|
||||
globalValueNumber(fctmp.getAnArgument()) = globalValueNumber(exp)
|
||||
) and
|
||||
fctmp.getTarget().hasName(["strlen", "strcat", "strncat", "strcpy", "sptintf", "printf"])
|
||||
fctmp.getTarget().hasName(["strlen", "strcat", "strncat", "strcpy", "sprintf", "printf"])
|
||||
)
|
||||
or
|
||||
exists(AssignExpr astmp |
|
||||
|
||||
@@ -1,20 +0,0 @@
|
||||
import cpp
|
||||
|
||||
class StringVariable extends Variable {
|
||||
StringVariable() {
|
||||
this.getType().(PointerType).stripType().getName() = "char"
|
||||
}
|
||||
}
|
||||
|
||||
class StringField extends StringVariable, Field
|
||||
{
|
||||
}
|
||||
|
||||
class StringParameter extends StringVariable, Parameter
|
||||
{
|
||||
}
|
||||
|
||||
from StringVariable f
|
||||
where f.getFile().getRelativePath().matches("c/extractor/src/%")
|
||||
and not f.getASpecifier().getName() = "extern"
|
||||
select f, f.getFile().getRelativePath()
|
||||
@@ -1,9 +0,0 @@
|
||||
import cpp
|
||||
import relevant
|
||||
|
||||
from Function fn
|
||||
where
|
||||
fn.getNamespace() instanceof GlobalNamespace and
|
||||
not exists(fn.getDeclaringType()) and
|
||||
is_relevant_result(fn.getFile())
|
||||
select fn, "This function is not declared in a namespace", fn.getFile().getRelativePath()
|
||||
@@ -1,4 +0,0 @@
|
||||
import cpp
|
||||
|
||||
from Function fn
|
||||
where not exists(fn.getDeclaringType()) and is_relevant_result(fn.getFile())
|
||||
@@ -1,25 +0,0 @@
|
||||
// Flags use of global variables
|
||||
import cpp
|
||||
|
||||
class RelevantGlobalVariable extends GlobalVariable
|
||||
{
|
||||
RelevantGlobalVariable() {
|
||||
any()
|
||||
}
|
||||
}
|
||||
|
||||
predicate is_valid_global_variable(Variable var) {
|
||||
var.getType().stripType().getName() = "trie_node" or
|
||||
var.getType().isConst() or
|
||||
var.getType().isDeeplyConst() or
|
||||
var.isConstexpr() or
|
||||
var.getType() instanceof ArrayType or
|
||||
var.getASpecifier().getName() = "extern" or
|
||||
var.getFile().getRelativePath().matches("c/extractor/edg/%")
|
||||
}
|
||||
|
||||
from GlobalVariable globalVariable, string typeName
|
||||
where
|
||||
not is_valid_global_variable(globalVariable) and
|
||||
typeName = globalVariable.getType().stripType().getName()
|
||||
select globalVariable, typeName, globalVariable.getFile().getRelativePath()
|
||||
@@ -1,7 +0,0 @@
|
||||
import cpp
|
||||
import relevant
|
||||
|
||||
from Call call
|
||||
where call.getTarget().getName().matches("%printf")
|
||||
and is_relevant_result(call.getFile())
|
||||
select call, "Call to a printf formatter", call.getFile().getRelativePath()
|
||||
@@ -1,6 +0,0 @@
|
||||
import cpp
|
||||
|
||||
predicate is_relevant_result(File file)
|
||||
{
|
||||
not file.getRelativePath().matches("c/extractor/edg%")
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
import cpp
|
||||
|
||||
class ACompressedFileWrite extends Function {
|
||||
ACompressedFileWrite() {
|
||||
this.getName() = "operator<<" and
|
||||
this.getParameter(0).getType().stripType().getName() = "a_compressed_file"
|
||||
}
|
||||
}
|
||||
|
||||
class LabelDefinition extends Call {
|
||||
LabelDefinition() {
|
||||
this.getTarget() instanceof ACompressedFileWrite and
|
||||
this.getArgument(1).(StringLiteral).getValue().matches("=%")
|
||||
}
|
||||
}
|
||||
|
||||
predicate is_valid_file_write(Call call) {
|
||||
call.getFile().getBaseName() = "dbscheme.cpp"
|
||||
}
|
||||
|
||||
from Call call
|
||||
where
|
||||
call.getTarget() instanceof ACompressedFileWrite
|
||||
and not is_valid_file_write(call)
|
||||
select call
|
||||
@@ -1,5 +1,5 @@
|
||||
name: codeql/cpp-queries
|
||||
version: 0.9.11-dev
|
||||
version: 0.9.12-dev
|
||||
groups:
|
||||
- cpp
|
||||
- queries
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
| test.cpp:680:30:680:30 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:680:17:680:17 | call to begin | call to begin |
|
||||
| test.cpp:680:30:680:30 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:680:17:680:17 | call to end | call to end |
|
||||
| test.cpp:683:31:683:32 | call to at | This object is destroyed before $@ is called. | test.cpp:683:17:683:17 | call to begin | call to begin |
|
||||
| test.cpp:683:31:683:32 | call to at | This object is destroyed before $@ is called. | test.cpp:683:17:683:17 | call to end | call to end |
|
||||
| test.cpp:689:46:689:58 | pointer to ~vector output argument | This object is destroyed before $@ is called. | test.cpp:689:60:689:62 | call to end | call to end |
|
||||
| test.cpp:702:27:702:27 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:703:19:703:23 | call to begin | call to begin |
|
||||
| test.cpp:702:27:702:27 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:703:36:703:38 | call to end | call to end |
|
||||
| test.cpp:727:23:727:23 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:750:17:750:17 | call to begin | call to begin |
|
||||
| test.cpp:727:23:727:23 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:750:17:750:17 | call to end | call to end |
|
||||
| test.cpp:735:23:735:23 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:759:17:759:17 | call to begin | call to begin |
|
||||
| test.cpp:735:23:735:23 | call to operator[] | This object is destroyed before $@ is called. | test.cpp:759:17:759:17 | call to end | call to end |
|
||||
@@ -1 +0,0 @@
|
||||
experimental/Security/CWE/CWE-416/IteratorToExpiredContainer.ql
|
||||
@@ -56,6 +56,8 @@ astGuardsCompare
|
||||
| 17 | y < 1+1 when ... > ... is false |
|
||||
| 17 | y >= 1+1 when ... && ... is true |
|
||||
| 17 | y >= 1+1 when ... > ... is true |
|
||||
| 18 | call to get != 0 when call to get is true |
|
||||
| 18 | call to get == 0 when call to get is false |
|
||||
| 26 | 0 < x+0 when ... > ... is true |
|
||||
| 26 | 0 >= x+0 when ... > ... is false |
|
||||
| 26 | x < 0+1 when ... > ... is false |
|
||||
@@ -146,6 +148,24 @@ astGuardsCompare
|
||||
| 109 | y < 0+0 when ... < ... is true |
|
||||
| 109 | y >= 0+0 when ... < ... is false |
|
||||
| 109 | y >= 0+0 when ... \|\| ... is false |
|
||||
| 126 | 1 != 0 when 1 is true |
|
||||
| 126 | 1 != 0 when ... && ... is true |
|
||||
| 126 | 1 == 0 when 1 is false |
|
||||
| 126 | call to test3_condition != 0 when ... && ... is true |
|
||||
| 126 | call to test3_condition != 0 when call to test3_condition is true |
|
||||
| 126 | call to test3_condition == 0 when call to test3_condition is false |
|
||||
| 131 | b != 0 when b is true |
|
||||
| 131 | b == 0 when b is false |
|
||||
| 137 | 0 != 0 when 0 is true |
|
||||
| 137 | 0 == 0 when 0 is false |
|
||||
| 146 | ! ... != 0 when ! ... is true |
|
||||
| 146 | ! ... == 0 when ! ... is false |
|
||||
| 152 | x != 0 when ... && ... is true |
|
||||
| 152 | x != 0 when x is true |
|
||||
| 152 | x == 0 when x is false |
|
||||
| 152 | y != 0 when ... && ... is true |
|
||||
| 152 | y != 0 when y is true |
|
||||
| 152 | y == 0 when y is false |
|
||||
| 156 | ... + ... != x+0 when ... == ... is false |
|
||||
| 156 | ... + ... == x+0 when ... == ... is true |
|
||||
| 156 | x != ... + ...+0 when ... == ... is false |
|
||||
@@ -184,6 +204,8 @@ astGuardsCompare
|
||||
| 175 | call to foo != 0+0 when ... == ... is false |
|
||||
| 175 | call to foo == 0 when ... == ... is true |
|
||||
| 175 | call to foo == 0+0 when ... == ... is true |
|
||||
| 181 | x != 0 when x is true |
|
||||
| 181 | x == 0 when x is false |
|
||||
astGuardsControl
|
||||
| test.c:7:9:7:13 | ... > ... | false | 10 | 11 |
|
||||
| test.c:7:9:7:13 | ... > ... | true | 7 | 9 |
|
||||
@@ -485,8 +507,28 @@ astGuardsEnsure_const
|
||||
| test.c:109:9:109:14 | ... == ... | test.c:109:9:109:9 | x | != | 0 | 109 | 109 |
|
||||
| test.c:109:9:109:14 | ... == ... | test.c:109:9:109:9 | x | != | 0 | 113 | 113 |
|
||||
| test.c:109:9:109:23 | ... \|\| ... | test.c:109:9:109:9 | x | != | 0 | 113 | 113 |
|
||||
| test.c:126:7:126:7 | 1 | test.c:126:7:126:7 | 1 | != | 0 | 126 | 126 |
|
||||
| test.c:126:7:126:7 | 1 | test.c:126:7:126:7 | 1 | != | 0 | 126 | 128 |
|
||||
| test.c:126:7:126:7 | 1 | test.c:126:7:126:7 | 1 | != | 0 | 131 | 131 |
|
||||
| test.c:126:7:126:7 | 1 | test.c:126:7:126:7 | 1 | != | 0 | 131 | 132 |
|
||||
| test.c:126:7:126:7 | 1 | test.c:126:7:126:7 | 1 | != | 0 | 134 | 123 |
|
||||
| test.c:126:7:126:28 | ... && ... | test.c:126:7:126:7 | 1 | != | 0 | 126 | 128 |
|
||||
| test.c:126:7:126:28 | ... && ... | test.c:126:12:126:26 | call to test3_condition | != | 0 | 126 | 128 |
|
||||
| test.c:126:12:126:26 | call to test3_condition | test.c:126:12:126:26 | call to test3_condition | != | 0 | 126 | 128 |
|
||||
| test.c:131:7:131:7 | b | test.c:131:7:131:7 | b | != | 0 | 131 | 132 |
|
||||
| test.c:137:7:137:7 | 0 | test.c:137:7:137:7 | 0 | == | 0 | 142 | 136 |
|
||||
| test.c:146:7:146:8 | ! ... | test.c:146:7:146:8 | ! ... | != | 0 | 146 | 147 |
|
||||
| test.c:152:10:152:10 | x | test.c:152:10:152:10 | x | != | 0 | 151 | 152 |
|
||||
| test.c:152:10:152:10 | x | test.c:152:10:152:10 | x | != | 0 | 152 | 152 |
|
||||
| test.c:152:10:152:15 | ... && ... | test.c:152:10:152:10 | x | != | 0 | 151 | 152 |
|
||||
| test.c:152:10:152:15 | ... && ... | test.c:152:15:152:15 | y | != | 0 | 151 | 152 |
|
||||
| test.c:152:15:152:15 | y | test.c:152:15:152:15 | y | != | 0 | 151 | 152 |
|
||||
| test.c:175:13:175:32 | ... == ... | test.c:175:13:175:15 | call to foo | != | 0 | 175 | 175 |
|
||||
| test.c:175:13:175:32 | ... == ... | test.c:175:13:175:15 | call to foo | == | 0 | 175 | 175 |
|
||||
| test.c:181:9:181:9 | x | test.c:181:9:181:9 | x | != | 0 | 181 | 182 |
|
||||
| test.c:181:9:181:9 | x | test.c:181:9:181:9 | x | != | 0 | 186 | 180 |
|
||||
| test.c:181:9:181:9 | x | test.c:181:9:181:9 | x | == | 0 | 183 | 184 |
|
||||
| test.cpp:18:8:18:10 | call to get | test.cpp:18:8:18:10 | call to get | != | 0 | 19 | 19 |
|
||||
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | != | -1 | 30 | 30 |
|
||||
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | != | -1 | 34 | 34 |
|
||||
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | == | -1 | 30 | 30 |
|
||||
@@ -545,6 +587,8 @@ irGuardsCompare
|
||||
| 17 | y < 2 when CompareGT: ... > ... is false |
|
||||
| 17 | y >= 1+1 when CompareGT: ... > ... is true |
|
||||
| 17 | y >= 2 when CompareGT: ... > ... is true |
|
||||
| 18 | call to get != 0 when CompareNE: (bool)... is true |
|
||||
| 18 | call to get == 0 when CompareNE: (bool)... is false |
|
||||
| 26 | 0 < x+0 when CompareGT: ... > ... is true |
|
||||
| 26 | 0 >= x+0 when CompareGT: ... > ... is false |
|
||||
| 26 | x < 0+1 when CompareGT: ... > ... is false |
|
||||
@@ -635,6 +679,20 @@ irGuardsCompare
|
||||
| 109 | y < 0+0 when CompareLT: ... < ... is true |
|
||||
| 109 | y >= 0 when CompareLT: ... < ... is false |
|
||||
| 109 | y >= 0+0 when CompareLT: ... < ... is false |
|
||||
| 126 | 1 != 0 when Constant: 1 is true |
|
||||
| 126 | 1 == 0 when Constant: 1 is false |
|
||||
| 126 | call to test3_condition != 0 when Call: call to test3_condition is true |
|
||||
| 126 | call to test3_condition == 0 when Call: call to test3_condition is false |
|
||||
| 131 | b != 0 when Load: b is true |
|
||||
| 131 | b == 0 when Load: b is false |
|
||||
| 137 | 0 != 0 when Constant: 0 is true |
|
||||
| 137 | 0 == 0 when Constant: 0 is false |
|
||||
| 146 | ! ... != 0 when LogicalNot: ! ... is true |
|
||||
| 146 | ! ... == 0 when LogicalNot: ! ... is false |
|
||||
| 152 | x != 0 when Load: x is true |
|
||||
| 152 | x == 0 when Load: x is false |
|
||||
| 152 | y != 0 when Load: y is true |
|
||||
| 152 | y == 0 when Load: y is false |
|
||||
| 156 | ... + ... != x+0 when CompareEQ: ... == ... is false |
|
||||
| 156 | ... + ... == x+0 when CompareEQ: ... == ... is true |
|
||||
| 156 | x != ... + ...+0 when CompareEQ: ... == ... is false |
|
||||
@@ -673,6 +731,8 @@ irGuardsCompare
|
||||
| 175 | call to foo != 0+0 when CompareEQ: ... == ... is false |
|
||||
| 175 | call to foo == 0 when CompareEQ: ... == ... is true |
|
||||
| 175 | call to foo == 0+0 when CompareEQ: ... == ... is true |
|
||||
| 181 | x != 0 when Load: x is true |
|
||||
| 181 | x == 0 when Load: x is false |
|
||||
irGuardsControl
|
||||
| test.c:7:9:7:13 | CompareGT: ... > ... | false | 11 | 11 |
|
||||
| test.c:7:9:7:13 | CompareGT: ... > ... | true | 8 | 8 |
|
||||
@@ -994,8 +1054,22 @@ irGuardsEnsure_const
|
||||
| test.c:109:9:109:14 | CompareEQ: ... == ... | test.c:109:9:109:9 | Load: x | != | 0 | 109 | 109 |
|
||||
| test.c:109:9:109:14 | CompareEQ: ... == ... | test.c:109:9:109:9 | Load: x | != | 0 | 113 | 113 |
|
||||
| test.c:109:19:109:23 | CompareLT: ... < ... | test.c:109:19:109:19 | Load: y | >= | 0 | 113 | 113 |
|
||||
| test.c:126:7:126:7 | Constant: 1 | test.c:126:7:126:7 | Constant: 1 | != | 0 | 126 | 126 |
|
||||
| test.c:126:7:126:7 | Constant: 1 | test.c:126:7:126:7 | Constant: 1 | != | 0 | 127 | 127 |
|
||||
| test.c:126:7:126:7 | Constant: 1 | test.c:126:7:126:7 | Constant: 1 | != | 0 | 131 | 131 |
|
||||
| test.c:126:7:126:7 | Constant: 1 | test.c:126:7:126:7 | Constant: 1 | != | 0 | 132 | 132 |
|
||||
| test.c:126:7:126:7 | Constant: 1 | test.c:126:7:126:7 | Constant: 1 | != | 0 | 134 | 134 |
|
||||
| test.c:126:12:126:26 | Call: call to test3_condition | test.c:126:12:126:26 | Call: call to test3_condition | != | 0 | 127 | 127 |
|
||||
| test.c:131:7:131:7 | Load: b | test.c:131:7:131:7 | Load: b | != | 0 | 132 | 132 |
|
||||
| test.c:137:7:137:7 | Constant: 0 | test.c:137:7:137:7 | Constant: 0 | == | 0 | 142 | 142 |
|
||||
| test.c:146:7:146:8 | LogicalNot: ! ... | test.c:146:7:146:8 | LogicalNot: ! ... | != | 0 | 147 | 147 |
|
||||
| test.c:152:10:152:10 | Load: x | test.c:152:10:152:10 | Load: x | != | 0 | 152 | 152 |
|
||||
| test.c:152:15:152:15 | Load: y | test.c:152:15:152:15 | Load: y | != | 0 | 152 | 152 |
|
||||
| test.c:175:13:175:32 | CompareEQ: ... == ... | test.c:175:13:175:15 | Call: call to foo | != | 0 | 175 | 175 |
|
||||
| test.c:175:13:175:32 | CompareEQ: ... == ... | test.c:175:13:175:15 | Call: call to foo | == | 0 | 175 | 175 |
|
||||
| test.c:181:9:181:9 | Load: x | test.c:181:9:181:9 | Load: x | != | 0 | 182 | 182 |
|
||||
| test.c:181:9:181:9 | Load: x | test.c:181:9:181:9 | Load: x | == | 0 | 184 | 184 |
|
||||
| test.cpp:18:8:18:12 | CompareNE: (bool)... | test.cpp:18:8:18:10 | Call: call to get | != | 0 | 19 | 19 |
|
||||
| test.cpp:31:7:31:13 | CompareEQ: ... == ... | test.cpp:31:7:31:7 | Load: x | != | -1 | 34 | 34 |
|
||||
| test.cpp:31:7:31:13 | CompareEQ: ... == ... | test.cpp:31:7:31:7 | Load: x | == | -1 | 30 | 30 |
|
||||
| test.cpp:31:7:31:13 | CompareEQ: ... == ... | test.cpp:31:7:31:7 | Load: x | == | -1 | 32 | 32 |
|
||||
|
||||
@@ -26,9 +26,19 @@
|
||||
| test.c:137:7:137:7 | 0 |
|
||||
| test.c:146:7:146:8 | ! ... |
|
||||
| test.c:146:8:146:8 | x |
|
||||
| test.c:152:8:152:8 | p |
|
||||
| test.c:158:8:158:9 | ! ... |
|
||||
| test.c:158:9:158:9 | p |
|
||||
| test.c:164:8:164:8 | s |
|
||||
| test.c:170:8:170:9 | ! ... |
|
||||
| test.c:170:9:170:9 | s |
|
||||
| test.cpp:18:8:18:10 | call to get |
|
||||
| test.cpp:31:7:31:13 | ... == ... |
|
||||
| test.cpp:42:13:42:20 | call to getABool |
|
||||
| test.cpp:61:10:61:10 | i |
|
||||
| test.cpp:74:10:74:10 | i |
|
||||
| test.cpp:84:10:84:10 | i |
|
||||
| test.cpp:93:6:93:6 | c |
|
||||
| test.cpp:99:6:99:6 | f |
|
||||
| test.cpp:105:6:105:14 | ... != ... |
|
||||
| test.cpp:111:6:111:14 | ... != ... |
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
| 17 | y >= 1+1 when ... > ... is true |
|
||||
| 17 | y >= 2 when ... && ... is true |
|
||||
| 17 | y >= 2 when ... > ... is true |
|
||||
| 18 | call to get != 0 when call to get is true |
|
||||
| 18 | call to get == 0 when call to get is false |
|
||||
| 26 | 0 < x+0 when ... > ... is true |
|
||||
| 26 | 0 >= x+0 when ... > ... is false |
|
||||
| 26 | x < 0+1 when ... > ... is false |
|
||||
@@ -107,6 +109,8 @@
|
||||
| 85 | y != 0+0 when ... && ... is true |
|
||||
| 85 | y == 0 when ... != ... is false |
|
||||
| 85 | y == 0+0 when ... != ... is false |
|
||||
| 93 | c != 0 when c is true |
|
||||
| 93 | c == 0 when c is false |
|
||||
| 94 | 0 != x+0 when ... != ... is true |
|
||||
| 94 | 0 == x+0 when ... != ... is false |
|
||||
| 94 | x != 0 when ... != ... is true |
|
||||
@@ -119,6 +123,10 @@
|
||||
| 102 | j < 10+0 when ... < ... is true |
|
||||
| 102 | j >= 10 when ... < ... is false |
|
||||
| 102 | j >= 10+0 when ... < ... is false |
|
||||
| 105 | 0.0 != f+0 when ... != ... is true |
|
||||
| 105 | 0.0 == f+0 when ... != ... is false |
|
||||
| 105 | f != 0.0+0 when ... != ... is true |
|
||||
| 105 | f == 0.0+0 when ... != ... is false |
|
||||
| 109 | 0 != x+0 when ... == ... is false |
|
||||
| 109 | 0 != x+0 when ... \|\| ... is false |
|
||||
| 109 | 0 < y+1 when ... < ... is false |
|
||||
@@ -137,3 +145,27 @@
|
||||
| 109 | y >= 0 when ... \|\| ... is false |
|
||||
| 109 | y >= 0+0 when ... < ... is false |
|
||||
| 109 | y >= 0+0 when ... \|\| ... is false |
|
||||
| 111 | 0.0 != i+0 when ... != ... is true |
|
||||
| 111 | 0.0 == i+0 when ... != ... is false |
|
||||
| 111 | i != 0.0+0 when ... != ... is true |
|
||||
| 111 | i == 0.0+0 when ... != ... is false |
|
||||
| 126 | 1 != 0 when 1 is true |
|
||||
| 126 | 1 != 0 when ... && ... is true |
|
||||
| 126 | 1 == 0 when 1 is false |
|
||||
| 126 | call to test3_condition != 0 when ... && ... is true |
|
||||
| 126 | call to test3_condition != 0 when call to test3_condition is true |
|
||||
| 126 | call to test3_condition == 0 when call to test3_condition is false |
|
||||
| 131 | b != 0 when b is true |
|
||||
| 131 | b == 0 when b is false |
|
||||
| 137 | 0 != 0 when 0 is true |
|
||||
| 137 | 0 == 0 when 0 is false |
|
||||
| 146 | ! ... != 0 when ! ... is true |
|
||||
| 146 | ! ... == 0 when ! ... is false |
|
||||
| 152 | p != 0 when p is true |
|
||||
| 152 | p == 0 when p is false |
|
||||
| 158 | ! ... != 0 when ! ... is true |
|
||||
| 158 | ! ... == 0 when ! ... is false |
|
||||
| 164 | s != 0 when s is true |
|
||||
| 164 | s == 0 when s is false |
|
||||
| 170 | ! ... != 0 when ! ... is true |
|
||||
| 170 | ! ... == 0 when ! ... is false |
|
||||
|
||||
@@ -79,6 +79,12 @@
|
||||
| test.c:137:7:137:7 | 0 | false | 142 | 136 |
|
||||
| test.c:146:7:146:8 | ! ... | true | 146 | 147 |
|
||||
| test.c:146:8:146:8 | x | false | 146 | 147 |
|
||||
| test.c:152:8:152:8 | p | true | 152 | 154 |
|
||||
| test.c:158:8:158:9 | ! ... | true | 158 | 160 |
|
||||
| test.c:158:9:158:9 | p | false | 158 | 160 |
|
||||
| test.c:164:8:164:8 | s | true | 164 | 166 |
|
||||
| test.c:170:8:170:9 | ! ... | true | 170 | 172 |
|
||||
| test.c:170:9:170:9 | s | false | 170 | 172 |
|
||||
| test.cpp:18:8:18:10 | call to get | true | 19 | 19 |
|
||||
| test.cpp:31:7:31:13 | ... == ... | false | 30 | 30 |
|
||||
| test.cpp:31:7:31:13 | ... == ... | false | 34 | 34 |
|
||||
@@ -90,3 +96,7 @@
|
||||
| test.cpp:61:10:61:10 | i | Case[1] | 65 | 66 |
|
||||
| test.cpp:74:10:74:10 | i | Case[0..10] | 75 | 77 |
|
||||
| test.cpp:74:10:74:10 | i | Case[11..20] | 78 | 79 |
|
||||
| test.cpp:93:6:93:6 | c | true | 93 | 94 |
|
||||
| test.cpp:99:6:99:6 | f | true | 99 | 100 |
|
||||
| test.cpp:105:6:105:14 | ... != ... | true | 105 | 106 |
|
||||
| test.cpp:111:6:111:14 | ... != ... | true | 111 | 112 |
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
binary
|
||||
| test.c:7:9:7:13 | ... > ... | test.c:7:9:7:9 | x | < | test.c:7:13:7:13 | 0 | 1 | 10 | 11 |
|
||||
| test.c:7:9:7:13 | ... > ... | test.c:7:9:7:9 | x | >= | test.c:7:13:7:13 | 0 | 1 | 7 | 9 |
|
||||
| test.c:7:9:7:13 | ... > ... | test.c:7:13:7:13 | 0 | < | test.c:7:9:7:9 | x | 0 | 7 | 9 |
|
||||
@@ -154,3 +155,109 @@
|
||||
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:12:31:13 | - ... | != | test.cpp:31:7:31:7 | x | 0 | 34 | 34 |
|
||||
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:12:31:13 | - ... | == | test.cpp:31:7:31:7 | x | 0 | 30 | 30 |
|
||||
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:12:31:13 | - ... | == | test.cpp:31:7:31:7 | x | 0 | 31 | 32 |
|
||||
| test.cpp:105:6:105:14 | ... != ... | test.cpp:105:6:105:6 | f | != | test.cpp:105:11:105:14 | 0.0 | 0 | 105 | 106 |
|
||||
| test.cpp:105:6:105:14 | ... != ... | test.cpp:105:11:105:14 | 0.0 | != | test.cpp:105:6:105:6 | f | 0 | 105 | 106 |
|
||||
| test.cpp:111:6:111:14 | ... != ... | test.cpp:111:6:111:6 | i | != | test.cpp:111:11:111:14 | 0.0 | 0 | 111 | 112 |
|
||||
| test.cpp:111:6:111:14 | ... != ... | test.cpp:111:11:111:14 | 0.0 | != | test.cpp:111:6:111:6 | i | 0 | 111 | 112 |
|
||||
unary
|
||||
| test.c:7:9:7:13 | ... > ... | test.c:7:9:7:9 | x | < | 1 | 10 | 11 |
|
||||
| test.c:7:9:7:13 | ... > ... | test.c:7:9:7:9 | x | >= | 1 | 7 | 9 |
|
||||
| test.c:17:8:17:12 | ... < ... | test.c:17:8:17:8 | x | < | 0 | 17 | 17 |
|
||||
| test.c:17:8:17:12 | ... < ... | test.c:17:8:17:8 | x | < | 0 | 18 | 18 |
|
||||
| test.c:17:8:17:21 | ... && ... | test.c:17:8:17:8 | x | < | 0 | 18 | 18 |
|
||||
| test.c:17:8:17:21 | ... && ... | test.c:17:17:17:17 | y | >= | 2 | 18 | 18 |
|
||||
| test.c:17:17:17:21 | ... > ... | test.c:17:17:17:17 | y | >= | 2 | 18 | 18 |
|
||||
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | < | 1 | 2 | 2 |
|
||||
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | < | 1 | 31 | 34 |
|
||||
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | < | 1 | 34 | 34 |
|
||||
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | < | 1 | 39 | 42 |
|
||||
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | < | 1 | 42 | 42 |
|
||||
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | < | 1 | 42 | 44 |
|
||||
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | < | 1 | 45 | 45 |
|
||||
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | < | 1 | 45 | 47 |
|
||||
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | < | 1 | 51 | 53 |
|
||||
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | < | 1 | 56 | 58 |
|
||||
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | < | 1 | 58 | 58 |
|
||||
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | < | 1 | 58 | 66 |
|
||||
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | < | 1 | 62 | 62 |
|
||||
| test.c:26:11:26:15 | ... > ... | test.c:26:11:26:11 | x | >= | 1 | 26 | 28 |
|
||||
| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:16 | j | < | 10 | 34 | 34 |
|
||||
| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:16 | j | >= | 10 | 2 | 2 |
|
||||
| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:16 | j | >= | 10 | 39 | 42 |
|
||||
| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:16 | j | >= | 10 | 42 | 42 |
|
||||
| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:16 | j | >= | 10 | 42 | 44 |
|
||||
| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:16 | j | >= | 10 | 45 | 45 |
|
||||
| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:16 | j | >= | 10 | 45 | 47 |
|
||||
| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:16 | j | >= | 10 | 51 | 53 |
|
||||
| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:16 | j | >= | 10 | 56 | 58 |
|
||||
| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:16 | j | >= | 10 | 58 | 58 |
|
||||
| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:16 | j | >= | 10 | 58 | 66 |
|
||||
| test.c:34:16:34:21 | ... < ... | test.c:34:16:34:16 | j | >= | 10 | 62 | 62 |
|
||||
| test.c:42:16:42:21 | ... < ... | test.c:42:16:42:16 | j | < | 10 | 42 | 42 |
|
||||
| test.c:42:16:42:21 | ... < ... | test.c:42:16:42:16 | j | < | 10 | 42 | 44 |
|
||||
| test.c:42:16:42:21 | ... < ... | test.c:42:16:42:16 | j | < | 10 | 45 | 45 |
|
||||
| test.c:42:16:42:21 | ... < ... | test.c:42:16:42:16 | j | < | 10 | 45 | 47 |
|
||||
| test.c:42:16:42:21 | ... < ... | test.c:42:16:42:16 | j | < | 10 | 51 | 53 |
|
||||
| test.c:44:12:44:16 | ... > ... | test.c:44:12:44:12 | z | < | 1 | 42 | 42 |
|
||||
| test.c:44:12:44:16 | ... > ... | test.c:44:12:44:12 | z | < | 1 | 51 | 53 |
|
||||
| test.c:44:12:44:16 | ... > ... | test.c:44:12:44:12 | z | >= | 1 | 45 | 45 |
|
||||
| test.c:44:12:44:16 | ... > ... | test.c:44:12:44:12 | z | >= | 1 | 45 | 47 |
|
||||
| test.c:45:16:45:20 | ... > ... | test.c:45:16:45:16 | y | >= | 1 | 45 | 47 |
|
||||
| test.c:58:9:58:14 | ... == ... | test.c:58:9:58:9 | x | != | 0 | 58 | 58 |
|
||||
| test.c:58:9:58:14 | ... == ... | test.c:58:9:58:9 | x | != | 0 | 62 | 62 |
|
||||
| test.c:58:9:58:23 | ... \|\| ... | test.c:58:9:58:9 | x | != | 0 | 62 | 62 |
|
||||
| test.c:58:9:58:23 | ... \|\| ... | test.c:58:19:58:19 | y | >= | 0 | 62 | 62 |
|
||||
| test.c:58:19:58:23 | ... < ... | test.c:58:19:58:19 | y | >= | 0 | 62 | 62 |
|
||||
| test.c:75:9:75:14 | ... == ... | test.c:75:9:75:9 | x | != | 0 | 78 | 79 |
|
||||
| test.c:75:9:75:14 | ... == ... | test.c:75:9:75:9 | x | == | 0 | 75 | 77 |
|
||||
| test.c:85:8:85:13 | ... == ... | test.c:85:8:85:8 | x | == | 0 | 85 | 85 |
|
||||
| test.c:85:8:85:13 | ... == ... | test.c:85:8:85:8 | x | == | 0 | 86 | 86 |
|
||||
| test.c:85:8:85:23 | ... && ... | test.c:85:8:85:8 | x | == | 0 | 86 | 86 |
|
||||
| test.c:85:8:85:23 | ... && ... | test.c:85:18:85:18 | y | != | 0 | 86 | 86 |
|
||||
| test.c:85:18:85:23 | ... != ... | test.c:85:18:85:18 | y | != | 0 | 86 | 86 |
|
||||
| test.c:94:11:94:16 | ... != ... | test.c:94:11:94:11 | x | != | 0 | 94 | 96 |
|
||||
| test.c:94:11:94:16 | ... != ... | test.c:94:11:94:11 | x | == | 0 | 70 | 70 |
|
||||
| test.c:94:11:94:16 | ... != ... | test.c:94:11:94:11 | x | == | 0 | 99 | 102 |
|
||||
| test.c:94:11:94:16 | ... != ... | test.c:94:11:94:11 | x | == | 0 | 102 | 102 |
|
||||
| test.c:94:11:94:16 | ... != ... | test.c:94:11:94:11 | x | == | 0 | 107 | 109 |
|
||||
| test.c:94:11:94:16 | ... != ... | test.c:94:11:94:11 | x | == | 0 | 109 | 109 |
|
||||
| test.c:94:11:94:16 | ... != ... | test.c:94:11:94:11 | x | == | 0 | 109 | 117 |
|
||||
| test.c:94:11:94:16 | ... != ... | test.c:94:11:94:11 | x | == | 0 | 113 | 113 |
|
||||
| test.c:102:16:102:21 | ... < ... | test.c:102:16:102:16 | j | < | 10 | 102 | 102 |
|
||||
| test.c:102:16:102:21 | ... < ... | test.c:102:16:102:16 | j | >= | 10 | 70 | 70 |
|
||||
| test.c:102:16:102:21 | ... < ... | test.c:102:16:102:16 | j | >= | 10 | 107 | 109 |
|
||||
| test.c:102:16:102:21 | ... < ... | test.c:102:16:102:16 | j | >= | 10 | 109 | 109 |
|
||||
| test.c:102:16:102:21 | ... < ... | test.c:102:16:102:16 | j | >= | 10 | 109 | 117 |
|
||||
| test.c:102:16:102:21 | ... < ... | test.c:102:16:102:16 | j | >= | 10 | 113 | 113 |
|
||||
| test.c:109:9:109:14 | ... == ... | test.c:109:9:109:9 | x | != | 0 | 109 | 109 |
|
||||
| test.c:109:9:109:14 | ... == ... | test.c:109:9:109:9 | x | != | 0 | 113 | 113 |
|
||||
| test.c:109:9:109:23 | ... \|\| ... | test.c:109:9:109:9 | x | != | 0 | 113 | 113 |
|
||||
| test.c:109:9:109:23 | ... \|\| ... | test.c:109:19:109:19 | y | >= | 0 | 113 | 113 |
|
||||
| test.c:109:19:109:23 | ... < ... | test.c:109:19:109:19 | y | >= | 0 | 113 | 113 |
|
||||
| test.c:126:7:126:7 | 1 | test.c:126:7:126:7 | 1 | != | 0 | 126 | 126 |
|
||||
| test.c:126:7:126:7 | 1 | test.c:126:7:126:7 | 1 | != | 0 | 126 | 128 |
|
||||
| test.c:126:7:126:7 | 1 | test.c:126:7:126:7 | 1 | != | 0 | 131 | 131 |
|
||||
| test.c:126:7:126:7 | 1 | test.c:126:7:126:7 | 1 | != | 0 | 131 | 132 |
|
||||
| test.c:126:7:126:7 | 1 | test.c:126:7:126:7 | 1 | != | 0 | 134 | 123 |
|
||||
| test.c:126:7:126:28 | ... && ... | test.c:126:7:126:7 | 1 | != | 0 | 126 | 128 |
|
||||
| test.c:126:7:126:28 | ... && ... | test.c:126:12:126:26 | call to test3_condition | != | 0 | 126 | 128 |
|
||||
| test.c:126:12:126:26 | call to test3_condition | test.c:126:12:126:26 | call to test3_condition | != | 0 | 126 | 128 |
|
||||
| test.c:131:7:131:7 | b | test.c:131:7:131:7 | b | != | 0 | 131 | 132 |
|
||||
| test.c:137:7:137:7 | 0 | test.c:137:7:137:7 | 0 | == | 0 | 142 | 136 |
|
||||
| test.c:146:7:146:8 | ! ... | test.c:146:7:146:8 | ! ... | != | 0 | 146 | 147 |
|
||||
| test.c:152:8:152:8 | p | test.c:152:8:152:8 | p | != | 0 | 152 | 154 |
|
||||
| test.c:158:8:158:9 | ! ... | test.c:158:8:158:9 | ! ... | != | 0 | 158 | 160 |
|
||||
| test.c:164:8:164:8 | s | test.c:164:8:164:8 | s | != | 0 | 164 | 166 |
|
||||
| test.c:170:8:170:9 | ! ... | test.c:170:8:170:9 | ! ... | != | 0 | 170 | 172 |
|
||||
| test.cpp:18:8:18:10 | call to get | test.cpp:18:8:18:10 | call to get | != | 0 | 19 | 19 |
|
||||
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | != | -1 | 30 | 30 |
|
||||
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | != | -1 | 34 | 34 |
|
||||
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | == | -1 | 30 | 30 |
|
||||
| test.cpp:31:7:31:13 | ... == ... | test.cpp:31:7:31:7 | x | == | -1 | 31 | 32 |
|
||||
| test.cpp:61:10:61:10 | i | test.cpp:61:10:61:10 | i | == | 0 | 62 | 64 |
|
||||
| test.cpp:61:10:61:10 | i | test.cpp:61:10:61:10 | i | == | 1 | 65 | 66 |
|
||||
| test.cpp:74:10:74:10 | i | test.cpp:74:10:74:10 | i | < | 11 | 75 | 77 |
|
||||
| test.cpp:74:10:74:10 | i | test.cpp:74:10:74:10 | i | < | 21 | 78 | 79 |
|
||||
| test.cpp:74:10:74:10 | i | test.cpp:74:10:74:10 | i | >= | 0 | 75 | 77 |
|
||||
| test.cpp:74:10:74:10 | i | test.cpp:74:10:74:10 | i | >= | 11 | 78 | 79 |
|
||||
| test.cpp:93:6:93:6 | c | test.cpp:93:6:93:6 | c | != | 0 | 93 | 94 |
|
||||
|
||||
@@ -7,8 +7,9 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.controlflow.Guards
|
||||
|
||||
from GuardCondition guard, Expr left, Expr right, int k, int start, int end, string op
|
||||
where
|
||||
query predicate binary(
|
||||
GuardCondition guard, Expr left, string op, Expr right, int k, int start, int end
|
||||
) {
|
||||
exists(BasicBlock block |
|
||||
guard.ensuresLt(left, right, k, block, true) and op = "<"
|
||||
or
|
||||
@@ -20,4 +21,18 @@ where
|
||||
|
|
||||
block.hasLocationInfo(_, start, _, end, _)
|
||||
)
|
||||
select guard, left, op, right, k, start, end
|
||||
}
|
||||
|
||||
query predicate unary(GuardCondition guard, Expr left, string op, int k, int start, int end) {
|
||||
exists(BasicBlock block |
|
||||
guard.ensuresLt(left, k, block, true) and op = "<"
|
||||
or
|
||||
guard.ensuresLt(left, k, block, false) and op = ">="
|
||||
or
|
||||
guard.ensuresEq(left, k, block, true) and op = "=="
|
||||
or
|
||||
guard.ensuresEq(left, k, block, false) and op = "!="
|
||||
|
|
||||
block.hasLocationInfo(_, start, _, end, _)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -147,3 +147,27 @@ void test5(int x) {
|
||||
test3();
|
||||
}
|
||||
}
|
||||
|
||||
void test6(char* p) {
|
||||
if(p) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void test7(char* p) {
|
||||
if(!p) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void test8(short s) {
|
||||
if(s) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void test9(short s) {
|
||||
if(!s) {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -85,4 +85,30 @@ void test_switches_default(int i) {
|
||||
default:
|
||||
use1(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void use(...);
|
||||
|
||||
void pointer_comparison(char* c) {
|
||||
if(c) {
|
||||
use(c);
|
||||
}
|
||||
}
|
||||
|
||||
void implicit_float_comparison(float f) {
|
||||
if(f) {
|
||||
use(f);
|
||||
}
|
||||
}
|
||||
|
||||
void explicit_float_comparison(float f) {
|
||||
if(f != 0.0f) {
|
||||
use(f);
|
||||
}
|
||||
}
|
||||
|
||||
void int_float_comparison(int i) {
|
||||
if(i != 0.0f) {
|
||||
use(i);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -228,7 +228,6 @@ irFlow
|
||||
| test.cpp:333:17:333:22 | call to source | test.cpp:337:10:337:18 | globalVar |
|
||||
| test.cpp:333:17:333:22 | call to source | test.cpp:339:10:339:18 | globalVar |
|
||||
| test.cpp:333:17:333:22 | call to source | test.cpp:343:10:343:18 | globalVar |
|
||||
| test.cpp:333:17:333:22 | call to source | test.cpp:349:10:349:18 | globalVar |
|
||||
| test.cpp:347:17:347:22 | call to source | test.cpp:337:10:337:18 | globalVar |
|
||||
| test.cpp:347:17:347:22 | call to source | test.cpp:339:10:339:18 | globalVar |
|
||||
| test.cpp:347:17:347:22 | call to source | test.cpp:343:10:343:18 | globalVar |
|
||||
@@ -260,7 +259,6 @@ irFlow
|
||||
| test.cpp:562:17:562:31 | *call to indirect_source | test.cpp:566:10:566:19 | * ... |
|
||||
| test.cpp:562:17:562:31 | *call to indirect_source | test.cpp:568:10:568:19 | * ... |
|
||||
| test.cpp:562:17:562:31 | *call to indirect_source | test.cpp:572:10:572:19 | * ... |
|
||||
| test.cpp:562:17:562:31 | *call to indirect_source | test.cpp:578:10:578:19 | * ... |
|
||||
| test.cpp:576:17:576:31 | *call to indirect_source | test.cpp:566:10:566:19 | * ... |
|
||||
| test.cpp:576:17:576:31 | *call to indirect_source | test.cpp:568:10:568:19 | * ... |
|
||||
| test.cpp:576:17:576:31 | *call to indirect_source | test.cpp:572:10:572:19 | * ... |
|
||||
|
||||
@@ -346,7 +346,7 @@ namespace FlowThroughGlobals {
|
||||
void taintAndCall() {
|
||||
globalVar = source();
|
||||
calledAfterTaint();
|
||||
sink(globalVar); // $ ast ir=333:17 ir=347:17
|
||||
sink(globalVar); // $ ast ir
|
||||
}
|
||||
}
|
||||
|
||||
@@ -575,7 +575,7 @@ namespace IndirectFlowThroughGlobals {
|
||||
void taintAndCall() {
|
||||
globalInt = indirect_source();
|
||||
calledAfterTaint();
|
||||
sink(*globalInt); // $ ir=562:17 ir=576:17 MISSING: ast=562:17 ast=576:17
|
||||
sink(*globalInt); // $ ir MISSING: ast=562:17 ast=576:17
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -66,8 +66,8 @@ public:
|
||||
insert_iterator_by_trait operator++(int);
|
||||
insert_iterator_by_trait &operator--();
|
||||
insert_iterator_by_trait operator--(int);
|
||||
insert_iterator_by_trait operator*();
|
||||
insert_iterator_by_trait operator=(int x);
|
||||
insert_iterator_by_trait& operator*();
|
||||
insert_iterator_by_trait& operator=(int x);
|
||||
};
|
||||
|
||||
template<>
|
||||
|
||||
@@ -389,7 +389,7 @@ void test_vector_output_iterator(int b) {
|
||||
*i9 = source();
|
||||
taint_vector_output_iterator(i9);
|
||||
|
||||
sink(v9); // $ ast=330:10 MISSING: ir SPURIOUS: ast=389:8
|
||||
sink(v9); // $ ast=330:10 ir SPURIOUS: ast=389:8
|
||||
|
||||
std::vector<int>::iterator i10 = v10.begin();
|
||||
vector_iterator_assign_wrapper(i10, 10);
|
||||
@@ -440,14 +440,14 @@ void test_vector_inserter(char *source_string) {
|
||||
std::vector<std::string> out;
|
||||
auto it = std::back_inserter(out);
|
||||
*++it = std::string(source_string);
|
||||
sink(out); // $ ast MISSING: ir
|
||||
sink(out); // $ ast,ir
|
||||
}
|
||||
|
||||
{
|
||||
std::vector<int> out;
|
||||
auto it = std::back_inserter(out);
|
||||
*++it = source();
|
||||
sink(out); // $ ast MISSING: ir
|
||||
sink(out); // $ ast,ir
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19411,6 +19411,12 @@ ir.cpp:
|
||||
# 2207| Value = [CharLiteral] 97
|
||||
# 2207| ValueCategory = prvalue
|
||||
# 2208| getStmt(2): [BreakStmt] break;
|
||||
# 2212| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
|
||||
# 2212| Type = [VoidType] void
|
||||
# 2212| ValueCategory = prvalue
|
||||
# 2212| getQualifier(): [VariableAccess] x
|
||||
# 2212| Type = [Class] ClassWithDestructor
|
||||
# 2212| ValueCategory = lvalue
|
||||
# 2209| getStmt(3): [SwitchCase] default:
|
||||
# 2210| getStmt(4): [ExprStmt] ExprStmt
|
||||
# 2210| getExpr(): [FunctionCall] call to set_x
|
||||
@@ -19424,6 +19430,12 @@ ir.cpp:
|
||||
# 2210| Value = [CharLiteral] 98
|
||||
# 2210| ValueCategory = prvalue
|
||||
# 2211| getStmt(5): [BreakStmt] break;
|
||||
# 2212| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
|
||||
# 2212| Type = [VoidType] void
|
||||
# 2212| ValueCategory = prvalue
|
||||
# 2212| getQualifier(): [VariableAccess] x
|
||||
# 2212| Type = [Class] ClassWithDestructor
|
||||
# 2212| ValueCategory = lvalue
|
||||
# 2212| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
|
||||
# 2212| Type = [VoidType] void
|
||||
# 2212| ValueCategory = prvalue
|
||||
@@ -19565,12 +19577,6 @@ ir.cpp:
|
||||
# 2216| Type = [PlainCharType] char
|
||||
# 2216| Value = [CharLiteral] 97
|
||||
# 2216| ValueCategory = prvalue
|
||||
# 2215| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
|
||||
# 2215| Type = [VoidType] void
|
||||
# 2215| ValueCategory = prvalue
|
||||
# 2215| getQualifier(): [VariableAccess] y
|
||||
# 2215| Type = [Class] ClassWithDestructor
|
||||
# 2215| ValueCategory = lvalue
|
||||
# 2215| getImplicitDestructorCall(0): [DestructorCall] call to ~vector
|
||||
# 2215| Type = [VoidType] void
|
||||
# 2215| ValueCategory = prvalue
|
||||
@@ -19580,6 +19586,12 @@ ir.cpp:
|
||||
# 2215| getUpdate().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
|
||||
# 2215| Type = [ClassTemplateInstantiation,Struct] iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>
|
||||
# 2215| ValueCategory = lvalue
|
||||
# 2215| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
|
||||
# 2215| Type = [VoidType] void
|
||||
# 2215| ValueCategory = prvalue
|
||||
# 2215| getQualifier(): [VariableAccess] y
|
||||
# 2215| Type = [Class] ClassWithDestructor
|
||||
# 2215| ValueCategory = lvalue
|
||||
# 2218| getStmt(6): [RangeBasedForStmt] for(...:...) ...
|
||||
# 2218| getInitialization(): [DeclStmt] declaration
|
||||
# 2218| getDeclarationEntry(0): [VariableDeclarationEntry] definition of ys
|
||||
@@ -19746,12 +19758,6 @@ ir.cpp:
|
||||
# 2233| getQualifier(): [VariableAccess] x
|
||||
# 2233| Type = [Class] ClassWithDestructor
|
||||
# 2233| ValueCategory = lvalue
|
||||
# 2218| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
|
||||
# 2218| Type = [VoidType] void
|
||||
# 2218| ValueCategory = prvalue
|
||||
# 2218| getQualifier(): [VariableAccess] y
|
||||
# 2218| Type = [Class] ClassWithDestructor
|
||||
# 2218| ValueCategory = lvalue
|
||||
# 2218| getImplicitDestructorCall(0): [DestructorCall] call to ~vector
|
||||
# 2218| Type = [VoidType] void
|
||||
# 2218| ValueCategory = prvalue
|
||||
@@ -19761,6 +19767,12 @@ ir.cpp:
|
||||
# 2218| getUpdate().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
|
||||
# 2218| Type = [ClassTemplateInstantiation,Struct] iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>
|
||||
# 2218| ValueCategory = lvalue
|
||||
# 2218| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
|
||||
# 2218| Type = [VoidType] void
|
||||
# 2218| ValueCategory = prvalue
|
||||
# 2218| getQualifier(): [VariableAccess] y
|
||||
# 2218| Type = [Class] ClassWithDestructor
|
||||
# 2218| ValueCategory = lvalue
|
||||
# 2224| getStmt(7): [RangeBasedForStmt] for(...:...) ...
|
||||
# 2224| getInitialization(): [DeclStmt] declaration
|
||||
# 2224| getDeclarationEntry(0): [VariableDeclarationEntry] definition of ys
|
||||
@@ -20038,12 +20050,6 @@ ir.cpp:
|
||||
# 2232| getQualifier(): [VariableAccess] z1
|
||||
# 2232| Type = [Class] ClassWithDestructor
|
||||
# 2232| ValueCategory = lvalue
|
||||
# 2229| getImplicitDestructorCall(2): [DestructorCall] call to ~ClassWithDestructor
|
||||
# 2229| Type = [VoidType] void
|
||||
# 2229| ValueCategory = prvalue
|
||||
# 2229| getQualifier(): [VariableAccess] y
|
||||
# 2229| Type = [Class] ClassWithDestructor
|
||||
# 2229| ValueCategory = lvalue
|
||||
# 2229| getImplicitDestructorCall(0): [DestructorCall] call to ~vector
|
||||
# 2229| Type = [VoidType] void
|
||||
# 2229| ValueCategory = prvalue
|
||||
@@ -20053,6 +20059,12 @@ ir.cpp:
|
||||
# 2229| getUpdate().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
|
||||
# 2229| Type = [ClassTemplateInstantiation,Struct] iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>
|
||||
# 2229| ValueCategory = lvalue
|
||||
# 2229| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
|
||||
# 2229| Type = [VoidType] void
|
||||
# 2229| ValueCategory = prvalue
|
||||
# 2229| getQualifier(): [VariableAccess] y
|
||||
# 2229| Type = [Class] ClassWithDestructor
|
||||
# 2229| ValueCategory = lvalue
|
||||
# 2233| getStmt(9): [ReturnStmt] return ...
|
||||
# 2233| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
|
||||
# 2233| Type = [VoidType] void
|
||||
@@ -20662,15 +20674,15 @@ ir.cpp:
|
||||
# 2309| getQualifier(): [VariableAccess] s2
|
||||
# 2309| Type = [Struct] String
|
||||
# 2309| ValueCategory = lvalue
|
||||
# 2307| getImplicitDestructorCall(1): [DestructorCall] call to ~String
|
||||
# 2307| getUpdate().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
|
||||
# 2307| Type = [ClassTemplateInstantiation,Struct] iterator<random_access_iterator_tag, String, ptrdiff_t, String *, String &>
|
||||
# 2307| ValueCategory = lvalue
|
||||
# 2307| getImplicitDestructorCall(0): [DestructorCall] call to ~String
|
||||
# 2307| Type = [VoidType] void
|
||||
# 2307| ValueCategory = prvalue
|
||||
# 2307| getQualifier(): [VariableAccess] s
|
||||
# 2307| Type = [Struct] String
|
||||
# 2307| ValueCategory = lvalue
|
||||
# 2307| getUpdate().getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
|
||||
# 2307| Type = [ClassTemplateInstantiation,Struct] iterator<random_access_iterator_tag, String, ptrdiff_t, String *, String &>
|
||||
# 2307| ValueCategory = lvalue
|
||||
# 2311| getStmt(3): [ForStmt] for(...;...;...) ...
|
||||
# 2311| getInitialization(): [DeclStmt] declaration
|
||||
# 2311| getDeclarationEntry(0): [VariableDeclarationEntry] definition of s
|
||||
@@ -22334,6 +22346,265 @@ ir.cpp:
|
||||
# 2480| Type = [Struct] B
|
||||
# 2480| ValueCategory = xvalue
|
||||
# 2481| getStmt(1): [ReturnStmt] return ...
|
||||
# 2484| [TopLevelFunction] void destructor_without_block(bool)
|
||||
# 2484| <params>:
|
||||
# 2484| getParameter(0): [Parameter] b
|
||||
# 2484| Type = [BoolType] bool
|
||||
# 2485| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 2486| getStmt(0): [IfStmt] if (...) ...
|
||||
# 2486| getCondition(): [VariableAccess] b
|
||||
# 2486| Type = [BoolType] bool
|
||||
# 2486| ValueCategory = prvalue(load)
|
||||
# 2487| getThen(): [DeclStmt] declaration
|
||||
# 2487| getDeclarationEntry(0): [VariableDeclarationEntry] definition of c
|
||||
# 2487| Type = [Class] ClassWithDestructor
|
||||
# 2487| getVariable().getInitializer(): [Initializer] initializer for c
|
||||
# 2487| getExpr(): [ConstructorCall] call to ClassWithDestructor
|
||||
# 2487| Type = [VoidType] void
|
||||
# 2487| ValueCategory = prvalue
|
||||
#-----| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
|
||||
#-----| Type = [VoidType] void
|
||||
#-----| ValueCategory = prvalue
|
||||
#-----| getQualifier(): [VariableAccess] c
|
||||
#-----| Type = [Class] ClassWithDestructor
|
||||
#-----| ValueCategory = lvalue
|
||||
# 2489| getStmt(1): [IfStmt] if (...) ...
|
||||
# 2489| getCondition(): [VariableAccess] b
|
||||
# 2489| Type = [BoolType] bool
|
||||
# 2489| ValueCategory = prvalue(load)
|
||||
# 2490| getThen(): [DeclStmt] declaration
|
||||
# 2490| getDeclarationEntry(0): [VariableDeclarationEntry] definition of d
|
||||
# 2490| Type = [Class] ClassWithDestructor
|
||||
# 2490| getVariable().getInitializer(): [Initializer] initializer for d
|
||||
# 2490| getExpr(): [ConstructorCall] call to ClassWithDestructor
|
||||
# 2490| Type = [VoidType] void
|
||||
# 2490| ValueCategory = prvalue
|
||||
#-----| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
|
||||
#-----| Type = [VoidType] void
|
||||
#-----| ValueCategory = prvalue
|
||||
#-----| getQualifier(): [VariableAccess] d
|
||||
#-----| Type = [Class] ClassWithDestructor
|
||||
#-----| ValueCategory = lvalue
|
||||
# 2492| getElse(): [DeclStmt] declaration
|
||||
# 2492| getDeclarationEntry(0): [VariableDeclarationEntry] definition of e
|
||||
# 2492| Type = [Class] ClassWithDestructor
|
||||
# 2492| getVariable().getInitializer(): [Initializer] initializer for e
|
||||
# 2492| getExpr(): [ConstructorCall] call to ClassWithDestructor
|
||||
# 2492| Type = [VoidType] void
|
||||
# 2492| ValueCategory = prvalue
|
||||
#-----| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
|
||||
#-----| Type = [VoidType] void
|
||||
#-----| ValueCategory = prvalue
|
||||
#-----| getQualifier(): [VariableAccess] e
|
||||
#-----| Type = [Class] ClassWithDestructor
|
||||
#-----| ValueCategory = lvalue
|
||||
# 2494| getStmt(2): [WhileStmt] while (...) ...
|
||||
# 2494| getCondition(): [VariableAccess] b
|
||||
# 2494| Type = [BoolType] bool
|
||||
# 2494| ValueCategory = prvalue(load)
|
||||
# 2495| getStmt(): [DeclStmt] declaration
|
||||
# 2495| getDeclarationEntry(0): [VariableDeclarationEntry] definition of f
|
||||
# 2495| Type = [Class] ClassWithDestructor
|
||||
# 2495| getVariable().getInitializer(): [Initializer] initializer for f
|
||||
# 2495| getExpr(): [ConstructorCall] call to ClassWithDestructor
|
||||
# 2495| Type = [VoidType] void
|
||||
# 2495| ValueCategory = prvalue
|
||||
#-----| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
|
||||
#-----| Type = [VoidType] void
|
||||
#-----| ValueCategory = prvalue
|
||||
#-----| getQualifier(): [VariableAccess] f
|
||||
#-----| Type = [Class] ClassWithDestructor
|
||||
#-----| ValueCategory = lvalue
|
||||
# 2497| getStmt(3): [ForStmt] for(...;...;...) ...
|
||||
# 2497| getInitialization(): [DeclStmt] declaration
|
||||
# 2497| getDeclarationEntry(0): [VariableDeclarationEntry] definition of i
|
||||
# 2497| Type = [IntType] int
|
||||
# 2497| getVariable().getInitializer(): [Initializer] initializer for i
|
||||
# 2497| getExpr(): [Literal] 0
|
||||
# 2497| Type = [IntType] int
|
||||
# 2497| Value = [Literal] 0
|
||||
# 2497| ValueCategory = prvalue
|
||||
# 2497| getCondition(): [LTExpr] ... < ...
|
||||
# 2497| Type = [BoolType] bool
|
||||
# 2497| ValueCategory = prvalue
|
||||
# 2497| getLesserOperand(): [VariableAccess] i
|
||||
# 2497| Type = [IntType] int
|
||||
# 2497| ValueCategory = prvalue(load)
|
||||
# 2497| getGreaterOperand(): [Literal] 42
|
||||
# 2497| Type = [IntType] int
|
||||
# 2497| Value = [Literal] 42
|
||||
# 2497| ValueCategory = prvalue
|
||||
# 2497| getUpdate(): [PrefixIncrExpr] ++ ...
|
||||
# 2497| Type = [IntType] int
|
||||
# 2497| ValueCategory = lvalue
|
||||
# 2497| getOperand(): [VariableAccess] i
|
||||
# 2497| Type = [IntType] int
|
||||
# 2497| ValueCategory = lvalue
|
||||
# 2498| getStmt(): [DeclStmt] declaration
|
||||
# 2498| getDeclarationEntry(0): [VariableDeclarationEntry] definition of g
|
||||
# 2498| Type = [Class] ClassWithDestructor
|
||||
# 2498| getVariable().getInitializer(): [Initializer] initializer for g
|
||||
# 2498| getExpr(): [ConstructorCall] call to ClassWithDestructor
|
||||
# 2498| Type = [VoidType] void
|
||||
# 2498| ValueCategory = prvalue
|
||||
#-----| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
|
||||
#-----| Type = [VoidType] void
|
||||
#-----| ValueCategory = prvalue
|
||||
#-----| getQualifier(): [VariableAccess] g
|
||||
#-----| Type = [Class] ClassWithDestructor
|
||||
#-----| ValueCategory = lvalue
|
||||
# 2499| getStmt(4): [ReturnStmt] return ...
|
||||
# 2501| [TopLevelFunction] void destruction_in_switch_1(int)
|
||||
# 2501| <params>:
|
||||
# 2501| getParameter(0): [Parameter] c
|
||||
# 2501| Type = [IntType] int
|
||||
# 2501| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 2502| getStmt(0): [SwitchStmt] switch (...) ...
|
||||
# 2502| getExpr(): [VariableAccess] c
|
||||
# 2502| Type = [IntType] int
|
||||
# 2502| ValueCategory = prvalue(load)
|
||||
# 2502| getStmt(): [BlockStmt] { ... }
|
||||
# 2503| getStmt(0): [SwitchCase] case ...:
|
||||
# 2503| getExpr(): [Literal] 0
|
||||
# 2503| Type = [IntType] int
|
||||
# 2503| Value = [Literal] 0
|
||||
# 2503| ValueCategory = prvalue
|
||||
# 2503| getStmt(1): [BlockStmt] { ... }
|
||||
# 2504| getStmt(0): [DeclStmt] declaration
|
||||
# 2504| getDeclarationEntry(0): [VariableDeclarationEntry] definition of x
|
||||
# 2504| Type = [Class] ClassWithDestructor
|
||||
# 2504| getVariable().getInitializer(): [Initializer] initializer for x
|
||||
# 2504| getExpr(): [ConstructorCall] call to ClassWithDestructor
|
||||
# 2504| Type = [VoidType] void
|
||||
# 2504| ValueCategory = prvalue
|
||||
# 2505| getStmt(1): [BreakStmt] break;
|
||||
# 2506| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
|
||||
# 2506| Type = [VoidType] void
|
||||
# 2506| ValueCategory = prvalue
|
||||
# 2506| getQualifier(): [VariableAccess] x
|
||||
# 2506| Type = [Class] ClassWithDestructor
|
||||
# 2506| ValueCategory = lvalue
|
||||
# 2506| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
|
||||
# 2506| Type = [VoidType] void
|
||||
# 2506| ValueCategory = prvalue
|
||||
# 2506| getQualifier(): [VariableAccess] x
|
||||
# 2506| Type = [Class] ClassWithDestructor
|
||||
# 2506| ValueCategory = lvalue
|
||||
# 2507| getStmt(1): [LabelStmt] label ...:
|
||||
# 2508| getStmt(2): [ReturnStmt] return ...
|
||||
# 2510| [TopLevelFunction] void destruction_in_switch_2(int)
|
||||
# 2510| <params>:
|
||||
# 2510| getParameter(0): [Parameter] c
|
||||
# 2510| Type = [IntType] int
|
||||
# 2510| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 2511| getStmt(0): [SwitchStmt] switch (...) ...
|
||||
# 2511| getInitialization(): [DeclStmt] declaration
|
||||
# 2511| getDeclarationEntry(0): [VariableDeclarationEntry] definition of y
|
||||
# 2511| Type = [Class] ClassWithDestructor
|
||||
# 2511| getVariable().getInitializer(): [Initializer] initializer for y
|
||||
# 2511| getExpr(): [ConstructorCall] call to ClassWithDestructor
|
||||
# 2511| Type = [VoidType] void
|
||||
# 2511| ValueCategory = prvalue
|
||||
# 2511| getExpr(): [VariableAccess] c
|
||||
# 2511| Type = [IntType] int
|
||||
# 2511| ValueCategory = prvalue(load)
|
||||
# 2511| getStmt(): [BlockStmt] { ... }
|
||||
# 2512| getStmt(0): [SwitchCase] case ...:
|
||||
# 2512| getExpr(): [Literal] 0
|
||||
# 2512| Type = [IntType] int
|
||||
# 2512| Value = [Literal] 0
|
||||
# 2512| ValueCategory = prvalue
|
||||
# 2512| getStmt(1): [BlockStmt] { ... }
|
||||
# 2513| getStmt(0): [BreakStmt] break;
|
||||
# 2518| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
|
||||
# 2518| Type = [VoidType] void
|
||||
# 2518| ValueCategory = prvalue
|
||||
# 2518| getQualifier(): [VariableAccess] y
|
||||
# 2518| Type = [Class] ClassWithDestructor
|
||||
# 2518| ValueCategory = lvalue
|
||||
# 2515| getStmt(2): [SwitchCase] default:
|
||||
# 2515| getStmt(3): [BlockStmt] { ... }
|
||||
# 2516| getStmt(0): [BreakStmt] break;
|
||||
# 2518| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
|
||||
# 2518| Type = [VoidType] void
|
||||
# 2518| ValueCategory = prvalue
|
||||
# 2518| getQualifier(): [VariableAccess] y
|
||||
# 2518| Type = [Class] ClassWithDestructor
|
||||
# 2518| ValueCategory = lvalue
|
||||
# 2518| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
|
||||
# 2518| Type = [VoidType] void
|
||||
# 2518| ValueCategory = prvalue
|
||||
# 2518| getQualifier(): [VariableAccess] y
|
||||
# 2518| Type = [Class] ClassWithDestructor
|
||||
# 2518| ValueCategory = lvalue
|
||||
# 2518| getStmt(1): [LabelStmt] label ...:
|
||||
# 2519| getStmt(2): [ReturnStmt] return ...
|
||||
# 2521| [TopLevelFunction] void destruction_in_switch_3(int)
|
||||
# 2521| <params>:
|
||||
# 2521| getParameter(0): [Parameter] c
|
||||
# 2521| Type = [IntType] int
|
||||
# 2521| getEntryPoint(): [BlockStmt] { ... }
|
||||
# 2522| getStmt(0): [SwitchStmt] switch (...) ...
|
||||
# 2522| getInitialization(): [DeclStmt] declaration
|
||||
# 2522| getDeclarationEntry(0): [VariableDeclarationEntry] definition of y
|
||||
# 2522| Type = [Class] ClassWithDestructor
|
||||
# 2522| getVariable().getInitializer(): [Initializer] initializer for y
|
||||
# 2522| getExpr(): [ConstructorCall] call to ClassWithDestructor
|
||||
# 2522| Type = [VoidType] void
|
||||
# 2522| ValueCategory = prvalue
|
||||
# 2522| getExpr(): [VariableAccess] c
|
||||
# 2522| Type = [IntType] int
|
||||
# 2522| ValueCategory = prvalue(load)
|
||||
# 2522| getStmt(): [BlockStmt] { ... }
|
||||
# 2523| getStmt(0): [SwitchCase] case ...:
|
||||
# 2523| getExpr(): [Literal] 0
|
||||
# 2523| Type = [IntType] int
|
||||
# 2523| Value = [Literal] 0
|
||||
# 2523| ValueCategory = prvalue
|
||||
# 2523| getStmt(1): [BlockStmt] { ... }
|
||||
# 2524| getStmt(0): [DeclStmt] declaration
|
||||
# 2524| getDeclarationEntry(0): [VariableDeclarationEntry] definition of x
|
||||
# 2524| Type = [Class] ClassWithDestructor
|
||||
# 2524| getVariable().getInitializer(): [Initializer] initializer for x
|
||||
# 2524| getExpr(): [ConstructorCall] call to ClassWithDestructor
|
||||
# 2524| Type = [VoidType] void
|
||||
# 2524| ValueCategory = prvalue
|
||||
# 2525| getStmt(1): [BreakStmt] break;
|
||||
# 2526| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
|
||||
# 2526| Type = [VoidType] void
|
||||
# 2526| ValueCategory = prvalue
|
||||
# 2526| getQualifier(): [VariableAccess] x
|
||||
# 2526| Type = [Class] ClassWithDestructor
|
||||
# 2526| ValueCategory = lvalue
|
||||
# 2530| getImplicitDestructorCall(1): [DestructorCall] call to ~ClassWithDestructor
|
||||
# 2530| Type = [VoidType] void
|
||||
# 2530| ValueCategory = prvalue
|
||||
# 2530| getQualifier(): [VariableAccess] y
|
||||
# 2530| Type = [Class] ClassWithDestructor
|
||||
# 2530| ValueCategory = lvalue
|
||||
# 2526| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
|
||||
# 2526| Type = [VoidType] void
|
||||
# 2526| ValueCategory = prvalue
|
||||
# 2526| getQualifier(): [VariableAccess] x
|
||||
# 2526| Type = [Class] ClassWithDestructor
|
||||
# 2526| ValueCategory = lvalue
|
||||
# 2527| getStmt(2): [SwitchCase] default:
|
||||
# 2527| getStmt(3): [BlockStmt] { ... }
|
||||
# 2528| getStmt(0): [BreakStmt] break;
|
||||
# 2530| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
|
||||
# 2530| Type = [VoidType] void
|
||||
# 2530| ValueCategory = prvalue
|
||||
# 2530| getQualifier(): [VariableAccess] y
|
||||
# 2530| Type = [Class] ClassWithDestructor
|
||||
# 2530| ValueCategory = lvalue
|
||||
# 2530| getImplicitDestructorCall(0): [DestructorCall] call to ~ClassWithDestructor
|
||||
# 2530| Type = [VoidType] void
|
||||
# 2530| ValueCategory = prvalue
|
||||
# 2530| getQualifier(): [VariableAccess] y
|
||||
# 2530| Type = [Class] ClassWithDestructor
|
||||
# 2530| ValueCategory = lvalue
|
||||
# 2530| getStmt(1): [LabelStmt] label ...:
|
||||
# 2531| getStmt(2): [ReturnStmt] return ...
|
||||
perf-regression.cpp:
|
||||
# 4| [CopyAssignmentOperator] Big& Big::operator=(Big const&)
|
||||
# 4| <params>:
|
||||
|
||||
@@ -15372,7 +15372,7 @@ ir.cpp:
|
||||
#-----| True -> Block 2
|
||||
|
||||
# 2198| Block 1
|
||||
# 2198| m2198_9(unknown) = Phi : from 13:~m2233_5, from 19:~m2233_13, from 23:~m2233_22
|
||||
# 2198| m2198_9(unknown) = Phi : from 14:~m2233_5, from 19:~m2233_13, from 23:~m2233_22
|
||||
# 2198| v2198_10(void) = ReturnVoid :
|
||||
# 2198| v2198_11(void) = AliasedUse : ~m2198_9
|
||||
# 2198| v2198_12(void) = ExitFunction :
|
||||
@@ -15438,42 +15438,58 @@ ir.cpp:
|
||||
#-----| Default -> Block 6
|
||||
|
||||
# 2206| Block 5
|
||||
# 2206| v2206_1(void) = NoOp :
|
||||
# 2207| r2207_1(glval<ClassWithDestructor>) = VariableAddress[x] :
|
||||
# 2207| r2207_2(glval<unknown>) = FunctionAddress[set_x] :
|
||||
# 2207| r2207_3(char) = Constant[97] :
|
||||
# 2207| v2207_4(void) = Call[set_x] : func:r2207_2, this:r2207_1, 0:r2207_3
|
||||
# 2207| m2207_5(unknown) = ^CallSideEffect : ~m2205_6
|
||||
# 2207| m2207_6(unknown) = Chi : total:m2205_6, partial:m2207_5
|
||||
# 2207| v2207_7(void) = ^IndirectReadSideEffect[-1] : &:r2207_1, m2205_8
|
||||
# 2207| m2207_8(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2207_1
|
||||
# 2207| m2207_9(ClassWithDestructor) = Chi : total:m2205_8, partial:m2207_8
|
||||
# 2208| v2208_1(void) = NoOp :
|
||||
# 2206| v2206_1(void) = NoOp :
|
||||
# 2207| r2207_1(glval<ClassWithDestructor>) = VariableAddress[x] :
|
||||
# 2207| r2207_2(glval<unknown>) = FunctionAddress[set_x] :
|
||||
# 2207| r2207_3(char) = Constant[97] :
|
||||
# 2207| v2207_4(void) = Call[set_x] : func:r2207_2, this:r2207_1, 0:r2207_3
|
||||
# 2207| m2207_5(unknown) = ^CallSideEffect : ~m2205_6
|
||||
# 2207| m2207_6(unknown) = Chi : total:m2205_6, partial:m2207_5
|
||||
# 2207| v2207_7(void) = ^IndirectReadSideEffect[-1] : &:r2207_1, m2205_8
|
||||
# 2207| m2207_8(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2207_1
|
||||
# 2207| m2207_9(ClassWithDestructor) = Chi : total:m2205_8, partial:m2207_8
|
||||
# 2212| r2212_1(glval<ClassWithDestructor>) = VariableAddress[x] :
|
||||
# 2212| r2212_2(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
|
||||
# 2212| v2212_3(void) = Call[~ClassWithDestructor] : func:r2212_2, this:r2212_1
|
||||
# 2212| m2212_4(unknown) = ^CallSideEffect : ~m2207_6
|
||||
# 2212| m2212_5(unknown) = Chi : total:m2207_6, partial:m2212_4
|
||||
# 2212| v2212_6(void) = ^IndirectReadSideEffect[-1] : &:r2212_1, m2207_9
|
||||
# 2212| m2212_7(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2212_1
|
||||
# 2212| m2212_8(ClassWithDestructor) = Chi : total:m2207_9, partial:m2212_7
|
||||
# 2208| v2208_1(void) = NoOp :
|
||||
#-----| Goto -> Block 7
|
||||
|
||||
# 2209| Block 6
|
||||
# 2209| v2209_1(void) = NoOp :
|
||||
# 2210| r2210_1(glval<ClassWithDestructor>) = VariableAddress[x] :
|
||||
# 2210| r2210_2(glval<unknown>) = FunctionAddress[set_x] :
|
||||
# 2210| r2210_3(char) = Constant[98] :
|
||||
# 2210| v2210_4(void) = Call[set_x] : func:r2210_2, this:r2210_1, 0:r2210_3
|
||||
# 2210| m2210_5(unknown) = ^CallSideEffect : ~m2205_6
|
||||
# 2210| m2210_6(unknown) = Chi : total:m2205_6, partial:m2210_5
|
||||
# 2210| v2210_7(void) = ^IndirectReadSideEffect[-1] : &:r2210_1, m2205_8
|
||||
# 2210| m2210_8(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2210_1
|
||||
# 2210| m2210_9(ClassWithDestructor) = Chi : total:m2205_8, partial:m2210_8
|
||||
# 2211| v2211_1(void) = NoOp :
|
||||
# 2209| v2209_1(void) = NoOp :
|
||||
# 2210| r2210_1(glval<ClassWithDestructor>) = VariableAddress[x] :
|
||||
# 2210| r2210_2(glval<unknown>) = FunctionAddress[set_x] :
|
||||
# 2210| r2210_3(char) = Constant[98] :
|
||||
# 2210| v2210_4(void) = Call[set_x] : func:r2210_2, this:r2210_1, 0:r2210_3
|
||||
# 2210| m2210_5(unknown) = ^CallSideEffect : ~m2205_6
|
||||
# 2210| m2210_6(unknown) = Chi : total:m2205_6, partial:m2210_5
|
||||
# 2210| v2210_7(void) = ^IndirectReadSideEffect[-1] : &:r2210_1, m2205_8
|
||||
# 2210| m2210_8(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2210_1
|
||||
# 2210| m2210_9(ClassWithDestructor) = Chi : total:m2205_8, partial:m2210_8
|
||||
# 2212| r2212_9(glval<ClassWithDestructor>) = VariableAddress[x] :
|
||||
# 2212| r2212_10(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
|
||||
# 2212| v2212_11(void) = Call[~ClassWithDestructor] : func:r2212_10, this:r2212_9
|
||||
# 2212| m2212_12(unknown) = ^CallSideEffect : ~m2210_6
|
||||
# 2212| m2212_13(unknown) = Chi : total:m2210_6, partial:m2212_12
|
||||
# 2212| v2212_14(void) = ^IndirectReadSideEffect[-1] : &:r2212_9, m2210_9
|
||||
# 2212| m2212_15(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2212_9
|
||||
# 2212| m2212_16(ClassWithDestructor) = Chi : total:m2210_9, partial:m2212_15
|
||||
# 2211| v2211_1(void) = NoOp :
|
||||
#-----| Goto -> Block 7
|
||||
|
||||
# 2212| Block 7
|
||||
# 2212| m2212_1(unknown) = Phi : from 5:~m2207_6, from 6:~m2210_6
|
||||
# 2212| v2212_2(void) = NoOp :
|
||||
# 2212| m2212_17(unknown) = Phi : from 5:~m2212_5, from 6:~m2212_13
|
||||
# 2212| v2212_18(void) = NoOp :
|
||||
# 2214| r2214_1(glval<ClassWithDestructor>) = VariableAddress[x] :
|
||||
# 2214| m2214_2(ClassWithDestructor) = Uninitialized[x] : &:r2214_1
|
||||
# 2214| r2214_3(glval<unknown>) = FunctionAddress[ClassWithDestructor] :
|
||||
# 2214| v2214_4(void) = Call[ClassWithDestructor] : func:r2214_3, this:r2214_1
|
||||
# 2214| m2214_5(unknown) = ^CallSideEffect : ~m2212_1
|
||||
# 2214| m2214_6(unknown) = Chi : total:m2212_1, partial:m2214_5
|
||||
# 2214| m2214_5(unknown) = ^CallSideEffect : ~m2212_17
|
||||
# 2214| m2214_6(unknown) = Chi : total:m2212_17, partial:m2214_5
|
||||
# 2214| m2214_7(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2214_1
|
||||
# 2214| m2214_8(ClassWithDestructor) = Chi : total:m2214_2, partial:m2214_7
|
||||
# 2215| r2215_1(glval<vector<ClassWithDestructor>>) = VariableAddress[ys] :
|
||||
@@ -15524,8 +15540,8 @@ ir.cpp:
|
||||
#-----| Goto -> Block 8
|
||||
|
||||
# 2215| Block 8
|
||||
# 2215| m2215_40(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>) = Phi : from 7:m2215_32, from 9:m2215_72
|
||||
# 2215| m2215_41(unknown) = Phi : from 7:~m2215_39, from 9:~m2215_63
|
||||
# 2215| m2215_40(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>) = Phi : from 7:m2215_32, from 9:m2215_64
|
||||
# 2215| m2215_41(unknown) = Phi : from 7:~m2215_39, from 9:~m2215_69
|
||||
# 2215| r2215_42(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = VariableAddress[(__begin)] :
|
||||
#-----| r0_7(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = Convert : r2215_42
|
||||
# 2215| r2215_43(glval<unknown>) = FunctionAddress[operator!=] :
|
||||
@@ -15567,27 +15583,35 @@ ir.cpp:
|
||||
# 2216| v2216_7(void) = ^IndirectReadSideEffect[-1] : &:r2216_1, m2215_58
|
||||
# 2216| m2216_8(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2216_1
|
||||
# 2216| m2216_9(ClassWithDestructor) = Chi : total:m2215_58, partial:m2216_8
|
||||
# 2215| r2215_59(glval<ClassWithDestructor>) = VariableAddress[y] :
|
||||
# 2215| r2215_60(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
|
||||
# 2215| v2215_61(void) = Call[~ClassWithDestructor] : func:r2215_60, this:r2215_59
|
||||
# 2215| m2215_62(unknown) = ^CallSideEffect : ~m2216_6
|
||||
# 2215| m2215_63(unknown) = Chi : total:m2216_6, partial:m2215_62
|
||||
# 2215| v2215_64(void) = ^IndirectReadSideEffect[-1] : &:r2215_59, m2216_9
|
||||
# 2215| m2215_65(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2215_59
|
||||
# 2215| m2215_66(ClassWithDestructor) = Chi : total:m2216_9, partial:m2215_65
|
||||
# 2215| r2215_67(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = VariableAddress[(__begin)] :
|
||||
# 2215| r2215_68(glval<unknown>) = FunctionAddress[operator++] :
|
||||
# 2215| r2215_69(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &> &) = Call[operator++] : func:r2215_68, this:r2215_67
|
||||
# 2215| v2215_70(void) = ^IndirectReadSideEffect[-1] : &:r2215_67, m2215_40
|
||||
# 2215| m2215_71(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>) = ^IndirectMayWriteSideEffect[-1] : &:r2215_67
|
||||
# 2215| m2215_72(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>) = Chi : total:m2215_40, partial:m2215_71
|
||||
# 2215| r2215_73(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = CopyValue : r2215_69
|
||||
# 2215| r2215_59(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = VariableAddress[(__begin)] :
|
||||
# 2215| r2215_60(glval<unknown>) = FunctionAddress[operator++] :
|
||||
# 2215| r2215_61(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &> &) = Call[operator++] : func:r2215_60, this:r2215_59
|
||||
# 2215| v2215_62(void) = ^IndirectReadSideEffect[-1] : &:r2215_59, m2215_40
|
||||
# 2215| m2215_63(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>) = ^IndirectMayWriteSideEffect[-1] : &:r2215_59
|
||||
# 2215| m2215_64(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>) = Chi : total:m2215_40, partial:m2215_63
|
||||
# 2215| r2215_65(glval<ClassWithDestructor>) = VariableAddress[y] :
|
||||
# 2215| r2215_66(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
|
||||
# 2215| v2215_67(void) = Call[~ClassWithDestructor] : func:r2215_66, this:r2215_65
|
||||
# 2215| m2215_68(unknown) = ^CallSideEffect : ~m2216_6
|
||||
# 2215| m2215_69(unknown) = Chi : total:m2216_6, partial:m2215_68
|
||||
# 2215| v2215_70(void) = ^IndirectReadSideEffect[-1] : &:r2215_65, m2216_9
|
||||
# 2215| m2215_71(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2215_65
|
||||
# 2215| m2215_72(ClassWithDestructor) = Chi : total:m2216_9, partial:m2215_71
|
||||
# 2215| r2215_73(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = CopyValue : r2215_61
|
||||
#-----| Goto (back edge) -> Block 8
|
||||
|
||||
# 2218| Block 10
|
||||
# 2215| Block 10
|
||||
# 2215| r2215_74(glval<vector<ClassWithDestructor>>) = VariableAddress[ys] :
|
||||
# 2215| r2215_75(glval<unknown>) = FunctionAddress[~vector] :
|
||||
# 2215| v2215_76(void) = Call[~vector] : func:r2215_75, this:r2215_74
|
||||
# 2215| m2215_77(unknown) = ^CallSideEffect : ~m2215_50
|
||||
# 2215| m2215_78(unknown) = Chi : total:m2215_50, partial:m2215_77
|
||||
# 2215| v2215_79(void) = ^IndirectReadSideEffect[-1] : &:r2215_74, ~m2215_78
|
||||
# 2215| m2215_80(vector<ClassWithDestructor>) = ^IndirectMayWriteSideEffect[-1] : &:r2215_74
|
||||
# 2215| m2215_81(unknown) = Chi : total:m2215_78, partial:m2215_80
|
||||
# 2218| r2218_1(glval<vector<ClassWithDestructor>>) = VariableAddress[ys] :
|
||||
# 2218| m2218_2(vector<ClassWithDestructor>) = Uninitialized[ys] : &:r2218_1
|
||||
# 2218| m2218_3(unknown) = Chi : total:m2215_50, partial:m2218_2
|
||||
# 2218| m2218_3(unknown) = Chi : total:m2215_81, partial:m2218_2
|
||||
# 2218| r2218_4(glval<unknown>) = FunctionAddress[vector] :
|
||||
# 2218| r2218_5(glval<ClassWithDestructor>) = VariableAddress[#temp2218:45] :
|
||||
# 2218| r2218_6(glval<ClassWithDestructor>) = VariableAddress[x] :
|
||||
@@ -15633,8 +15657,8 @@ ir.cpp:
|
||||
#-----| Goto -> Block 11
|
||||
|
||||
# 2218| Block 11
|
||||
# 2218| m2218_40(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>) = Phi : from 10:m2218_32, from 14:m2218_88
|
||||
# 2218| m2218_41(unknown) = Phi : from 10:~m2218_39, from 14:~m2218_79
|
||||
# 2218| m2218_40(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>) = Phi : from 10:m2218_32, from 12:m2218_58
|
||||
# 2218| m2218_41(unknown) = Phi : from 10:~m2218_39, from 12:~m2218_63
|
||||
# 2218| r2218_42(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = VariableAddress[(__begin)] :
|
||||
#-----| r0_24(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = Convert : r2218_42
|
||||
# 2218| r2218_43(glval<unknown>) = FunctionAddress[operator!=] :
|
||||
@@ -15656,26 +15680,44 @@ ir.cpp:
|
||||
#-----| v0_32(void) = ^IndirectReadSideEffect[-1] : &:r0_24, m2218_40
|
||||
# 2218| v2218_52(void) = ConditionalBranch : r2218_51
|
||||
#-----| False -> Block 15
|
||||
#-----| True -> Block 12
|
||||
#-----| True -> Block 13
|
||||
|
||||
# 2218| Block 12
|
||||
# 2218| r2218_53(glval<ClassWithDestructor>) = VariableAddress[y] :
|
||||
# 2218| r2218_54(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = VariableAddress[(__begin)] :
|
||||
#-----| r0_33(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = Convert : r2218_54
|
||||
# 2218| r2218_55(glval<unknown>) = FunctionAddress[operator*] :
|
||||
# 2218| r2218_56(ClassWithDestructor &) = Call[operator*] : func:r2218_55, this:r0_33
|
||||
# 2218| r2218_53(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = VariableAddress[(__begin)] :
|
||||
# 2218| r2218_54(glval<unknown>) = FunctionAddress[operator++] :
|
||||
# 2218| r2218_55(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &> &) = Call[operator++] : func:r2218_54, this:r2218_53
|
||||
# 2218| v2218_56(void) = ^IndirectReadSideEffect[-1] : &:r2218_53, m2218_40
|
||||
# 2218| m2218_57(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>) = ^IndirectMayWriteSideEffect[-1] : &:r2218_53
|
||||
# 2218| m2218_58(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>) = Chi : total:m2218_40, partial:m2218_57
|
||||
# 2218| r2218_59(glval<ClassWithDestructor>) = VariableAddress[y] :
|
||||
# 2218| r2218_60(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
|
||||
# 2218| v2218_61(void) = Call[~ClassWithDestructor] : func:r2218_60, this:r2218_59
|
||||
# 2218| m2218_62(unknown) = ^CallSideEffect : ~m2220_5
|
||||
# 2218| m2218_63(unknown) = Chi : total:m2220_5, partial:m2218_62
|
||||
# 2218| v2218_64(void) = ^IndirectReadSideEffect[-1] : &:r2218_59, m2220_8
|
||||
# 2218| m2218_65(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2218_59
|
||||
# 2218| m2218_66(ClassWithDestructor) = Chi : total:m2220_8, partial:m2218_65
|
||||
# 2218| r2218_67(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = CopyValue : r2218_55
|
||||
#-----| Goto (back edge) -> Block 11
|
||||
|
||||
# 2218| Block 13
|
||||
# 2218| r2218_68(glval<ClassWithDestructor>) = VariableAddress[y] :
|
||||
# 2218| r2218_69(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = VariableAddress[(__begin)] :
|
||||
#-----| r0_33(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = Convert : r2218_69
|
||||
# 2218| r2218_70(glval<unknown>) = FunctionAddress[operator*] :
|
||||
# 2218| r2218_71(ClassWithDestructor &) = Call[operator*] : func:r2218_70, this:r0_33
|
||||
#-----| v0_34(void) = ^IndirectReadSideEffect[-1] : &:r0_33, m2218_40
|
||||
# 2218| r2218_57(ClassWithDestructor) = Load[?] : &:r2218_56, ~m2218_50
|
||||
# 2218| m2218_58(ClassWithDestructor) = Store[y] : &:r2218_53, r2218_57
|
||||
# 2218| r2218_72(ClassWithDestructor) = Load[?] : &:r2218_71, ~m2218_50
|
||||
# 2218| m2218_73(ClassWithDestructor) = Store[y] : &:r2218_68, r2218_72
|
||||
# 2219| r2219_1(glval<ClassWithDestructor>) = VariableAddress[y] :
|
||||
# 2219| r2219_2(glval<unknown>) = FunctionAddress[set_x] :
|
||||
# 2219| r2219_3(char) = Constant[97] :
|
||||
# 2219| v2219_4(void) = Call[set_x] : func:r2219_2, this:r2219_1, 0:r2219_3
|
||||
# 2219| m2219_5(unknown) = ^CallSideEffect : ~m2218_50
|
||||
# 2219| m2219_6(unknown) = Chi : total:m2218_50, partial:m2219_5
|
||||
# 2219| v2219_7(void) = ^IndirectReadSideEffect[-1] : &:r2219_1, m2218_58
|
||||
# 2219| v2219_7(void) = ^IndirectReadSideEffect[-1] : &:r2219_1, m2218_73
|
||||
# 2219| m2219_8(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2219_1
|
||||
# 2219| m2219_9(ClassWithDestructor) = Chi : total:m2218_58, partial:m2219_8
|
||||
# 2219| m2219_9(ClassWithDestructor) = Chi : total:m2218_73, partial:m2219_8
|
||||
# 2220| r2220_1(glval<ClassWithDestructor>) = VariableAddress[y] :
|
||||
# 2220| r2220_2(glval<unknown>) = FunctionAddress[get_x] :
|
||||
# 2220| r2220_3(char) = Call[get_x] : func:r2220_2, this:r2220_1
|
||||
@@ -15688,59 +15730,49 @@ ir.cpp:
|
||||
# 2220| r2220_10(int) = Constant[98] :
|
||||
# 2220| r2220_11(bool) = CompareEQ : r2220_9, r2220_10
|
||||
# 2220| v2220_12(void) = ConditionalBranch : r2220_11
|
||||
#-----| False -> Block 14
|
||||
#-----| True -> Block 13
|
||||
#-----| False -> Block 12
|
||||
#-----| True -> Block 14
|
||||
|
||||
# 2221| Block 13
|
||||
# 2221| Block 14
|
||||
# 2221| v2221_1(void) = NoOp :
|
||||
# 2218| r2218_59(glval<ClassWithDestructor>) = VariableAddress[y] :
|
||||
# 2218| r2218_60(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
|
||||
# 2218| v2218_61(void) = Call[~ClassWithDestructor] : func:r2218_60, this:r2218_59
|
||||
# 2218| m2218_62(unknown) = ^CallSideEffect : ~m2220_5
|
||||
# 2218| m2218_63(unknown) = Chi : total:m2220_5, partial:m2218_62
|
||||
# 2218| v2218_64(void) = ^IndirectReadSideEffect[-1] : &:r2218_59, m2220_8
|
||||
# 2218| m2218_65(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2218_59
|
||||
# 2218| m2218_66(ClassWithDestructor) = Chi : total:m2220_8, partial:m2218_65
|
||||
# 2218| r2218_67(glval<vector<ClassWithDestructor>>) = VariableAddress[ys] :
|
||||
# 2218| r2218_68(glval<unknown>) = FunctionAddress[~vector] :
|
||||
# 2218| v2218_69(void) = Call[~vector] : func:r2218_68, this:r2218_67
|
||||
# 2218| m2218_70(unknown) = ^CallSideEffect : ~m2218_63
|
||||
# 2218| m2218_71(unknown) = Chi : total:m2218_63, partial:m2218_70
|
||||
# 2218| v2218_72(void) = ^IndirectReadSideEffect[-1] : &:r2218_67, ~m2218_71
|
||||
# 2218| m2218_73(vector<ClassWithDestructor>) = ^IndirectMayWriteSideEffect[-1] : &:r2218_67
|
||||
# 2218| m2218_74(unknown) = Chi : total:m2218_71, partial:m2218_73
|
||||
# 2218| r2218_74(glval<ClassWithDestructor>) = VariableAddress[y] :
|
||||
# 2218| r2218_75(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
|
||||
# 2218| v2218_76(void) = Call[~ClassWithDestructor] : func:r2218_75, this:r2218_74
|
||||
# 2218| m2218_77(unknown) = ^CallSideEffect : ~m2220_5
|
||||
# 2218| m2218_78(unknown) = Chi : total:m2220_5, partial:m2218_77
|
||||
# 2218| v2218_79(void) = ^IndirectReadSideEffect[-1] : &:r2218_74, m2220_8
|
||||
# 2218| m2218_80(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2218_74
|
||||
# 2218| m2218_81(ClassWithDestructor) = Chi : total:m2220_8, partial:m2218_80
|
||||
# 2218| r2218_82(glval<vector<ClassWithDestructor>>) = VariableAddress[ys] :
|
||||
# 2218| r2218_83(glval<unknown>) = FunctionAddress[~vector] :
|
||||
# 2218| v2218_84(void) = Call[~vector] : func:r2218_83, this:r2218_82
|
||||
# 2218| m2218_85(unknown) = ^CallSideEffect : ~m2218_78
|
||||
# 2218| m2218_86(unknown) = Chi : total:m2218_78, partial:m2218_85
|
||||
# 2218| v2218_87(void) = ^IndirectReadSideEffect[-1] : &:r2218_82, ~m2218_86
|
||||
# 2218| m2218_88(vector<ClassWithDestructor>) = ^IndirectMayWriteSideEffect[-1] : &:r2218_82
|
||||
# 2218| m2218_89(unknown) = Chi : total:m2218_86, partial:m2218_88
|
||||
# 2233| r2233_1(glval<ClassWithDestructor>) = VariableAddress[x] :
|
||||
# 2233| r2233_2(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
|
||||
# 2233| v2233_3(void) = Call[~ClassWithDestructor] : func:r2233_2, this:r2233_1
|
||||
# 2233| m2233_4(unknown) = ^CallSideEffect : ~m2218_74
|
||||
# 2233| m2233_5(unknown) = Chi : total:m2218_74, partial:m2233_4
|
||||
# 2233| m2233_4(unknown) = ^CallSideEffect : ~m2218_89
|
||||
# 2233| m2233_5(unknown) = Chi : total:m2218_89, partial:m2233_4
|
||||
# 2233| v2233_6(void) = ^IndirectReadSideEffect[-1] : &:r2233_1, m2214_8
|
||||
# 2233| m2233_7(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2233_1
|
||||
# 2233| m2233_8(ClassWithDestructor) = Chi : total:m2214_8, partial:m2233_7
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
# 2218| Block 14
|
||||
# 2218| r2218_75(glval<ClassWithDestructor>) = VariableAddress[y] :
|
||||
# 2218| r2218_76(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
|
||||
# 2218| v2218_77(void) = Call[~ClassWithDestructor] : func:r2218_76, this:r2218_75
|
||||
# 2218| m2218_78(unknown) = ^CallSideEffect : ~m2220_5
|
||||
# 2218| m2218_79(unknown) = Chi : total:m2220_5, partial:m2218_78
|
||||
# 2218| v2218_80(void) = ^IndirectReadSideEffect[-1] : &:r2218_75, m2220_8
|
||||
# 2218| m2218_81(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2218_75
|
||||
# 2218| m2218_82(ClassWithDestructor) = Chi : total:m2220_8, partial:m2218_81
|
||||
# 2218| r2218_83(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = VariableAddress[(__begin)] :
|
||||
# 2218| r2218_84(glval<unknown>) = FunctionAddress[operator++] :
|
||||
# 2218| r2218_85(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &> &) = Call[operator++] : func:r2218_84, this:r2218_83
|
||||
# 2218| v2218_86(void) = ^IndirectReadSideEffect[-1] : &:r2218_83, m2218_40
|
||||
# 2218| m2218_87(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>) = ^IndirectMayWriteSideEffect[-1] : &:r2218_83
|
||||
# 2218| m2218_88(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>) = Chi : total:m2218_40, partial:m2218_87
|
||||
# 2218| r2218_89(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = CopyValue : r2218_85
|
||||
#-----| Goto (back edge) -> Block 11
|
||||
|
||||
# 2224| Block 15
|
||||
# 2218| Block 15
|
||||
# 2218| r2218_90(glval<vector<ClassWithDestructor>>) = VariableAddress[ys] :
|
||||
# 2218| r2218_91(glval<unknown>) = FunctionAddress[~vector] :
|
||||
# 2218| v2218_92(void) = Call[~vector] : func:r2218_91, this:r2218_90
|
||||
# 2218| m2218_93(unknown) = ^CallSideEffect : ~m2218_50
|
||||
# 2218| m2218_94(unknown) = Chi : total:m2218_50, partial:m2218_93
|
||||
# 2218| v2218_95(void) = ^IndirectReadSideEffect[-1] : &:r2218_90, ~m2218_94
|
||||
# 2218| m2218_96(vector<ClassWithDestructor>) = ^IndirectMayWriteSideEffect[-1] : &:r2218_90
|
||||
# 2218| m2218_97(unknown) = Chi : total:m2218_94, partial:m2218_96
|
||||
# 2224| r2224_1(glval<vector<int>>) = VariableAddress[ys] :
|
||||
# 2224| m2224_2(vector<int>) = Uninitialized[ys] : &:r2224_1
|
||||
# 2224| m2224_3(unknown) = Chi : total:m2218_50, partial:m2224_2
|
||||
# 2224| m2224_3(unknown) = Chi : total:m2218_97, partial:m2224_2
|
||||
# 2224| r2224_4(glval<unknown>) = FunctionAddress[vector] :
|
||||
# 2224| r2224_5(int) = Constant[1] :
|
||||
# 2224| v2224_6(void) = Call[vector] : func:r2224_4, this:r2224_1, 0:r2224_5
|
||||
@@ -15846,10 +15878,18 @@ ir.cpp:
|
||||
# 2233| m2233_16(ClassWithDestructor) = Chi : total:m2214_8, partial:m2233_15
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
# 2229| Block 20
|
||||
# 2224| Block 20
|
||||
# 2224| r2224_62(glval<vector<int>>) = VariableAddress[ys] :
|
||||
# 2224| r2224_63(glval<unknown>) = FunctionAddress[~vector] :
|
||||
# 2224| v2224_64(void) = Call[~vector] : func:r2224_63, this:r2224_62
|
||||
# 2224| m2224_65(unknown) = ^CallSideEffect : ~m2224_38
|
||||
# 2224| m2224_66(unknown) = Chi : total:m2224_38, partial:m2224_65
|
||||
# 2224| v2224_67(void) = ^IndirectReadSideEffect[-1] : &:r2224_62, ~m2224_66
|
||||
# 2224| m2224_68(vector<int>) = ^IndirectMayWriteSideEffect[-1] : &:r2224_62
|
||||
# 2224| m2224_69(unknown) = Chi : total:m2224_66, partial:m2224_68
|
||||
# 2229| r2229_1(glval<vector<ClassWithDestructor>>) = VariableAddress[ys] :
|
||||
# 2229| m2229_2(vector<ClassWithDestructor>) = Uninitialized[ys] : &:r2229_1
|
||||
# 2229| m2229_3(unknown) = Chi : total:m2224_38, partial:m2229_2
|
||||
# 2229| m2229_3(unknown) = Chi : total:m2224_69, partial:m2229_2
|
||||
# 2229| r2229_4(glval<unknown>) = FunctionAddress[vector] :
|
||||
# 2229| r2229_5(glval<ClassWithDestructor>) = VariableAddress[#temp2229:45] :
|
||||
# 2229| r2229_6(glval<ClassWithDestructor>) = VariableAddress[x] :
|
||||
@@ -15895,8 +15935,8 @@ ir.cpp:
|
||||
#-----| Goto -> Block 21
|
||||
|
||||
# 2229| Block 21
|
||||
# 2229| m2229_40(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>) = Phi : from 20:m2229_32, from 22:m2229_72
|
||||
# 2229| m2229_41(unknown) = Phi : from 20:~m2229_39, from 22:~m2229_63
|
||||
# 2229| m2229_40(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>) = Phi : from 20:m2229_32, from 22:m2229_64
|
||||
# 2229| m2229_41(unknown) = Phi : from 20:~m2229_39, from 22:~m2229_69
|
||||
# 2229| r2229_42(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = VariableAddress[(__begin)] :
|
||||
#-----| r0_58(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = Convert : r2229_42
|
||||
# 2229| r2229_43(glval<unknown>) = FunctionAddress[operator!=] :
|
||||
@@ -15961,33 +16001,41 @@ ir.cpp:
|
||||
# 2232| v2232_14(void) = ^IndirectReadSideEffect[-1] : &:r2232_9, m2230_8
|
||||
# 2232| m2232_15(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2232_9
|
||||
# 2232| m2232_16(ClassWithDestructor) = Chi : total:m2230_8, partial:m2232_15
|
||||
# 2229| r2229_59(glval<ClassWithDestructor>) = VariableAddress[y] :
|
||||
# 2229| r2229_60(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
|
||||
# 2229| v2229_61(void) = Call[~ClassWithDestructor] : func:r2229_60, this:r2229_59
|
||||
# 2229| m2229_62(unknown) = ^CallSideEffect : ~m2232_13
|
||||
# 2229| m2229_63(unknown) = Chi : total:m2232_13, partial:m2229_62
|
||||
# 2229| v2229_64(void) = ^IndirectReadSideEffect[-1] : &:r2229_59, m2229_58
|
||||
# 2229| m2229_65(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2229_59
|
||||
# 2229| m2229_66(ClassWithDestructor) = Chi : total:m2229_58, partial:m2229_65
|
||||
# 2229| r2229_67(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = VariableAddress[(__begin)] :
|
||||
# 2229| r2229_68(glval<unknown>) = FunctionAddress[operator++] :
|
||||
# 2229| r2229_69(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &> &) = Call[operator++] : func:r2229_68, this:r2229_67
|
||||
# 2229| v2229_70(void) = ^IndirectReadSideEffect[-1] : &:r2229_67, m2229_40
|
||||
# 2229| m2229_71(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>) = ^IndirectMayWriteSideEffect[-1] : &:r2229_67
|
||||
# 2229| m2229_72(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>) = Chi : total:m2229_40, partial:m2229_71
|
||||
# 2229| r2229_73(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = CopyValue : r2229_69
|
||||
# 2229| r2229_59(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = VariableAddress[(__begin)] :
|
||||
# 2229| r2229_60(glval<unknown>) = FunctionAddress[operator++] :
|
||||
# 2229| r2229_61(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &> &) = Call[operator++] : func:r2229_60, this:r2229_59
|
||||
# 2229| v2229_62(void) = ^IndirectReadSideEffect[-1] : &:r2229_59, m2229_40
|
||||
# 2229| m2229_63(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>) = ^IndirectMayWriteSideEffect[-1] : &:r2229_59
|
||||
# 2229| m2229_64(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>) = Chi : total:m2229_40, partial:m2229_63
|
||||
# 2229| r2229_65(glval<ClassWithDestructor>) = VariableAddress[y] :
|
||||
# 2229| r2229_66(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
|
||||
# 2229| v2229_67(void) = Call[~ClassWithDestructor] : func:r2229_66, this:r2229_65
|
||||
# 2229| m2229_68(unknown) = ^CallSideEffect : ~m2232_13
|
||||
# 2229| m2229_69(unknown) = Chi : total:m2232_13, partial:m2229_68
|
||||
# 2229| v2229_70(void) = ^IndirectReadSideEffect[-1] : &:r2229_65, m2229_58
|
||||
# 2229| m2229_71(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2229_65
|
||||
# 2229| m2229_72(ClassWithDestructor) = Chi : total:m2229_58, partial:m2229_71
|
||||
# 2229| r2229_73(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = CopyValue : r2229_61
|
||||
#-----| Goto (back edge) -> Block 21
|
||||
|
||||
# 2233| Block 23
|
||||
# 2233| v2233_17(void) = NoOp :
|
||||
# 2233| r2233_18(glval<ClassWithDestructor>) = VariableAddress[x] :
|
||||
# 2233| r2233_19(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
|
||||
# 2233| v2233_20(void) = Call[~ClassWithDestructor] : func:r2233_19, this:r2233_18
|
||||
# 2233| m2233_21(unknown) = ^CallSideEffect : ~m2229_50
|
||||
# 2233| m2233_22(unknown) = Chi : total:m2229_50, partial:m2233_21
|
||||
# 2233| v2233_23(void) = ^IndirectReadSideEffect[-1] : &:r2233_18, m2214_8
|
||||
# 2233| m2233_24(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2233_18
|
||||
# 2233| m2233_25(ClassWithDestructor) = Chi : total:m2214_8, partial:m2233_24
|
||||
# 2229| Block 23
|
||||
# 2229| r2229_74(glval<vector<ClassWithDestructor>>) = VariableAddress[ys] :
|
||||
# 2229| r2229_75(glval<unknown>) = FunctionAddress[~vector] :
|
||||
# 2229| v2229_76(void) = Call[~vector] : func:r2229_75, this:r2229_74
|
||||
# 2229| m2229_77(unknown) = ^CallSideEffect : ~m2229_50
|
||||
# 2229| m2229_78(unknown) = Chi : total:m2229_50, partial:m2229_77
|
||||
# 2229| v2229_79(void) = ^IndirectReadSideEffect[-1] : &:r2229_74, ~m2229_78
|
||||
# 2229| m2229_80(vector<ClassWithDestructor>) = ^IndirectMayWriteSideEffect[-1] : &:r2229_74
|
||||
# 2229| m2229_81(unknown) = Chi : total:m2229_78, partial:m2229_80
|
||||
# 2233| v2233_17(void) = NoOp :
|
||||
# 2233| r2233_18(glval<ClassWithDestructor>) = VariableAddress[x] :
|
||||
# 2233| r2233_19(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
|
||||
# 2233| v2233_20(void) = Call[~ClassWithDestructor] : func:r2233_19, this:r2233_18
|
||||
# 2233| m2233_21(unknown) = ^CallSideEffect : ~m2229_81
|
||||
# 2233| m2233_22(unknown) = Chi : total:m2229_81, partial:m2233_21
|
||||
# 2233| v2233_23(void) = ^IndirectReadSideEffect[-1] : &:r2233_18, m2214_8
|
||||
# 2233| m2233_24(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2233_18
|
||||
# 2233| m2233_25(ClassWithDestructor) = Chi : total:m2214_8, partial:m2233_24
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
# 2198| Block 24
|
||||
@@ -16684,8 +16732,8 @@ ir.cpp:
|
||||
#-----| Goto -> Block 4
|
||||
|
||||
# 2307| Block 4
|
||||
# 2307| m2307_47(iterator<random_access_iterator_tag, String, ptrdiff_t, String *, String &>) = Phi : from 3:m2307_39, from 5:m2307_89
|
||||
# 2307| m2307_48(unknown) = Phi : from 3:~m2307_46, from 5:~m2307_83
|
||||
# 2307| m2307_47(iterator<random_access_iterator_tag, String, ptrdiff_t, String *, String &>) = Phi : from 3:m2307_39, from 5:m2307_81
|
||||
# 2307| m2307_48(unknown) = Phi : from 3:~m2307_46, from 5:~m2307_89
|
||||
# 2307| r2307_49(glval<iterator<random_access_iterator_tag, String, ptrdiff_t, String *, String &>>) = VariableAddress[(__begin)] :
|
||||
#-----| r0_7(glval<iterator<random_access_iterator_tag, String, ptrdiff_t, String *, String &>>) = Convert : r2307_49
|
||||
# 2307| r2307_50(glval<unknown>) = FunctionAddress[operator!=] :
|
||||
@@ -16745,21 +16793,21 @@ ir.cpp:
|
||||
# 2309| v2309_6(void) = ^IndirectReadSideEffect[-1] : &:r2309_1, ~m2309_5
|
||||
# 2309| m2309_7(String) = ^IndirectMayWriteSideEffect[-1] : &:r2309_1
|
||||
# 2309| m2309_8(unknown) = Chi : total:m2309_5, partial:m2309_7
|
||||
# 2307| r2307_76(glval<String>) = VariableAddress[s] :
|
||||
# 2307| r2307_77(glval<unknown>) = FunctionAddress[~String] :
|
||||
# 2307| v2307_78(void) = Call[~String] : func:r2307_77, this:r2307_76
|
||||
# 2307| m2307_79(unknown) = ^CallSideEffect : ~m2309_8
|
||||
# 2307| m2307_80(unknown) = Chi : total:m2309_8, partial:m2307_79
|
||||
# 2307| v2307_81(void) = ^IndirectReadSideEffect[-1] : &:r2307_76, ~m2307_80
|
||||
# 2307| m2307_82(String) = ^IndirectMayWriteSideEffect[-1] : &:r2307_76
|
||||
# 2307| m2307_83(unknown) = Chi : total:m2307_80, partial:m2307_82
|
||||
# 2307| r2307_84(glval<iterator<random_access_iterator_tag, String, ptrdiff_t, String *, String &>>) = VariableAddress[(__begin)] :
|
||||
# 2307| r2307_85(glval<unknown>) = FunctionAddress[operator++] :
|
||||
# 2307| r2307_86(iterator<random_access_iterator_tag, String, ptrdiff_t, String *, String &> &) = Call[operator++] : func:r2307_85, this:r2307_84
|
||||
# 2307| v2307_87(void) = ^IndirectReadSideEffect[-1] : &:r2307_84, m2307_47
|
||||
# 2307| m2307_88(iterator<random_access_iterator_tag, String, ptrdiff_t, String *, String &>) = ^IndirectMayWriteSideEffect[-1] : &:r2307_84
|
||||
# 2307| m2307_89(iterator<random_access_iterator_tag, String, ptrdiff_t, String *, String &>) = Chi : total:m2307_47, partial:m2307_88
|
||||
# 2307| r2307_90(glval<iterator<random_access_iterator_tag, String, ptrdiff_t, String *, String &>>) = CopyValue : r2307_86
|
||||
# 2307| r2307_76(glval<iterator<random_access_iterator_tag, String, ptrdiff_t, String *, String &>>) = VariableAddress[(__begin)] :
|
||||
# 2307| r2307_77(glval<unknown>) = FunctionAddress[operator++] :
|
||||
# 2307| r2307_78(iterator<random_access_iterator_tag, String, ptrdiff_t, String *, String &> &) = Call[operator++] : func:r2307_77, this:r2307_76
|
||||
# 2307| v2307_79(void) = ^IndirectReadSideEffect[-1] : &:r2307_76, m2307_47
|
||||
# 2307| m2307_80(iterator<random_access_iterator_tag, String, ptrdiff_t, String *, String &>) = ^IndirectMayWriteSideEffect[-1] : &:r2307_76
|
||||
# 2307| m2307_81(iterator<random_access_iterator_tag, String, ptrdiff_t, String *, String &>) = Chi : total:m2307_47, partial:m2307_80
|
||||
# 2307| r2307_82(glval<String>) = VariableAddress[s] :
|
||||
# 2307| r2307_83(glval<unknown>) = FunctionAddress[~String] :
|
||||
# 2307| v2307_84(void) = Call[~String] : func:r2307_83, this:r2307_82
|
||||
# 2307| m2307_85(unknown) = ^CallSideEffect : ~m2309_8
|
||||
# 2307| m2307_86(unknown) = Chi : total:m2309_8, partial:m2307_85
|
||||
# 2307| v2307_87(void) = ^IndirectReadSideEffect[-1] : &:r2307_82, ~m2307_86
|
||||
# 2307| m2307_88(String) = ^IndirectMayWriteSideEffect[-1] : &:r2307_82
|
||||
# 2307| m2307_89(unknown) = Chi : total:m2307_86, partial:m2307_88
|
||||
# 2307| r2307_90(glval<iterator<random_access_iterator_tag, String, ptrdiff_t, String *, String &>>) = CopyValue : r2307_78
|
||||
#-----| Goto (back edge) -> Block 4
|
||||
|
||||
# 2311| Block 6
|
||||
@@ -17805,6 +17853,330 @@ ir.cpp:
|
||||
# 2478| v2478_6(void) = AliasedUse : ~m2480_20
|
||||
# 2478| v2478_7(void) = ExitFunction :
|
||||
|
||||
# 2484| void destructor_without_block(bool)
|
||||
# 2484| Block 0
|
||||
# 2484| v2484_1(void) = EnterFunction :
|
||||
# 2484| m2484_2(unknown) = AliasedDefinition :
|
||||
# 2484| m2484_3(unknown) = InitializeNonLocal :
|
||||
# 2484| m2484_4(unknown) = Chi : total:m2484_2, partial:m2484_3
|
||||
# 2484| r2484_5(glval<bool>) = VariableAddress[b] :
|
||||
# 2484| m2484_6(bool) = InitializeParameter[b] : &:r2484_5
|
||||
# 2486| r2486_1(glval<bool>) = VariableAddress[b] :
|
||||
# 2486| r2486_2(bool) = Load[b] : &:r2486_1, m2484_6
|
||||
# 2486| v2486_3(void) = ConditionalBranch : r2486_2
|
||||
#-----| False -> Block 2
|
||||
#-----| True -> Block 1
|
||||
|
||||
# 2487| Block 1
|
||||
# 2487| r2487_1(glval<ClassWithDestructor>) = VariableAddress[c] :
|
||||
# 2487| m2487_2(ClassWithDestructor) = Uninitialized[c] : &:r2487_1
|
||||
# 2487| r2487_3(glval<unknown>) = FunctionAddress[ClassWithDestructor] :
|
||||
# 2487| v2487_4(void) = Call[ClassWithDestructor] : func:r2487_3, this:r2487_1
|
||||
# 2487| m2487_5(unknown) = ^CallSideEffect : ~m2484_4
|
||||
# 2487| m2487_6(unknown) = Chi : total:m2484_4, partial:m2487_5
|
||||
# 2487| m2487_7(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2487_1
|
||||
# 2487| m2487_8(ClassWithDestructor) = Chi : total:m2487_2, partial:m2487_7
|
||||
#-----| r0_1(glval<ClassWithDestructor>) = VariableAddress[c] :
|
||||
#-----| r0_2(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
|
||||
#-----| v0_3(void) = Call[~ClassWithDestructor] : func:r0_2, this:r0_1
|
||||
#-----| m0_4(unknown) = ^CallSideEffect : ~m2487_6
|
||||
#-----| m0_5(unknown) = Chi : total:m2487_6, partial:m0_4
|
||||
#-----| v0_6(void) = ^IndirectReadSideEffect[-1] : &:r0_1, m2487_8
|
||||
#-----| m0_7(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r0_1
|
||||
#-----| m0_8(ClassWithDestructor) = Chi : total:m2487_8, partial:m0_7
|
||||
#-----| Goto -> Block 2
|
||||
|
||||
# 2489| Block 2
|
||||
# 2489| m2489_1(unknown) = Phi : from 0:~m2484_4, from 1:~m0_5
|
||||
# 2489| r2489_2(glval<bool>) = VariableAddress[b] :
|
||||
# 2489| r2489_3(bool) = Load[b] : &:r2489_2, m2484_6
|
||||
# 2489| v2489_4(void) = ConditionalBranch : r2489_3
|
||||
#-----| False -> Block 4
|
||||
#-----| True -> Block 3
|
||||
|
||||
# 2490| Block 3
|
||||
# 2490| r2490_1(glval<ClassWithDestructor>) = VariableAddress[d] :
|
||||
# 2490| m2490_2(ClassWithDestructor) = Uninitialized[d] : &:r2490_1
|
||||
# 2490| r2490_3(glval<unknown>) = FunctionAddress[ClassWithDestructor] :
|
||||
# 2490| v2490_4(void) = Call[ClassWithDestructor] : func:r2490_3, this:r2490_1
|
||||
# 2490| m2490_5(unknown) = ^CallSideEffect : ~m2489_1
|
||||
# 2490| m2490_6(unknown) = Chi : total:m2489_1, partial:m2490_5
|
||||
# 2490| m2490_7(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2490_1
|
||||
# 2490| m2490_8(ClassWithDestructor) = Chi : total:m2490_2, partial:m2490_7
|
||||
#-----| r0_9(glval<ClassWithDestructor>) = VariableAddress[d] :
|
||||
#-----| r0_10(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
|
||||
#-----| v0_11(void) = Call[~ClassWithDestructor] : func:r0_10, this:r0_9
|
||||
#-----| m0_12(unknown) = ^CallSideEffect : ~m2490_6
|
||||
#-----| m0_13(unknown) = Chi : total:m2490_6, partial:m0_12
|
||||
#-----| v0_14(void) = ^IndirectReadSideEffect[-1] : &:r0_9, m2490_8
|
||||
#-----| m0_15(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r0_9
|
||||
#-----| m0_16(ClassWithDestructor) = Chi : total:m2490_8, partial:m0_15
|
||||
#-----| Goto -> Block 5
|
||||
|
||||
# 2492| Block 4
|
||||
# 2492| r2492_1(glval<ClassWithDestructor>) = VariableAddress[e] :
|
||||
# 2492| m2492_2(ClassWithDestructor) = Uninitialized[e] : &:r2492_1
|
||||
# 2492| r2492_3(glval<unknown>) = FunctionAddress[ClassWithDestructor] :
|
||||
# 2492| v2492_4(void) = Call[ClassWithDestructor] : func:r2492_3, this:r2492_1
|
||||
# 2492| m2492_5(unknown) = ^CallSideEffect : ~m2489_1
|
||||
# 2492| m2492_6(unknown) = Chi : total:m2489_1, partial:m2492_5
|
||||
# 2492| m2492_7(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2492_1
|
||||
# 2492| m2492_8(ClassWithDestructor) = Chi : total:m2492_2, partial:m2492_7
|
||||
#-----| r0_17(glval<ClassWithDestructor>) = VariableAddress[e] :
|
||||
#-----| r0_18(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
|
||||
#-----| v0_19(void) = Call[~ClassWithDestructor] : func:r0_18, this:r0_17
|
||||
#-----| m0_20(unknown) = ^CallSideEffect : ~m2492_6
|
||||
#-----| m0_21(unknown) = Chi : total:m2492_6, partial:m0_20
|
||||
#-----| v0_22(void) = ^IndirectReadSideEffect[-1] : &:r0_17, m2492_8
|
||||
#-----| m0_23(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r0_17
|
||||
#-----| m0_24(ClassWithDestructor) = Chi : total:m2492_8, partial:m0_23
|
||||
#-----| Goto -> Block 5
|
||||
|
||||
# 2494| Block 5
|
||||
# 2494| m2494_1(unknown) = Phi : from 3:~m0_13, from 4:~m0_21, from 6:~m0_29
|
||||
# 2494| r2494_2(glval<bool>) = VariableAddress[b] :
|
||||
# 2494| r2494_3(bool) = Load[b] : &:r2494_2, m2484_6
|
||||
# 2494| v2494_4(void) = ConditionalBranch : r2494_3
|
||||
#-----| False -> Block 7
|
||||
#-----| True -> Block 6
|
||||
|
||||
# 2495| Block 6
|
||||
# 2495| r2495_1(glval<ClassWithDestructor>) = VariableAddress[f] :
|
||||
# 2495| m2495_2(ClassWithDestructor) = Uninitialized[f] : &:r2495_1
|
||||
# 2495| r2495_3(glval<unknown>) = FunctionAddress[ClassWithDestructor] :
|
||||
# 2495| v2495_4(void) = Call[ClassWithDestructor] : func:r2495_3, this:r2495_1
|
||||
# 2495| m2495_5(unknown) = ^CallSideEffect : ~m2494_1
|
||||
# 2495| m2495_6(unknown) = Chi : total:m2494_1, partial:m2495_5
|
||||
# 2495| m2495_7(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2495_1
|
||||
# 2495| m2495_8(ClassWithDestructor) = Chi : total:m2495_2, partial:m2495_7
|
||||
#-----| r0_25(glval<ClassWithDestructor>) = VariableAddress[f] :
|
||||
#-----| r0_26(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
|
||||
#-----| v0_27(void) = Call[~ClassWithDestructor] : func:r0_26, this:r0_25
|
||||
#-----| m0_28(unknown) = ^CallSideEffect : ~m2495_6
|
||||
#-----| m0_29(unknown) = Chi : total:m2495_6, partial:m0_28
|
||||
#-----| v0_30(void) = ^IndirectReadSideEffect[-1] : &:r0_25, m2495_8
|
||||
#-----| m0_31(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r0_25
|
||||
#-----| m0_32(ClassWithDestructor) = Chi : total:m2495_8, partial:m0_31
|
||||
#-----| Goto (back edge) -> Block 5
|
||||
|
||||
# 2497| Block 7
|
||||
# 2497| r2497_1(glval<int>) = VariableAddress[i] :
|
||||
# 2497| r2497_2(int) = Constant[0] :
|
||||
# 2497| m2497_3(int) = Store[i] : &:r2497_1, r2497_2
|
||||
#-----| Goto -> Block 8
|
||||
|
||||
# 2497| Block 8
|
||||
# 2497| m2497_4(unknown) = Phi : from 7:~m2494_1, from 9:~m0_37
|
||||
# 2497| m2497_5(int) = Phi : from 7:m2497_3, from 9:m2497_15
|
||||
# 2497| r2497_6(glval<int>) = VariableAddress[i] :
|
||||
# 2497| r2497_7(int) = Load[i] : &:r2497_6, m2497_5
|
||||
# 2497| r2497_8(int) = Constant[42] :
|
||||
# 2497| r2497_9(bool) = CompareLT : r2497_7, r2497_8
|
||||
# 2497| v2497_10(void) = ConditionalBranch : r2497_9
|
||||
#-----| False -> Block 10
|
||||
#-----| True -> Block 9
|
||||
|
||||
# 2498| Block 9
|
||||
# 2498| r2498_1(glval<ClassWithDestructor>) = VariableAddress[g] :
|
||||
# 2498| m2498_2(ClassWithDestructor) = Uninitialized[g] : &:r2498_1
|
||||
# 2498| r2498_3(glval<unknown>) = FunctionAddress[ClassWithDestructor] :
|
||||
# 2498| v2498_4(void) = Call[ClassWithDestructor] : func:r2498_3, this:r2498_1
|
||||
# 2498| m2498_5(unknown) = ^CallSideEffect : ~m2497_4
|
||||
# 2498| m2498_6(unknown) = Chi : total:m2497_4, partial:m2498_5
|
||||
# 2498| m2498_7(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2498_1
|
||||
# 2498| m2498_8(ClassWithDestructor) = Chi : total:m2498_2, partial:m2498_7
|
||||
#-----| r0_33(glval<ClassWithDestructor>) = VariableAddress[g] :
|
||||
#-----| r0_34(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
|
||||
#-----| v0_35(void) = Call[~ClassWithDestructor] : func:r0_34, this:r0_33
|
||||
#-----| m0_36(unknown) = ^CallSideEffect : ~m2498_6
|
||||
#-----| m0_37(unknown) = Chi : total:m2498_6, partial:m0_36
|
||||
#-----| v0_38(void) = ^IndirectReadSideEffect[-1] : &:r0_33, m2498_8
|
||||
#-----| m0_39(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r0_33
|
||||
#-----| m0_40(ClassWithDestructor) = Chi : total:m2498_8, partial:m0_39
|
||||
# 2497| r2497_11(glval<int>) = VariableAddress[i] :
|
||||
# 2497| r2497_12(int) = Load[i] : &:r2497_11, m2497_5
|
||||
# 2497| r2497_13(int) = Constant[1] :
|
||||
# 2497| r2497_14(int) = Add : r2497_12, r2497_13
|
||||
# 2497| m2497_15(int) = Store[i] : &:r2497_11, r2497_14
|
||||
#-----| Goto (back edge) -> Block 8
|
||||
|
||||
# 2499| Block 10
|
||||
# 2499| v2499_1(void) = NoOp :
|
||||
# 2484| v2484_7(void) = ReturnVoid :
|
||||
# 2484| v2484_8(void) = AliasedUse : ~m2497_4
|
||||
# 2484| v2484_9(void) = ExitFunction :
|
||||
|
||||
# 2501| void destruction_in_switch_1(int)
|
||||
# 2501| Block 0
|
||||
# 2501| v2501_1(void) = EnterFunction :
|
||||
# 2501| m2501_2(unknown) = AliasedDefinition :
|
||||
# 2501| m2501_3(unknown) = InitializeNonLocal :
|
||||
# 2501| m2501_4(unknown) = Chi : total:m2501_2, partial:m2501_3
|
||||
# 2501| r2501_5(glval<int>) = VariableAddress[c] :
|
||||
# 2501| m2501_6(int) = InitializeParameter[c] : &:r2501_5
|
||||
# 2502| r2502_1(glval<int>) = VariableAddress[c] :
|
||||
# 2502| r2502_2(int) = Load[c] : &:r2502_1, m2501_6
|
||||
# 2502| v2502_3(void) = Switch : r2502_2
|
||||
#-----| Case[0] -> Block 1
|
||||
#-----| Default -> Block 2
|
||||
|
||||
# 2503| Block 1
|
||||
# 2503| v2503_1(void) = NoOp :
|
||||
# 2504| r2504_1(glval<ClassWithDestructor>) = VariableAddress[x] :
|
||||
# 2504| m2504_2(ClassWithDestructor) = Uninitialized[x] : &:r2504_1
|
||||
# 2504| r2504_3(glval<unknown>) = FunctionAddress[ClassWithDestructor] :
|
||||
# 2504| v2504_4(void) = Call[ClassWithDestructor] : func:r2504_3, this:r2504_1
|
||||
# 2504| m2504_5(unknown) = ^CallSideEffect : ~m2501_4
|
||||
# 2504| m2504_6(unknown) = Chi : total:m2501_4, partial:m2504_5
|
||||
# 2504| m2504_7(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2504_1
|
||||
# 2504| m2504_8(ClassWithDestructor) = Chi : total:m2504_2, partial:m2504_7
|
||||
# 2506| r2506_1(glval<ClassWithDestructor>) = VariableAddress[x] :
|
||||
# 2506| r2506_2(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
|
||||
# 2506| v2506_3(void) = Call[~ClassWithDestructor] : func:r2506_2, this:r2506_1
|
||||
# 2506| m2506_4(unknown) = ^CallSideEffect : ~m2504_6
|
||||
# 2506| m2506_5(unknown) = Chi : total:m2504_6, partial:m2506_4
|
||||
# 2506| v2506_6(void) = ^IndirectReadSideEffect[-1] : &:r2506_1, m2504_8
|
||||
# 2506| m2506_7(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2506_1
|
||||
# 2506| m2506_8(ClassWithDestructor) = Chi : total:m2504_8, partial:m2506_7
|
||||
# 2505| v2505_1(void) = NoOp :
|
||||
#-----| Goto -> Block 2
|
||||
|
||||
# 2507| Block 2
|
||||
# 2507| m2507_1(unknown) = Phi : from 0:~m2501_4, from 1:~m2506_5
|
||||
# 2507| v2507_2(void) = NoOp :
|
||||
# 2508| v2508_1(void) = NoOp :
|
||||
# 2501| v2501_7(void) = ReturnVoid :
|
||||
# 2501| v2501_8(void) = AliasedUse : ~m2507_1
|
||||
# 2501| v2501_9(void) = ExitFunction :
|
||||
|
||||
# 2510| void destruction_in_switch_2(int)
|
||||
# 2510| Block 0
|
||||
# 2510| v2510_1(void) = EnterFunction :
|
||||
# 2510| m2510_2(unknown) = AliasedDefinition :
|
||||
# 2510| m2510_3(unknown) = InitializeNonLocal :
|
||||
# 2510| m2510_4(unknown) = Chi : total:m2510_2, partial:m2510_3
|
||||
# 2510| r2510_5(glval<int>) = VariableAddress[c] :
|
||||
# 2510| m2510_6(int) = InitializeParameter[c] : &:r2510_5
|
||||
# 2511| r2511_1(glval<ClassWithDestructor>) = VariableAddress[y] :
|
||||
# 2511| m2511_2(ClassWithDestructor) = Uninitialized[y] : &:r2511_1
|
||||
# 2511| r2511_3(glval<unknown>) = FunctionAddress[ClassWithDestructor] :
|
||||
# 2511| v2511_4(void) = Call[ClassWithDestructor] : func:r2511_3, this:r2511_1
|
||||
# 2511| m2511_5(unknown) = ^CallSideEffect : ~m2510_4
|
||||
# 2511| m2511_6(unknown) = Chi : total:m2510_4, partial:m2511_5
|
||||
# 2511| m2511_7(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2511_1
|
||||
# 2511| m2511_8(ClassWithDestructor) = Chi : total:m2511_2, partial:m2511_7
|
||||
# 2511| r2511_9(glval<int>) = VariableAddress[c] :
|
||||
# 2511| r2511_10(int) = Load[c] : &:r2511_9, m2510_6
|
||||
# 2511| v2511_11(void) = Switch : r2511_10
|
||||
#-----| Case[0] -> Block 1
|
||||
#-----| Default -> Block 2
|
||||
|
||||
# 2512| Block 1
|
||||
# 2512| v2512_1(void) = NoOp :
|
||||
# 2518| r2518_1(glval<ClassWithDestructor>) = VariableAddress[y] :
|
||||
# 2518| r2518_2(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
|
||||
# 2518| v2518_3(void) = Call[~ClassWithDestructor] : func:r2518_2, this:r2518_1
|
||||
# 2518| m2518_4(unknown) = ^CallSideEffect : ~m2511_6
|
||||
# 2518| m2518_5(unknown) = Chi : total:m2511_6, partial:m2518_4
|
||||
# 2518| v2518_6(void) = ^IndirectReadSideEffect[-1] : &:r2518_1, m2511_8
|
||||
# 2518| m2518_7(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2518_1
|
||||
# 2518| m2518_8(ClassWithDestructor) = Chi : total:m2511_8, partial:m2518_7
|
||||
# 2513| v2513_1(void) = NoOp :
|
||||
#-----| Goto -> Block 3
|
||||
|
||||
# 2515| Block 2
|
||||
# 2515| v2515_1(void) = NoOp :
|
||||
# 2518| r2518_9(glval<ClassWithDestructor>) = VariableAddress[y] :
|
||||
# 2518| r2518_10(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
|
||||
# 2518| v2518_11(void) = Call[~ClassWithDestructor] : func:r2518_10, this:r2518_9
|
||||
# 2518| m2518_12(unknown) = ^CallSideEffect : ~m2511_6
|
||||
# 2518| m2518_13(unknown) = Chi : total:m2511_6, partial:m2518_12
|
||||
# 2518| v2518_14(void) = ^IndirectReadSideEffect[-1] : &:r2518_9, m2511_8
|
||||
# 2518| m2518_15(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2518_9
|
||||
# 2518| m2518_16(ClassWithDestructor) = Chi : total:m2511_8, partial:m2518_15
|
||||
# 2516| v2516_1(void) = NoOp :
|
||||
#-----| Goto -> Block 3
|
||||
|
||||
# 2518| Block 3
|
||||
# 2518| m2518_17(unknown) = Phi : from 1:~m2518_5, from 2:~m2518_13
|
||||
# 2518| v2518_18(void) = NoOp :
|
||||
# 2519| v2519_1(void) = NoOp :
|
||||
# 2510| v2510_7(void) = ReturnVoid :
|
||||
# 2510| v2510_8(void) = AliasedUse : ~m2518_17
|
||||
# 2510| v2510_9(void) = ExitFunction :
|
||||
|
||||
# 2521| void destruction_in_switch_3(int)
|
||||
# 2521| Block 0
|
||||
# 2521| v2521_1(void) = EnterFunction :
|
||||
# 2521| m2521_2(unknown) = AliasedDefinition :
|
||||
# 2521| m2521_3(unknown) = InitializeNonLocal :
|
||||
# 2521| m2521_4(unknown) = Chi : total:m2521_2, partial:m2521_3
|
||||
# 2521| r2521_5(glval<int>) = VariableAddress[c] :
|
||||
# 2521| m2521_6(int) = InitializeParameter[c] : &:r2521_5
|
||||
# 2522| r2522_1(glval<ClassWithDestructor>) = VariableAddress[y] :
|
||||
# 2522| m2522_2(ClassWithDestructor) = Uninitialized[y] : &:r2522_1
|
||||
# 2522| r2522_3(glval<unknown>) = FunctionAddress[ClassWithDestructor] :
|
||||
# 2522| v2522_4(void) = Call[ClassWithDestructor] : func:r2522_3, this:r2522_1
|
||||
# 2522| m2522_5(unknown) = ^CallSideEffect : ~m2521_4
|
||||
# 2522| m2522_6(unknown) = Chi : total:m2521_4, partial:m2522_5
|
||||
# 2522| m2522_7(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2522_1
|
||||
# 2522| m2522_8(ClassWithDestructor) = Chi : total:m2522_2, partial:m2522_7
|
||||
# 2522| r2522_9(glval<int>) = VariableAddress[c] :
|
||||
# 2522| r2522_10(int) = Load[c] : &:r2522_9, m2521_6
|
||||
# 2522| v2522_11(void) = Switch : r2522_10
|
||||
#-----| Case[0] -> Block 1
|
||||
#-----| Default -> Block 2
|
||||
|
||||
# 2523| Block 1
|
||||
# 2523| v2523_1(void) = NoOp :
|
||||
# 2524| r2524_1(glval<ClassWithDestructor>) = VariableAddress[x] :
|
||||
# 2524| m2524_2(ClassWithDestructor) = Uninitialized[x] : &:r2524_1
|
||||
# 2524| r2524_3(glval<unknown>) = FunctionAddress[ClassWithDestructor] :
|
||||
# 2524| v2524_4(void) = Call[ClassWithDestructor] : func:r2524_3, this:r2524_1
|
||||
# 2524| m2524_5(unknown) = ^CallSideEffect : ~m2522_6
|
||||
# 2524| m2524_6(unknown) = Chi : total:m2522_6, partial:m2524_5
|
||||
# 2524| m2524_7(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2524_1
|
||||
# 2524| m2524_8(ClassWithDestructor) = Chi : total:m2524_2, partial:m2524_7
|
||||
# 2526| r2526_1(glval<ClassWithDestructor>) = VariableAddress[x] :
|
||||
# 2526| r2526_2(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
|
||||
# 2526| v2526_3(void) = Call[~ClassWithDestructor] : func:r2526_2, this:r2526_1
|
||||
# 2526| m2526_4(unknown) = ^CallSideEffect : ~m2524_6
|
||||
# 2526| m2526_5(unknown) = Chi : total:m2524_6, partial:m2526_4
|
||||
# 2526| v2526_6(void) = ^IndirectReadSideEffect[-1] : &:r2526_1, m2524_8
|
||||
# 2526| m2526_7(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2526_1
|
||||
# 2526| m2526_8(ClassWithDestructor) = Chi : total:m2524_8, partial:m2526_7
|
||||
# 2530| r2530_1(glval<ClassWithDestructor>) = VariableAddress[y] :
|
||||
# 2530| r2530_2(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
|
||||
# 2530| v2530_3(void) = Call[~ClassWithDestructor] : func:r2530_2, this:r2530_1
|
||||
# 2530| m2530_4(unknown) = ^CallSideEffect : ~m2526_5
|
||||
# 2530| m2530_5(unknown) = Chi : total:m2526_5, partial:m2530_4
|
||||
# 2530| v2530_6(void) = ^IndirectReadSideEffect[-1] : &:r2530_1, m2522_8
|
||||
# 2530| m2530_7(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2530_1
|
||||
# 2530| m2530_8(ClassWithDestructor) = Chi : total:m2522_8, partial:m2530_7
|
||||
# 2525| v2525_1(void) = NoOp :
|
||||
#-----| Goto -> Block 3
|
||||
|
||||
# 2527| Block 2
|
||||
# 2527| v2527_1(void) = NoOp :
|
||||
# 2530| r2530_9(glval<ClassWithDestructor>) = VariableAddress[y] :
|
||||
# 2530| r2530_10(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
|
||||
# 2530| v2530_11(void) = Call[~ClassWithDestructor] : func:r2530_10, this:r2530_9
|
||||
# 2530| m2530_12(unknown) = ^CallSideEffect : ~m2522_6
|
||||
# 2530| m2530_13(unknown) = Chi : total:m2522_6, partial:m2530_12
|
||||
# 2530| v2530_14(void) = ^IndirectReadSideEffect[-1] : &:r2530_9, m2522_8
|
||||
# 2530| m2530_15(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2530_9
|
||||
# 2530| m2530_16(ClassWithDestructor) = Chi : total:m2522_8, partial:m2530_15
|
||||
# 2528| v2528_1(void) = NoOp :
|
||||
#-----| Goto -> Block 3
|
||||
|
||||
# 2530| Block 3
|
||||
# 2530| m2530_17(unknown) = Phi : from 1:~m2530_5, from 2:~m2530_13
|
||||
# 2530| v2530_18(void) = NoOp :
|
||||
# 2531| v2531_1(void) = NoOp :
|
||||
# 2521| v2521_7(void) = ReturnVoid :
|
||||
# 2521| v2521_8(void) = AliasedUse : ~m2530_17
|
||||
# 2521| v2521_9(void) = ExitFunction :
|
||||
|
||||
perf-regression.cpp:
|
||||
# 6| void Big::Big()
|
||||
# 6| Block 0
|
||||
|
||||
@@ -2432,7 +2432,7 @@ void initialization_with_temp_destructor() {
|
||||
}
|
||||
|
||||
void param_with_destructor_by_value(ClassWithDestructor c) {
|
||||
// The call to ~ClassWithDestructor::ClassWithDestructor() seems to be missing here.
|
||||
// The call to ~ClassWithDestructor::ClassWithDestructor() happens on the side of the caller
|
||||
}
|
||||
|
||||
void param_with_destructor_by_pointer(ClassWithDestructor* c) {
|
||||
@@ -2481,4 +2481,53 @@ namespace rvalue_conversion_with_destructor {
|
||||
}
|
||||
}
|
||||
|
||||
void destructor_without_block(bool b)
|
||||
{
|
||||
if (b)
|
||||
ClassWithDestructor c;
|
||||
|
||||
if (b)
|
||||
ClassWithDestructor d;
|
||||
else
|
||||
ClassWithDestructor e;
|
||||
|
||||
while (b)
|
||||
ClassWithDestructor f;
|
||||
|
||||
for(int i = 0; i < 42; ++i)
|
||||
ClassWithDestructor g;
|
||||
}
|
||||
|
||||
void destruction_in_switch_1(int c) {
|
||||
switch (c) {
|
||||
case 0: {
|
||||
ClassWithDestructor x;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void destruction_in_switch_2(int c) {
|
||||
switch (ClassWithDestructor y; c) {
|
||||
case 0: {
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void destruction_in_switch_3(int c) {
|
||||
switch (ClassWithDestructor y; c) {
|
||||
case 0: {
|
||||
ClassWithDestructor x;
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// semmle-extractor-options: -std=c++20 --clang
|
||||
|
||||
@@ -14207,40 +14207,52 @@ ir.cpp:
|
||||
#-----| Default -> Block 8
|
||||
|
||||
# 2206| Block 7
|
||||
# 2206| v2206_1(void) = NoOp :
|
||||
# 2207| r2207_1(glval<ClassWithDestructor>) = VariableAddress[x] :
|
||||
# 2207| r2207_2(glval<unknown>) = FunctionAddress[set_x] :
|
||||
# 2207| r2207_3(char) = Constant[97] :
|
||||
# 2207| v2207_4(void) = Call[set_x] : func:r2207_2, this:r2207_1, 0:r2207_3
|
||||
# 2207| mu2207_5(unknown) = ^CallSideEffect : ~m?
|
||||
# 2207| v2207_6(void) = ^IndirectReadSideEffect[-1] : &:r2207_1, ~m?
|
||||
# 2207| mu2207_7(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2207_1
|
||||
# 2208| v2208_1(void) = NoOp :
|
||||
#-----| Goto -> Block 10
|
||||
|
||||
# 2209| Block 8
|
||||
# 2209| v2209_1(void) = NoOp :
|
||||
# 2210| r2210_1(glval<ClassWithDestructor>) = VariableAddress[x] :
|
||||
# 2210| r2210_2(glval<unknown>) = FunctionAddress[set_x] :
|
||||
# 2210| r2210_3(char) = Constant[98] :
|
||||
# 2210| v2210_4(void) = Call[set_x] : func:r2210_2, this:r2210_1, 0:r2210_3
|
||||
# 2210| mu2210_5(unknown) = ^CallSideEffect : ~m?
|
||||
# 2210| v2210_6(void) = ^IndirectReadSideEffect[-1] : &:r2210_1, ~m?
|
||||
# 2210| mu2210_7(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2210_1
|
||||
# 2211| v2211_1(void) = NoOp :
|
||||
#-----| Goto -> Block 10
|
||||
|
||||
# 2212| Block 9
|
||||
# 2206| v2206_1(void) = NoOp :
|
||||
# 2207| r2207_1(glval<ClassWithDestructor>) = VariableAddress[x] :
|
||||
# 2207| r2207_2(glval<unknown>) = FunctionAddress[set_x] :
|
||||
# 2207| r2207_3(char) = Constant[97] :
|
||||
# 2207| v2207_4(void) = Call[set_x] : func:r2207_2, this:r2207_1, 0:r2207_3
|
||||
# 2207| mu2207_5(unknown) = ^CallSideEffect : ~m?
|
||||
# 2207| v2207_6(void) = ^IndirectReadSideEffect[-1] : &:r2207_1, ~m?
|
||||
# 2207| mu2207_7(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2207_1
|
||||
# 2212| r2212_1(glval<ClassWithDestructor>) = VariableAddress[x] :
|
||||
# 2212| r2212_2(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
|
||||
# 2212| v2212_3(void) = Call[~ClassWithDestructor] : func:r2212_2, this:r2212_1
|
||||
# 2212| mu2212_4(unknown) = ^CallSideEffect : ~m?
|
||||
# 2212| v2212_5(void) = ^IndirectReadSideEffect[-1] : &:r2212_1, ~m?
|
||||
# 2212| mu2212_6(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2212_1
|
||||
# 2208| v2208_1(void) = NoOp :
|
||||
#-----| Goto -> Block 10
|
||||
|
||||
# 2209| Block 8
|
||||
# 2209| v2209_1(void) = NoOp :
|
||||
# 2210| r2210_1(glval<ClassWithDestructor>) = VariableAddress[x] :
|
||||
# 2210| r2210_2(glval<unknown>) = FunctionAddress[set_x] :
|
||||
# 2210| r2210_3(char) = Constant[98] :
|
||||
# 2210| v2210_4(void) = Call[set_x] : func:r2210_2, this:r2210_1, 0:r2210_3
|
||||
# 2210| mu2210_5(unknown) = ^CallSideEffect : ~m?
|
||||
# 2210| v2210_6(void) = ^IndirectReadSideEffect[-1] : &:r2210_1, ~m?
|
||||
# 2210| mu2210_7(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2210_1
|
||||
# 2212| r2212_7(glval<ClassWithDestructor>) = VariableAddress[x] :
|
||||
# 2212| r2212_8(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
|
||||
# 2212| v2212_9(void) = Call[~ClassWithDestructor] : func:r2212_8, this:r2212_7
|
||||
# 2212| mu2212_10(unknown) = ^CallSideEffect : ~m?
|
||||
# 2212| v2212_11(void) = ^IndirectReadSideEffect[-1] : &:r2212_7, ~m?
|
||||
# 2212| mu2212_12(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2212_7
|
||||
# 2211| v2211_1(void) = NoOp :
|
||||
#-----| Goto -> Block 10
|
||||
|
||||
# 2212| Block 9
|
||||
# 2212| r2212_13(glval<ClassWithDestructor>) = VariableAddress[x] :
|
||||
# 2212| r2212_14(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
|
||||
# 2212| v2212_15(void) = Call[~ClassWithDestructor] : func:r2212_14, this:r2212_13
|
||||
# 2212| mu2212_16(unknown) = ^CallSideEffect : ~m?
|
||||
# 2212| v2212_17(void) = ^IndirectReadSideEffect[-1] : &:r2212_13, ~m?
|
||||
# 2212| mu2212_18(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2212_13
|
||||
#-----| Goto -> Block 10
|
||||
|
||||
# 2212| Block 10
|
||||
# 2212| v2212_7(void) = NoOp :
|
||||
# 2212| v2212_19(void) = NoOp :
|
||||
# 2214| r2214_1(glval<ClassWithDestructor>) = VariableAddress[x] :
|
||||
# 2214| mu2214_2(ClassWithDestructor) = Uninitialized[x] : &:r2214_1
|
||||
# 2214| r2214_3(glval<unknown>) = FunctionAddress[ClassWithDestructor] :
|
||||
@@ -14306,7 +14318,7 @@ ir.cpp:
|
||||
# 2215| r2215_41(bool) = Call[operator!=] : func:r2215_35, this:r0_7, 0:r0_13
|
||||
#-----| v0_14(void) = ^IndirectReadSideEffect[-1] : &:r0_7, ~m?
|
||||
# 2215| v2215_42(void) = ConditionalBranch : r2215_41
|
||||
#-----| False -> Block 14
|
||||
#-----| False -> Block 13
|
||||
#-----| True -> Block 12
|
||||
|
||||
# 2215| Block 12
|
||||
@@ -14325,30 +14337,27 @@ ir.cpp:
|
||||
# 2216| mu2216_5(unknown) = ^CallSideEffect : ~m?
|
||||
# 2216| v2216_6(void) = ^IndirectReadSideEffect[-1] : &:r2216_1, ~m?
|
||||
# 2216| mu2216_7(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2216_1
|
||||
# 2215| r2215_49(glval<ClassWithDestructor>) = VariableAddress[y] :
|
||||
# 2215| r2215_50(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
|
||||
# 2215| v2215_51(void) = Call[~ClassWithDestructor] : func:r2215_50, this:r2215_49
|
||||
# 2215| mu2215_52(unknown) = ^CallSideEffect : ~m?
|
||||
# 2215| v2215_53(void) = ^IndirectReadSideEffect[-1] : &:r2215_49, ~m?
|
||||
# 2215| mu2215_54(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2215_49
|
||||
# 2215| r2215_55(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = VariableAddress[(__begin)] :
|
||||
# 2215| r2215_56(glval<unknown>) = FunctionAddress[operator++] :
|
||||
# 2215| r2215_57(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &> &) = Call[operator++] : func:r2215_56, this:r2215_55
|
||||
# 2215| v2215_58(void) = ^IndirectReadSideEffect[-1] : &:r2215_55, ~m?
|
||||
# 2215| mu2215_59(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>) = ^IndirectMayWriteSideEffect[-1] : &:r2215_55
|
||||
# 2215| r2215_60(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = CopyValue : r2215_57
|
||||
# 2215| r2215_49(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = VariableAddress[(__begin)] :
|
||||
# 2215| r2215_50(glval<unknown>) = FunctionAddress[operator++] :
|
||||
# 2215| r2215_51(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &> &) = Call[operator++] : func:r2215_50, this:r2215_49
|
||||
# 2215| v2215_52(void) = ^IndirectReadSideEffect[-1] : &:r2215_49, ~m?
|
||||
# 2215| mu2215_53(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>) = ^IndirectMayWriteSideEffect[-1] : &:r2215_49
|
||||
# 2215| r2215_54(glval<ClassWithDestructor>) = VariableAddress[y] :
|
||||
# 2215| r2215_55(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
|
||||
# 2215| v2215_56(void) = Call[~ClassWithDestructor] : func:r2215_55, this:r2215_54
|
||||
# 2215| mu2215_57(unknown) = ^CallSideEffect : ~m?
|
||||
# 2215| v2215_58(void) = ^IndirectReadSideEffect[-1] : &:r2215_54, ~m?
|
||||
# 2215| mu2215_59(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2215_54
|
||||
# 2215| r2215_60(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = CopyValue : r2215_51
|
||||
#-----| Goto (back edge) -> Block 11
|
||||
|
||||
# 2215| Block 13
|
||||
# 2215| r2215_61(glval<vector<ClassWithDestructor>>) = VariableAddress[ys] :
|
||||
# 2215| r2215_62(glval<unknown>) = FunctionAddress[~vector] :
|
||||
# 2215| v2215_63(void) = Call[~vector] : func:r2215_62, this:r2215_61
|
||||
# 2215| mu2215_64(unknown) = ^CallSideEffect : ~m?
|
||||
# 2215| v2215_65(void) = ^IndirectReadSideEffect[-1] : &:r2215_61, ~m?
|
||||
# 2215| mu2215_66(vector<ClassWithDestructor>) = ^IndirectMayWriteSideEffect[-1] : &:r2215_61
|
||||
#-----| Goto -> Block 14
|
||||
|
||||
# 2218| Block 14
|
||||
# 2215| r2215_61(glval<vector<ClassWithDestructor>>) = VariableAddress[ys] :
|
||||
# 2215| r2215_62(glval<unknown>) = FunctionAddress[~vector] :
|
||||
# 2215| v2215_63(void) = Call[~vector] : func:r2215_62, this:r2215_61
|
||||
# 2215| mu2215_64(unknown) = ^CallSideEffect : ~m?
|
||||
# 2215| v2215_65(void) = ^IndirectReadSideEffect[-1] : &:r2215_61, ~m?
|
||||
# 2215| mu2215_66(vector<ClassWithDestructor>) = ^IndirectMayWriteSideEffect[-1] : &:r2215_61
|
||||
# 2218| r2218_1(glval<vector<ClassWithDestructor>>) = VariableAddress[ys] :
|
||||
# 2218| mu2218_2(vector<ClassWithDestructor>) = Uninitialized[ys] : &:r2218_1
|
||||
# 2218| r2218_3(glval<unknown>) = FunctionAddress[vector] :
|
||||
@@ -14388,9 +14397,9 @@ ir.cpp:
|
||||
# 2218| r2218_32(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>) = Call[end] : func:r2218_31, this:r0_21
|
||||
#-----| v0_22(void) = ^IndirectReadSideEffect[-1] : &:r0_21, ~m?
|
||||
# 2218| mu2218_33(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>) = Store[(__end)] : &:r2218_28, r2218_32
|
||||
#-----| Goto -> Block 15
|
||||
#-----| Goto -> Block 14
|
||||
|
||||
# 2218| Block 15
|
||||
# 2218| Block 14
|
||||
# 2218| r2218_34(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = VariableAddress[(__begin)] :
|
||||
#-----| r0_23(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = Convert : r2218_34
|
||||
# 2218| r2218_35(glval<unknown>) = FunctionAddress[operator!=] :
|
||||
@@ -14408,18 +14417,33 @@ ir.cpp:
|
||||
# 2218| r2218_41(bool) = Call[operator!=] : func:r2218_35, this:r0_23, 0:r0_29
|
||||
#-----| v0_30(void) = ^IndirectReadSideEffect[-1] : &:r0_23, ~m?
|
||||
# 2218| v2218_42(void) = ConditionalBranch : r2218_41
|
||||
#-----| False -> Block 20
|
||||
#-----| False -> Block 18
|
||||
#-----| True -> Block 16
|
||||
|
||||
# 2218| Block 15
|
||||
# 2218| r2218_43(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = VariableAddress[(__begin)] :
|
||||
# 2218| r2218_44(glval<unknown>) = FunctionAddress[operator++] :
|
||||
# 2218| r2218_45(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &> &) = Call[operator++] : func:r2218_44, this:r2218_43
|
||||
# 2218| v2218_46(void) = ^IndirectReadSideEffect[-1] : &:r2218_43, ~m?
|
||||
# 2218| mu2218_47(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>) = ^IndirectMayWriteSideEffect[-1] : &:r2218_43
|
||||
# 2218| r2218_48(glval<ClassWithDestructor>) = VariableAddress[y] :
|
||||
# 2218| r2218_49(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
|
||||
# 2218| v2218_50(void) = Call[~ClassWithDestructor] : func:r2218_49, this:r2218_48
|
||||
# 2218| mu2218_51(unknown) = ^CallSideEffect : ~m?
|
||||
# 2218| v2218_52(void) = ^IndirectReadSideEffect[-1] : &:r2218_48, ~m?
|
||||
# 2218| mu2218_53(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2218_48
|
||||
# 2218| r2218_54(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = CopyValue : r2218_45
|
||||
#-----| Goto (back edge) -> Block 14
|
||||
|
||||
# 2218| Block 16
|
||||
# 2218| r2218_43(glval<ClassWithDestructor>) = VariableAddress[y] :
|
||||
# 2218| r2218_44(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = VariableAddress[(__begin)] :
|
||||
#-----| r0_31(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = Convert : r2218_44
|
||||
# 2218| r2218_45(glval<unknown>) = FunctionAddress[operator*] :
|
||||
# 2218| r2218_46(ClassWithDestructor &) = Call[operator*] : func:r2218_45, this:r0_31
|
||||
# 2218| r2218_55(glval<ClassWithDestructor>) = VariableAddress[y] :
|
||||
# 2218| r2218_56(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = VariableAddress[(__begin)] :
|
||||
#-----| r0_31(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = Convert : r2218_56
|
||||
# 2218| r2218_57(glval<unknown>) = FunctionAddress[operator*] :
|
||||
# 2218| r2218_58(ClassWithDestructor &) = Call[operator*] : func:r2218_57, this:r0_31
|
||||
#-----| v0_32(void) = ^IndirectReadSideEffect[-1] : &:r0_31, ~m?
|
||||
# 2218| r2218_47(ClassWithDestructor) = Load[?] : &:r2218_46, ~m?
|
||||
# 2218| mu2218_48(ClassWithDestructor) = Store[y] : &:r2218_43, r2218_47
|
||||
# 2218| r2218_59(ClassWithDestructor) = Load[?] : &:r2218_58, ~m?
|
||||
# 2218| mu2218_60(ClassWithDestructor) = Store[y] : &:r2218_55, r2218_59
|
||||
# 2219| r2219_1(glval<ClassWithDestructor>) = VariableAddress[y] :
|
||||
# 2219| r2219_2(glval<unknown>) = FunctionAddress[set_x] :
|
||||
# 2219| r2219_3(char) = Constant[97] :
|
||||
@@ -14437,23 +14461,23 @@ ir.cpp:
|
||||
# 2220| r2220_8(int) = Constant[98] :
|
||||
# 2220| r2220_9(bool) = CompareEQ : r2220_7, r2220_8
|
||||
# 2220| v2220_10(void) = ConditionalBranch : r2220_9
|
||||
#-----| False -> Block 18
|
||||
#-----| False -> Block 15
|
||||
#-----| True -> Block 17
|
||||
|
||||
# 2221| Block 17
|
||||
# 2221| v2221_1(void) = NoOp :
|
||||
# 2218| r2218_49(glval<ClassWithDestructor>) = VariableAddress[y] :
|
||||
# 2218| r2218_50(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
|
||||
# 2218| v2218_51(void) = Call[~ClassWithDestructor] : func:r2218_50, this:r2218_49
|
||||
# 2218| mu2218_52(unknown) = ^CallSideEffect : ~m?
|
||||
# 2218| v2218_53(void) = ^IndirectReadSideEffect[-1] : &:r2218_49, ~m?
|
||||
# 2218| mu2218_54(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2218_49
|
||||
# 2218| r2218_55(glval<vector<ClassWithDestructor>>) = VariableAddress[ys] :
|
||||
# 2218| r2218_56(glval<unknown>) = FunctionAddress[~vector] :
|
||||
# 2218| v2218_57(void) = Call[~vector] : func:r2218_56, this:r2218_55
|
||||
# 2218| mu2218_58(unknown) = ^CallSideEffect : ~m?
|
||||
# 2218| v2218_59(void) = ^IndirectReadSideEffect[-1] : &:r2218_55, ~m?
|
||||
# 2218| mu2218_60(vector<ClassWithDestructor>) = ^IndirectMayWriteSideEffect[-1] : &:r2218_55
|
||||
# 2218| r2218_61(glval<ClassWithDestructor>) = VariableAddress[y] :
|
||||
# 2218| r2218_62(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
|
||||
# 2218| v2218_63(void) = Call[~ClassWithDestructor] : func:r2218_62, this:r2218_61
|
||||
# 2218| mu2218_64(unknown) = ^CallSideEffect : ~m?
|
||||
# 2218| v2218_65(void) = ^IndirectReadSideEffect[-1] : &:r2218_61, ~m?
|
||||
# 2218| mu2218_66(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2218_61
|
||||
# 2218| r2218_67(glval<vector<ClassWithDestructor>>) = VariableAddress[ys] :
|
||||
# 2218| r2218_68(glval<unknown>) = FunctionAddress[~vector] :
|
||||
# 2218| v2218_69(void) = Call[~vector] : func:r2218_68, this:r2218_67
|
||||
# 2218| mu2218_70(unknown) = ^CallSideEffect : ~m?
|
||||
# 2218| v2218_71(void) = ^IndirectReadSideEffect[-1] : &:r2218_67, ~m?
|
||||
# 2218| mu2218_72(vector<ClassWithDestructor>) = ^IndirectMayWriteSideEffect[-1] : &:r2218_67
|
||||
# 2233| r2233_1(glval<ClassWithDestructor>) = VariableAddress[x] :
|
||||
# 2233| r2233_2(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
|
||||
# 2233| v2233_3(void) = Call[~ClassWithDestructor] : func:r2233_2, this:r2233_1
|
||||
@@ -14463,30 +14487,12 @@ ir.cpp:
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
# 2218| Block 18
|
||||
# 2218| r2218_61(glval<ClassWithDestructor>) = VariableAddress[y] :
|
||||
# 2218| r2218_62(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
|
||||
# 2218| v2218_63(void) = Call[~ClassWithDestructor] : func:r2218_62, this:r2218_61
|
||||
# 2218| mu2218_64(unknown) = ^CallSideEffect : ~m?
|
||||
# 2218| v2218_65(void) = ^IndirectReadSideEffect[-1] : &:r2218_61, ~m?
|
||||
# 2218| mu2218_66(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2218_61
|
||||
# 2218| r2218_67(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = VariableAddress[(__begin)] :
|
||||
# 2218| r2218_68(glval<unknown>) = FunctionAddress[operator++] :
|
||||
# 2218| r2218_69(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &> &) = Call[operator++] : func:r2218_68, this:r2218_67
|
||||
# 2218| v2218_70(void) = ^IndirectReadSideEffect[-1] : &:r2218_67, ~m?
|
||||
# 2218| mu2218_71(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>) = ^IndirectMayWriteSideEffect[-1] : &:r2218_67
|
||||
# 2218| r2218_72(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = CopyValue : r2218_69
|
||||
#-----| Goto (back edge) -> Block 15
|
||||
|
||||
# 2218| Block 19
|
||||
# 2218| r2218_73(glval<vector<ClassWithDestructor>>) = VariableAddress[ys] :
|
||||
# 2218| r2218_74(glval<unknown>) = FunctionAddress[~vector] :
|
||||
# 2218| v2218_75(void) = Call[~vector] : func:r2218_74, this:r2218_73
|
||||
# 2218| mu2218_76(unknown) = ^CallSideEffect : ~m?
|
||||
# 2218| v2218_77(void) = ^IndirectReadSideEffect[-1] : &:r2218_73, ~m?
|
||||
# 2218| mu2218_78(vector<ClassWithDestructor>) = ^IndirectMayWriteSideEffect[-1] : &:r2218_73
|
||||
#-----| Goto -> Block 20
|
||||
|
||||
# 2224| Block 20
|
||||
# 2218| r2218_73(glval<vector<ClassWithDestructor>>) = VariableAddress[ys] :
|
||||
# 2218| r2218_74(glval<unknown>) = FunctionAddress[~vector] :
|
||||
# 2218| v2218_75(void) = Call[~vector] : func:r2218_74, this:r2218_73
|
||||
# 2218| mu2218_76(unknown) = ^CallSideEffect : ~m?
|
||||
# 2218| v2218_77(void) = ^IndirectReadSideEffect[-1] : &:r2218_73, ~m?
|
||||
# 2218| mu2218_78(vector<ClassWithDestructor>) = ^IndirectMayWriteSideEffect[-1] : &:r2218_73
|
||||
# 2224| r2224_1(glval<vector<int>>) = VariableAddress[ys] :
|
||||
# 2224| mu2224_2(vector<int>) = Uninitialized[ys] : &:r2224_1
|
||||
# 2224| r2224_3(glval<unknown>) = FunctionAddress[vector] :
|
||||
@@ -14516,9 +14522,9 @@ ir.cpp:
|
||||
# 2224| r2224_22(iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &>) = Call[end] : func:r2224_21, this:r0_37
|
||||
#-----| v0_38(void) = ^IndirectReadSideEffect[-1] : &:r0_37, ~m?
|
||||
# 2224| mu2224_23(iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &>) = Store[(__end)] : &:r2224_18, r2224_22
|
||||
#-----| Goto -> Block 21
|
||||
#-----| Goto -> Block 19
|
||||
|
||||
# 2224| Block 21
|
||||
# 2224| Block 19
|
||||
# 2224| r2224_24(glval<iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &>>) = VariableAddress[(__begin)] :
|
||||
#-----| r0_39(glval<iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &>>) = Convert : r2224_24
|
||||
# 2224| r2224_25(glval<unknown>) = FunctionAddress[operator!=] :
|
||||
@@ -14536,19 +14542,19 @@ ir.cpp:
|
||||
# 2224| r2224_31(bool) = Call[operator!=] : func:r2224_25, this:r0_39, 0:r0_45
|
||||
#-----| v0_46(void) = ^IndirectReadSideEffect[-1] : &:r0_39, ~m?
|
||||
# 2224| v2224_32(void) = ConditionalBranch : r2224_31
|
||||
#-----| False -> Block 26
|
||||
#-----| True -> Block 23
|
||||
#-----| False -> Block 23
|
||||
#-----| True -> Block 21
|
||||
|
||||
# 2224| Block 22
|
||||
# 2224| Block 20
|
||||
# 2224| r2224_33(glval<iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &>>) = VariableAddress[(__begin)] :
|
||||
# 2224| r2224_34(glval<unknown>) = FunctionAddress[operator++] :
|
||||
# 2224| r2224_35(iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &> &) = Call[operator++] : func:r2224_34, this:r2224_33
|
||||
# 2224| v2224_36(void) = ^IndirectReadSideEffect[-1] : &:r2224_33, ~m?
|
||||
# 2224| mu2224_37(iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &>) = ^IndirectMayWriteSideEffect[-1] : &:r2224_33
|
||||
# 2224| r2224_38(glval<iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &>>) = CopyValue : r2224_35
|
||||
#-----| Goto (back edge) -> Block 21
|
||||
#-----| Goto (back edge) -> Block 19
|
||||
|
||||
# 2224| Block 23
|
||||
# 2224| Block 21
|
||||
# 2224| r2224_39(glval<int>) = VariableAddress[y] :
|
||||
# 2224| r2224_40(glval<iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &>>) = VariableAddress[(__begin)] :
|
||||
#-----| r0_47(glval<iterator<random_access_iterator_tag, int, ptrdiff_t, int *, int &>>) = Convert : r2224_40
|
||||
@@ -14562,10 +14568,10 @@ ir.cpp:
|
||||
# 2225| r2225_3(int) = Constant[1] :
|
||||
# 2225| r2225_4(bool) = CompareEQ : r2225_2, r2225_3
|
||||
# 2225| v2225_5(void) = ConditionalBranch : r2225_4
|
||||
#-----| False -> Block 22
|
||||
#-----| True -> Block 24
|
||||
#-----| False -> Block 20
|
||||
#-----| True -> Block 22
|
||||
|
||||
# 2226| Block 24
|
||||
# 2226| Block 22
|
||||
# 2226| v2226_1(void) = NoOp :
|
||||
# 2224| r2224_45(glval<vector<int>>) = VariableAddress[ys] :
|
||||
# 2224| r2224_46(glval<unknown>) = FunctionAddress[~vector] :
|
||||
@@ -14581,16 +14587,13 @@ ir.cpp:
|
||||
# 2233| mu2233_12(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2233_7
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
# 2224| Block 25
|
||||
# 2224| r2224_51(glval<vector<int>>) = VariableAddress[ys] :
|
||||
# 2224| r2224_52(glval<unknown>) = FunctionAddress[~vector] :
|
||||
# 2224| v2224_53(void) = Call[~vector] : func:r2224_52, this:r2224_51
|
||||
# 2224| mu2224_54(unknown) = ^CallSideEffect : ~m?
|
||||
# 2224| v2224_55(void) = ^IndirectReadSideEffect[-1] : &:r2224_51, ~m?
|
||||
# 2224| mu2224_56(vector<int>) = ^IndirectMayWriteSideEffect[-1] : &:r2224_51
|
||||
#-----| Goto -> Block 26
|
||||
|
||||
# 2229| Block 26
|
||||
# 2224| Block 23
|
||||
# 2224| r2224_51(glval<vector<int>>) = VariableAddress[ys] :
|
||||
# 2224| r2224_52(glval<unknown>) = FunctionAddress[~vector] :
|
||||
# 2224| v2224_53(void) = Call[~vector] : func:r2224_52, this:r2224_51
|
||||
# 2224| mu2224_54(unknown) = ^CallSideEffect : ~m?
|
||||
# 2224| v2224_55(void) = ^IndirectReadSideEffect[-1] : &:r2224_51, ~m?
|
||||
# 2224| mu2224_56(vector<int>) = ^IndirectMayWriteSideEffect[-1] : &:r2224_51
|
||||
# 2229| r2229_1(glval<vector<ClassWithDestructor>>) = VariableAddress[ys] :
|
||||
# 2229| mu2229_2(vector<ClassWithDestructor>) = Uninitialized[ys] : &:r2229_1
|
||||
# 2229| r2229_3(glval<unknown>) = FunctionAddress[vector] :
|
||||
@@ -14630,9 +14633,9 @@ ir.cpp:
|
||||
# 2229| r2229_32(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>) = Call[end] : func:r2229_31, this:r0_53
|
||||
#-----| v0_54(void) = ^IndirectReadSideEffect[-1] : &:r0_53, ~m?
|
||||
# 2229| mu2229_33(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>) = Store[(__end)] : &:r2229_28, r2229_32
|
||||
#-----| Goto -> Block 27
|
||||
#-----| Goto -> Block 24
|
||||
|
||||
# 2229| Block 27
|
||||
# 2229| Block 24
|
||||
# 2229| r2229_34(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = VariableAddress[(__begin)] :
|
||||
#-----| r0_55(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = Convert : r2229_34
|
||||
# 2229| r2229_35(glval<unknown>) = FunctionAddress[operator!=] :
|
||||
@@ -14650,10 +14653,10 @@ ir.cpp:
|
||||
# 2229| r2229_41(bool) = Call[operator!=] : func:r2229_35, this:r0_55, 0:r0_61
|
||||
#-----| v0_62(void) = ^IndirectReadSideEffect[-1] : &:r0_55, ~m?
|
||||
# 2229| v2229_42(void) = ConditionalBranch : r2229_41
|
||||
#-----| False -> Block 30
|
||||
#-----| True -> Block 28
|
||||
#-----| False -> Block 26
|
||||
#-----| True -> Block 25
|
||||
|
||||
# 2229| Block 28
|
||||
# 2229| Block 25
|
||||
# 2229| r2229_43(glval<ClassWithDestructor>) = VariableAddress[y] :
|
||||
# 2229| r2229_44(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = VariableAddress[(__begin)] :
|
||||
#-----| r0_63(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = Convert : r2229_44
|
||||
@@ -14686,37 +14689,34 @@ ir.cpp:
|
||||
# 2232| mu2232_10(unknown) = ^CallSideEffect : ~m?
|
||||
# 2232| v2232_11(void) = ^IndirectReadSideEffect[-1] : &:r2232_7, ~m?
|
||||
# 2232| mu2232_12(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2232_7
|
||||
# 2229| r2229_49(glval<ClassWithDestructor>) = VariableAddress[y] :
|
||||
# 2229| r2229_50(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
|
||||
# 2229| v2229_51(void) = Call[~ClassWithDestructor] : func:r2229_50, this:r2229_49
|
||||
# 2229| mu2229_52(unknown) = ^CallSideEffect : ~m?
|
||||
# 2229| v2229_53(void) = ^IndirectReadSideEffect[-1] : &:r2229_49, ~m?
|
||||
# 2229| mu2229_54(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2229_49
|
||||
# 2229| r2229_55(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = VariableAddress[(__begin)] :
|
||||
# 2229| r2229_56(glval<unknown>) = FunctionAddress[operator++] :
|
||||
# 2229| r2229_57(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &> &) = Call[operator++] : func:r2229_56, this:r2229_55
|
||||
# 2229| v2229_58(void) = ^IndirectReadSideEffect[-1] : &:r2229_55, ~m?
|
||||
# 2229| mu2229_59(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>) = ^IndirectMayWriteSideEffect[-1] : &:r2229_55
|
||||
# 2229| r2229_60(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = CopyValue : r2229_57
|
||||
#-----| Goto (back edge) -> Block 27
|
||||
# 2229| r2229_49(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = VariableAddress[(__begin)] :
|
||||
# 2229| r2229_50(glval<unknown>) = FunctionAddress[operator++] :
|
||||
# 2229| r2229_51(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &> &) = Call[operator++] : func:r2229_50, this:r2229_49
|
||||
# 2229| v2229_52(void) = ^IndirectReadSideEffect[-1] : &:r2229_49, ~m?
|
||||
# 2229| mu2229_53(iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>) = ^IndirectMayWriteSideEffect[-1] : &:r2229_49
|
||||
# 2229| r2229_54(glval<ClassWithDestructor>) = VariableAddress[y] :
|
||||
# 2229| r2229_55(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
|
||||
# 2229| v2229_56(void) = Call[~ClassWithDestructor] : func:r2229_55, this:r2229_54
|
||||
# 2229| mu2229_57(unknown) = ^CallSideEffect : ~m?
|
||||
# 2229| v2229_58(void) = ^IndirectReadSideEffect[-1] : &:r2229_54, ~m?
|
||||
# 2229| mu2229_59(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2229_54
|
||||
# 2229| r2229_60(glval<iterator<random_access_iterator_tag, ClassWithDestructor, ptrdiff_t, ClassWithDestructor *, ClassWithDestructor &>>) = CopyValue : r2229_51
|
||||
#-----| Goto (back edge) -> Block 24
|
||||
|
||||
# 2229| Block 29
|
||||
# 2229| r2229_61(glval<vector<ClassWithDestructor>>) = VariableAddress[ys] :
|
||||
# 2229| r2229_62(glval<unknown>) = FunctionAddress[~vector] :
|
||||
# 2229| v2229_63(void) = Call[~vector] : func:r2229_62, this:r2229_61
|
||||
# 2229| mu2229_64(unknown) = ^CallSideEffect : ~m?
|
||||
# 2229| v2229_65(void) = ^IndirectReadSideEffect[-1] : &:r2229_61, ~m?
|
||||
# 2229| mu2229_66(vector<ClassWithDestructor>) = ^IndirectMayWriteSideEffect[-1] : &:r2229_61
|
||||
#-----| Goto -> Block 30
|
||||
|
||||
# 2233| Block 30
|
||||
# 2233| v2233_13(void) = NoOp :
|
||||
# 2233| r2233_14(glval<ClassWithDestructor>) = VariableAddress[x] :
|
||||
# 2233| r2233_15(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
|
||||
# 2233| v2233_16(void) = Call[~ClassWithDestructor] : func:r2233_15, this:r2233_14
|
||||
# 2233| mu2233_17(unknown) = ^CallSideEffect : ~m?
|
||||
# 2233| v2233_18(void) = ^IndirectReadSideEffect[-1] : &:r2233_14, ~m?
|
||||
# 2233| mu2233_19(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2233_14
|
||||
# 2229| Block 26
|
||||
# 2229| r2229_61(glval<vector<ClassWithDestructor>>) = VariableAddress[ys] :
|
||||
# 2229| r2229_62(glval<unknown>) = FunctionAddress[~vector] :
|
||||
# 2229| v2229_63(void) = Call[~vector] : func:r2229_62, this:r2229_61
|
||||
# 2229| mu2229_64(unknown) = ^CallSideEffect : ~m?
|
||||
# 2229| v2229_65(void) = ^IndirectReadSideEffect[-1] : &:r2229_61, ~m?
|
||||
# 2229| mu2229_66(vector<ClassWithDestructor>) = ^IndirectMayWriteSideEffect[-1] : &:r2229_61
|
||||
# 2233| v2233_13(void) = NoOp :
|
||||
# 2233| r2233_14(glval<ClassWithDestructor>) = VariableAddress[x] :
|
||||
# 2233| r2233_15(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
|
||||
# 2233| v2233_16(void) = Call[~ClassWithDestructor] : func:r2233_15, this:r2233_14
|
||||
# 2233| mu2233_17(unknown) = ^CallSideEffect : ~m?
|
||||
# 2233| v2233_18(void) = ^IndirectReadSideEffect[-1] : &:r2233_14, ~m?
|
||||
# 2233| mu2233_19(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2233_14
|
||||
#-----| Goto -> Block 1
|
||||
|
||||
# 2235| void static_variable_with_destructor_1()
|
||||
@@ -15339,18 +15339,18 @@ ir.cpp:
|
||||
# 2309| mu2309_4(unknown) = ^CallSideEffect : ~m?
|
||||
# 2309| v2309_5(void) = ^IndirectReadSideEffect[-1] : &:r2309_1, ~m?
|
||||
# 2309| mu2309_6(String) = ^IndirectMayWriteSideEffect[-1] : &:r2309_1
|
||||
# 2307| r2307_60(glval<String>) = VariableAddress[s] :
|
||||
# 2307| r2307_61(glval<unknown>) = FunctionAddress[~String] :
|
||||
# 2307| v2307_62(void) = Call[~String] : func:r2307_61, this:r2307_60
|
||||
# 2307| mu2307_63(unknown) = ^CallSideEffect : ~m?
|
||||
# 2307| v2307_64(void) = ^IndirectReadSideEffect[-1] : &:r2307_60, ~m?
|
||||
# 2307| mu2307_65(String) = ^IndirectMayWriteSideEffect[-1] : &:r2307_60
|
||||
# 2307| r2307_66(glval<iterator<random_access_iterator_tag, String, ptrdiff_t, String *, String &>>) = VariableAddress[(__begin)] :
|
||||
# 2307| r2307_67(glval<unknown>) = FunctionAddress[operator++] :
|
||||
# 2307| r2307_68(iterator<random_access_iterator_tag, String, ptrdiff_t, String *, String &> &) = Call[operator++] : func:r2307_67, this:r2307_66
|
||||
# 2307| v2307_69(void) = ^IndirectReadSideEffect[-1] : &:r2307_66, ~m?
|
||||
# 2307| mu2307_70(iterator<random_access_iterator_tag, String, ptrdiff_t, String *, String &>) = ^IndirectMayWriteSideEffect[-1] : &:r2307_66
|
||||
# 2307| r2307_71(glval<iterator<random_access_iterator_tag, String, ptrdiff_t, String *, String &>>) = CopyValue : r2307_68
|
||||
# 2307| r2307_60(glval<iterator<random_access_iterator_tag, String, ptrdiff_t, String *, String &>>) = VariableAddress[(__begin)] :
|
||||
# 2307| r2307_61(glval<unknown>) = FunctionAddress[operator++] :
|
||||
# 2307| r2307_62(iterator<random_access_iterator_tag, String, ptrdiff_t, String *, String &> &) = Call[operator++] : func:r2307_61, this:r2307_60
|
||||
# 2307| v2307_63(void) = ^IndirectReadSideEffect[-1] : &:r2307_60, ~m?
|
||||
# 2307| mu2307_64(iterator<random_access_iterator_tag, String, ptrdiff_t, String *, String &>) = ^IndirectMayWriteSideEffect[-1] : &:r2307_60
|
||||
# 2307| r2307_65(glval<String>) = VariableAddress[s] :
|
||||
# 2307| r2307_66(glval<unknown>) = FunctionAddress[~String] :
|
||||
# 2307| v2307_67(void) = Call[~String] : func:r2307_66, this:r2307_65
|
||||
# 2307| mu2307_68(unknown) = ^CallSideEffect : ~m?
|
||||
# 2307| v2307_69(void) = ^IndirectReadSideEffect[-1] : &:r2307_65, ~m?
|
||||
# 2307| mu2307_70(String) = ^IndirectMayWriteSideEffect[-1] : &:r2307_65
|
||||
# 2307| r2307_71(glval<iterator<random_access_iterator_tag, String, ptrdiff_t, String *, String &>>) = CopyValue : r2307_62
|
||||
#-----| Goto (back edge) -> Block 4
|
||||
|
||||
# 2311| Block 6
|
||||
@@ -16244,6 +16244,315 @@ ir.cpp:
|
||||
# 2478| v2478_5(void) = AliasedUse : ~m?
|
||||
# 2478| v2478_6(void) = ExitFunction :
|
||||
|
||||
# 2484| void destructor_without_block(bool)
|
||||
# 2484| Block 0
|
||||
# 2484| v2484_1(void) = EnterFunction :
|
||||
# 2484| mu2484_2(unknown) = AliasedDefinition :
|
||||
# 2484| mu2484_3(unknown) = InitializeNonLocal :
|
||||
# 2484| r2484_4(glval<bool>) = VariableAddress[b] :
|
||||
# 2484| mu2484_5(bool) = InitializeParameter[b] : &:r2484_4
|
||||
# 2486| r2486_1(glval<bool>) = VariableAddress[b] :
|
||||
# 2486| r2486_2(bool) = Load[b] : &:r2486_1, ~m?
|
||||
# 2486| v2486_3(void) = ConditionalBranch : r2486_2
|
||||
#-----| False -> Block 2
|
||||
#-----| True -> Block 1
|
||||
|
||||
# 2487| Block 1
|
||||
# 2487| r2487_1(glval<ClassWithDestructor>) = VariableAddress[c] :
|
||||
# 2487| mu2487_2(ClassWithDestructor) = Uninitialized[c] : &:r2487_1
|
||||
# 2487| r2487_3(glval<unknown>) = FunctionAddress[ClassWithDestructor] :
|
||||
# 2487| v2487_4(void) = Call[ClassWithDestructor] : func:r2487_3, this:r2487_1
|
||||
# 2487| mu2487_5(unknown) = ^CallSideEffect : ~m?
|
||||
# 2487| mu2487_6(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2487_1
|
||||
#-----| r0_1(glval<ClassWithDestructor>) = VariableAddress[c] :
|
||||
#-----| r0_2(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
|
||||
#-----| v0_3(void) = Call[~ClassWithDestructor] : func:r0_2, this:r0_1
|
||||
#-----| mu0_4(unknown) = ^CallSideEffect : ~m?
|
||||
#-----| v0_5(void) = ^IndirectReadSideEffect[-1] : &:r0_1, ~m?
|
||||
#-----| mu0_6(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r0_1
|
||||
#-----| Goto -> Block 2
|
||||
|
||||
# 2489| Block 2
|
||||
# 2489| r2489_1(glval<bool>) = VariableAddress[b] :
|
||||
# 2489| r2489_2(bool) = Load[b] : &:r2489_1, ~m?
|
||||
# 2489| v2489_3(void) = ConditionalBranch : r2489_2
|
||||
#-----| False -> Block 4
|
||||
#-----| True -> Block 3
|
||||
|
||||
# 2490| Block 3
|
||||
# 2490| r2490_1(glval<ClassWithDestructor>) = VariableAddress[d] :
|
||||
# 2490| mu2490_2(ClassWithDestructor) = Uninitialized[d] : &:r2490_1
|
||||
# 2490| r2490_3(glval<unknown>) = FunctionAddress[ClassWithDestructor] :
|
||||
# 2490| v2490_4(void) = Call[ClassWithDestructor] : func:r2490_3, this:r2490_1
|
||||
# 2490| mu2490_5(unknown) = ^CallSideEffect : ~m?
|
||||
# 2490| mu2490_6(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2490_1
|
||||
#-----| r0_7(glval<ClassWithDestructor>) = VariableAddress[d] :
|
||||
#-----| r0_8(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
|
||||
#-----| v0_9(void) = Call[~ClassWithDestructor] : func:r0_8, this:r0_7
|
||||
#-----| mu0_10(unknown) = ^CallSideEffect : ~m?
|
||||
#-----| v0_11(void) = ^IndirectReadSideEffect[-1] : &:r0_7, ~m?
|
||||
#-----| mu0_12(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r0_7
|
||||
#-----| Goto -> Block 5
|
||||
|
||||
# 2492| Block 4
|
||||
# 2492| r2492_1(glval<ClassWithDestructor>) = VariableAddress[e] :
|
||||
# 2492| mu2492_2(ClassWithDestructor) = Uninitialized[e] : &:r2492_1
|
||||
# 2492| r2492_3(glval<unknown>) = FunctionAddress[ClassWithDestructor] :
|
||||
# 2492| v2492_4(void) = Call[ClassWithDestructor] : func:r2492_3, this:r2492_1
|
||||
# 2492| mu2492_5(unknown) = ^CallSideEffect : ~m?
|
||||
# 2492| mu2492_6(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2492_1
|
||||
#-----| r0_13(glval<ClassWithDestructor>) = VariableAddress[e] :
|
||||
#-----| r0_14(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
|
||||
#-----| v0_15(void) = Call[~ClassWithDestructor] : func:r0_14, this:r0_13
|
||||
#-----| mu0_16(unknown) = ^CallSideEffect : ~m?
|
||||
#-----| v0_17(void) = ^IndirectReadSideEffect[-1] : &:r0_13, ~m?
|
||||
#-----| mu0_18(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r0_13
|
||||
#-----| Goto -> Block 5
|
||||
|
||||
# 2494| Block 5
|
||||
# 2494| r2494_1(glval<bool>) = VariableAddress[b] :
|
||||
# 2494| r2494_2(bool) = Load[b] : &:r2494_1, ~m?
|
||||
# 2494| v2494_3(void) = ConditionalBranch : r2494_2
|
||||
#-----| False -> Block 7
|
||||
#-----| True -> Block 6
|
||||
|
||||
# 2495| Block 6
|
||||
# 2495| r2495_1(glval<ClassWithDestructor>) = VariableAddress[f] :
|
||||
# 2495| mu2495_2(ClassWithDestructor) = Uninitialized[f] : &:r2495_1
|
||||
# 2495| r2495_3(glval<unknown>) = FunctionAddress[ClassWithDestructor] :
|
||||
# 2495| v2495_4(void) = Call[ClassWithDestructor] : func:r2495_3, this:r2495_1
|
||||
# 2495| mu2495_5(unknown) = ^CallSideEffect : ~m?
|
||||
# 2495| mu2495_6(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2495_1
|
||||
#-----| r0_19(glval<ClassWithDestructor>) = VariableAddress[f] :
|
||||
#-----| r0_20(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
|
||||
#-----| v0_21(void) = Call[~ClassWithDestructor] : func:r0_20, this:r0_19
|
||||
#-----| mu0_22(unknown) = ^CallSideEffect : ~m?
|
||||
#-----| v0_23(void) = ^IndirectReadSideEffect[-1] : &:r0_19, ~m?
|
||||
#-----| mu0_24(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r0_19
|
||||
#-----| Goto (back edge) -> Block 5
|
||||
|
||||
# 2497| Block 7
|
||||
# 2497| r2497_1(glval<int>) = VariableAddress[i] :
|
||||
# 2497| r2497_2(int) = Constant[0] :
|
||||
# 2497| mu2497_3(int) = Store[i] : &:r2497_1, r2497_2
|
||||
#-----| Goto -> Block 8
|
||||
|
||||
# 2497| Block 8
|
||||
# 2497| r2497_4(glval<int>) = VariableAddress[i] :
|
||||
# 2497| r2497_5(int) = Load[i] : &:r2497_4, ~m?
|
||||
# 2497| r2497_6(int) = Constant[42] :
|
||||
# 2497| r2497_7(bool) = CompareLT : r2497_5, r2497_6
|
||||
# 2497| v2497_8(void) = ConditionalBranch : r2497_7
|
||||
#-----| False -> Block 10
|
||||
#-----| True -> Block 9
|
||||
|
||||
# 2498| Block 9
|
||||
# 2498| r2498_1(glval<ClassWithDestructor>) = VariableAddress[g] :
|
||||
# 2498| mu2498_2(ClassWithDestructor) = Uninitialized[g] : &:r2498_1
|
||||
# 2498| r2498_3(glval<unknown>) = FunctionAddress[ClassWithDestructor] :
|
||||
# 2498| v2498_4(void) = Call[ClassWithDestructor] : func:r2498_3, this:r2498_1
|
||||
# 2498| mu2498_5(unknown) = ^CallSideEffect : ~m?
|
||||
# 2498| mu2498_6(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2498_1
|
||||
#-----| r0_25(glval<ClassWithDestructor>) = VariableAddress[g] :
|
||||
#-----| r0_26(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
|
||||
#-----| v0_27(void) = Call[~ClassWithDestructor] : func:r0_26, this:r0_25
|
||||
#-----| mu0_28(unknown) = ^CallSideEffect : ~m?
|
||||
#-----| v0_29(void) = ^IndirectReadSideEffect[-1] : &:r0_25, ~m?
|
||||
#-----| mu0_30(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r0_25
|
||||
# 2497| r2497_9(glval<int>) = VariableAddress[i] :
|
||||
# 2497| r2497_10(int) = Load[i] : &:r2497_9, ~m?
|
||||
# 2497| r2497_11(int) = Constant[1] :
|
||||
# 2497| r2497_12(int) = Add : r2497_10, r2497_11
|
||||
# 2497| mu2497_13(int) = Store[i] : &:r2497_9, r2497_12
|
||||
#-----| Goto (back edge) -> Block 8
|
||||
|
||||
# 2499| Block 10
|
||||
# 2499| v2499_1(void) = NoOp :
|
||||
# 2484| v2484_6(void) = ReturnVoid :
|
||||
# 2484| v2484_7(void) = AliasedUse : ~m?
|
||||
# 2484| v2484_8(void) = ExitFunction :
|
||||
|
||||
# 2501| void destruction_in_switch_1(int)
|
||||
# 2501| Block 0
|
||||
# 2501| v2501_1(void) = EnterFunction :
|
||||
# 2501| mu2501_2(unknown) = AliasedDefinition :
|
||||
# 2501| mu2501_3(unknown) = InitializeNonLocal :
|
||||
# 2501| r2501_4(glval<int>) = VariableAddress[c] :
|
||||
# 2501| mu2501_5(int) = InitializeParameter[c] : &:r2501_4
|
||||
# 2502| r2502_1(glval<int>) = VariableAddress[c] :
|
||||
# 2502| r2502_2(int) = Load[c] : &:r2502_1, ~m?
|
||||
# 2502| v2502_3(void) = Switch : r2502_2
|
||||
#-----| Case[0] -> Block 1
|
||||
#-----| Default -> Block 3
|
||||
|
||||
# 2503| Block 1
|
||||
# 2503| v2503_1(void) = NoOp :
|
||||
# 2504| r2504_1(glval<ClassWithDestructor>) = VariableAddress[x] :
|
||||
# 2504| mu2504_2(ClassWithDestructor) = Uninitialized[x] : &:r2504_1
|
||||
# 2504| r2504_3(glval<unknown>) = FunctionAddress[ClassWithDestructor] :
|
||||
# 2504| v2504_4(void) = Call[ClassWithDestructor] : func:r2504_3, this:r2504_1
|
||||
# 2504| mu2504_5(unknown) = ^CallSideEffect : ~m?
|
||||
# 2504| mu2504_6(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2504_1
|
||||
# 2506| r2506_1(glval<ClassWithDestructor>) = VariableAddress[x] :
|
||||
# 2506| r2506_2(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
|
||||
# 2506| v2506_3(void) = Call[~ClassWithDestructor] : func:r2506_2, this:r2506_1
|
||||
# 2506| mu2506_4(unknown) = ^CallSideEffect : ~m?
|
||||
# 2506| v2506_5(void) = ^IndirectReadSideEffect[-1] : &:r2506_1, ~m?
|
||||
# 2506| mu2506_6(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2506_1
|
||||
# 2505| v2505_1(void) = NoOp :
|
||||
#-----| Goto -> Block 3
|
||||
|
||||
# 2506| Block 2
|
||||
# 2506| r2506_7(glval<ClassWithDestructor>) = VariableAddress[x] :
|
||||
# 2506| r2506_8(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
|
||||
# 2506| v2506_9(void) = Call[~ClassWithDestructor] : func:r2506_8, this:r2506_7
|
||||
# 2506| mu2506_10(unknown) = ^CallSideEffect : ~m?
|
||||
# 2506| v2506_11(void) = ^IndirectReadSideEffect[-1] : &:r2506_7, ~m?
|
||||
# 2506| mu2506_12(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2506_7
|
||||
#-----| Goto -> Block 3
|
||||
|
||||
# 2507| Block 3
|
||||
# 2507| v2507_1(void) = NoOp :
|
||||
# 2508| v2508_1(void) = NoOp :
|
||||
# 2501| v2501_6(void) = ReturnVoid :
|
||||
# 2501| v2501_7(void) = AliasedUse : ~m?
|
||||
# 2501| v2501_8(void) = ExitFunction :
|
||||
|
||||
# 2510| void destruction_in_switch_2(int)
|
||||
# 2510| Block 0
|
||||
# 2510| v2510_1(void) = EnterFunction :
|
||||
# 2510| mu2510_2(unknown) = AliasedDefinition :
|
||||
# 2510| mu2510_3(unknown) = InitializeNonLocal :
|
||||
# 2510| r2510_4(glval<int>) = VariableAddress[c] :
|
||||
# 2510| mu2510_5(int) = InitializeParameter[c] : &:r2510_4
|
||||
# 2511| r2511_1(glval<ClassWithDestructor>) = VariableAddress[y] :
|
||||
# 2511| mu2511_2(ClassWithDestructor) = Uninitialized[y] : &:r2511_1
|
||||
# 2511| r2511_3(glval<unknown>) = FunctionAddress[ClassWithDestructor] :
|
||||
# 2511| v2511_4(void) = Call[ClassWithDestructor] : func:r2511_3, this:r2511_1
|
||||
# 2511| mu2511_5(unknown) = ^CallSideEffect : ~m?
|
||||
# 2511| mu2511_6(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2511_1
|
||||
# 2511| r2511_7(glval<int>) = VariableAddress[c] :
|
||||
# 2511| r2511_8(int) = Load[c] : &:r2511_7, ~m?
|
||||
# 2511| v2511_9(void) = Switch : r2511_8
|
||||
#-----| Case[0] -> Block 1
|
||||
#-----| Default -> Block 2
|
||||
|
||||
# 2512| Block 1
|
||||
# 2512| v2512_1(void) = NoOp :
|
||||
# 2518| r2518_1(glval<ClassWithDestructor>) = VariableAddress[y] :
|
||||
# 2518| r2518_2(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
|
||||
# 2518| v2518_3(void) = Call[~ClassWithDestructor] : func:r2518_2, this:r2518_1
|
||||
# 2518| mu2518_4(unknown) = ^CallSideEffect : ~m?
|
||||
# 2518| v2518_5(void) = ^IndirectReadSideEffect[-1] : &:r2518_1, ~m?
|
||||
# 2518| mu2518_6(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2518_1
|
||||
# 2513| v2513_1(void) = NoOp :
|
||||
#-----| Goto -> Block 4
|
||||
|
||||
# 2515| Block 2
|
||||
# 2515| v2515_1(void) = NoOp :
|
||||
# 2518| r2518_7(glval<ClassWithDestructor>) = VariableAddress[y] :
|
||||
# 2518| r2518_8(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
|
||||
# 2518| v2518_9(void) = Call[~ClassWithDestructor] : func:r2518_8, this:r2518_7
|
||||
# 2518| mu2518_10(unknown) = ^CallSideEffect : ~m?
|
||||
# 2518| v2518_11(void) = ^IndirectReadSideEffect[-1] : &:r2518_7, ~m?
|
||||
# 2518| mu2518_12(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2518_7
|
||||
# 2516| v2516_1(void) = NoOp :
|
||||
#-----| Goto -> Block 4
|
||||
|
||||
# 2518| Block 3
|
||||
# 2518| r2518_13(glval<ClassWithDestructor>) = VariableAddress[y] :
|
||||
# 2518| r2518_14(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
|
||||
# 2518| v2518_15(void) = Call[~ClassWithDestructor] : func:r2518_14, this:r2518_13
|
||||
# 2518| mu2518_16(unknown) = ^CallSideEffect : ~m?
|
||||
# 2518| v2518_17(void) = ^IndirectReadSideEffect[-1] : &:r2518_13, ~m?
|
||||
# 2518| mu2518_18(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2518_13
|
||||
#-----| Goto -> Block 4
|
||||
|
||||
# 2518| Block 4
|
||||
# 2518| v2518_19(void) = NoOp :
|
||||
# 2519| v2519_1(void) = NoOp :
|
||||
# 2510| v2510_6(void) = ReturnVoid :
|
||||
# 2510| v2510_7(void) = AliasedUse : ~m?
|
||||
# 2510| v2510_8(void) = ExitFunction :
|
||||
|
||||
# 2521| void destruction_in_switch_3(int)
|
||||
# 2521| Block 0
|
||||
# 2521| v2521_1(void) = EnterFunction :
|
||||
# 2521| mu2521_2(unknown) = AliasedDefinition :
|
||||
# 2521| mu2521_3(unknown) = InitializeNonLocal :
|
||||
# 2521| r2521_4(glval<int>) = VariableAddress[c] :
|
||||
# 2521| mu2521_5(int) = InitializeParameter[c] : &:r2521_4
|
||||
# 2522| r2522_1(glval<ClassWithDestructor>) = VariableAddress[y] :
|
||||
# 2522| mu2522_2(ClassWithDestructor) = Uninitialized[y] : &:r2522_1
|
||||
# 2522| r2522_3(glval<unknown>) = FunctionAddress[ClassWithDestructor] :
|
||||
# 2522| v2522_4(void) = Call[ClassWithDestructor] : func:r2522_3, this:r2522_1
|
||||
# 2522| mu2522_5(unknown) = ^CallSideEffect : ~m?
|
||||
# 2522| mu2522_6(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2522_1
|
||||
# 2522| r2522_7(glval<int>) = VariableAddress[c] :
|
||||
# 2522| r2522_8(int) = Load[c] : &:r2522_7, ~m?
|
||||
# 2522| v2522_9(void) = Switch : r2522_8
|
||||
#-----| Case[0] -> Block 1
|
||||
#-----| Default -> Block 3
|
||||
|
||||
# 2523| Block 1
|
||||
# 2523| v2523_1(void) = NoOp :
|
||||
# 2524| r2524_1(glval<ClassWithDestructor>) = VariableAddress[x] :
|
||||
# 2524| mu2524_2(ClassWithDestructor) = Uninitialized[x] : &:r2524_1
|
||||
# 2524| r2524_3(glval<unknown>) = FunctionAddress[ClassWithDestructor] :
|
||||
# 2524| v2524_4(void) = Call[ClassWithDestructor] : func:r2524_3, this:r2524_1
|
||||
# 2524| mu2524_5(unknown) = ^CallSideEffect : ~m?
|
||||
# 2524| mu2524_6(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2524_1
|
||||
# 2526| r2526_1(glval<ClassWithDestructor>) = VariableAddress[x] :
|
||||
# 2526| r2526_2(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
|
||||
# 2526| v2526_3(void) = Call[~ClassWithDestructor] : func:r2526_2, this:r2526_1
|
||||
# 2526| mu2526_4(unknown) = ^CallSideEffect : ~m?
|
||||
# 2526| v2526_5(void) = ^IndirectReadSideEffect[-1] : &:r2526_1, ~m?
|
||||
# 2526| mu2526_6(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2526_1
|
||||
# 2530| r2530_1(glval<ClassWithDestructor>) = VariableAddress[y] :
|
||||
# 2530| r2530_2(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
|
||||
# 2530| v2530_3(void) = Call[~ClassWithDestructor] : func:r2530_2, this:r2530_1
|
||||
# 2530| mu2530_4(unknown) = ^CallSideEffect : ~m?
|
||||
# 2530| v2530_5(void) = ^IndirectReadSideEffect[-1] : &:r2530_1, ~m?
|
||||
# 2530| mu2530_6(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2530_1
|
||||
# 2525| v2525_1(void) = NoOp :
|
||||
#-----| Goto -> Block 5
|
||||
|
||||
# 2526| Block 2
|
||||
# 2526| r2526_7(glval<ClassWithDestructor>) = VariableAddress[x] :
|
||||
# 2526| r2526_8(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
|
||||
# 2526| v2526_9(void) = Call[~ClassWithDestructor] : func:r2526_8, this:r2526_7
|
||||
# 2526| mu2526_10(unknown) = ^CallSideEffect : ~m?
|
||||
# 2526| v2526_11(void) = ^IndirectReadSideEffect[-1] : &:r2526_7, ~m?
|
||||
# 2526| mu2526_12(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2526_7
|
||||
#-----| Goto -> Block 3
|
||||
|
||||
# 2527| Block 3
|
||||
# 2527| v2527_1(void) = NoOp :
|
||||
# 2530| r2530_7(glval<ClassWithDestructor>) = VariableAddress[y] :
|
||||
# 2530| r2530_8(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
|
||||
# 2530| v2530_9(void) = Call[~ClassWithDestructor] : func:r2530_8, this:r2530_7
|
||||
# 2530| mu2530_10(unknown) = ^CallSideEffect : ~m?
|
||||
# 2530| v2530_11(void) = ^IndirectReadSideEffect[-1] : &:r2530_7, ~m?
|
||||
# 2530| mu2530_12(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2530_7
|
||||
# 2528| v2528_1(void) = NoOp :
|
||||
#-----| Goto -> Block 5
|
||||
|
||||
# 2530| Block 4
|
||||
# 2530| r2530_13(glval<ClassWithDestructor>) = VariableAddress[y] :
|
||||
# 2530| r2530_14(glval<unknown>) = FunctionAddress[~ClassWithDestructor] :
|
||||
# 2530| v2530_15(void) = Call[~ClassWithDestructor] : func:r2530_14, this:r2530_13
|
||||
# 2530| mu2530_16(unknown) = ^CallSideEffect : ~m?
|
||||
# 2530| v2530_17(void) = ^IndirectReadSideEffect[-1] : &:r2530_13, ~m?
|
||||
# 2530| mu2530_18(ClassWithDestructor) = ^IndirectMayWriteSideEffect[-1] : &:r2530_13
|
||||
#-----| Goto -> Block 5
|
||||
|
||||
# 2530| Block 5
|
||||
# 2530| v2530_19(void) = NoOp :
|
||||
# 2531| v2531_1(void) = NoOp :
|
||||
# 2521| v2521_6(void) = ReturnVoid :
|
||||
# 2521| v2521_7(void) = AliasedUse : ~m?
|
||||
# 2521| v2521_8(void) = ExitFunction :
|
||||
|
||||
perf-regression.cpp:
|
||||
# 6| void Big::Big()
|
||||
# 6| Block 0
|
||||
|
||||
@@ -4,12 +4,6 @@ uniqueType
|
||||
uniqueNodeLocation
|
||||
missingLocation
|
||||
uniqueNodeToString
|
||||
| builtin.c:5:5:5:11 | (no string representation) | Node should have one toString but has 0. |
|
||||
| misc.c:227:7:227:28 | (no string representation) | Node should have one toString but has 0. |
|
||||
| static_init_templates.cpp:80:18:80:23 | (no string representation) | Node should have one toString but has 0. |
|
||||
| static_init_templates.cpp:80:18:80:23 | (no string representation) | Node should have one toString but has 0. |
|
||||
| static_init_templates.cpp:89:18:89:23 | (no string representation) | Node should have one toString but has 0. |
|
||||
| static_init_templates.cpp:89:18:89:23 | (no string representation) | Node should have one toString but has 0. |
|
||||
parameterCallable
|
||||
localFlowIsLocal
|
||||
readStepIsLocal
|
||||
|
||||
@@ -1,41 +0,0 @@
|
||||
WARNING: Type GVN has been deprecated and may be removed in future (ast_gvn.ql:4,6-9)
|
||||
| test.cpp:5:3:5:3 | x | 5:c3-c3 6:c3-c3 |
|
||||
| test.cpp:5:7:5:8 | p0 | 5:c7-c8 6:c7-c8 |
|
||||
| test.cpp:5:7:5:13 | ... + ... | 5:c7-c13 6:c7-c13 7:c7-c7 |
|
||||
| test.cpp:5:12:5:13 | p1 | 5:c12-c13 6:c12-c13 |
|
||||
| test.cpp:16:3:16:3 | x | 16:c3-c3 17:c3-c3 |
|
||||
| test.cpp:16:7:16:8 | p0 | 16:c7-c8 17:c7-c8 |
|
||||
| test.cpp:16:7:16:13 | ... + ... | 16:c7-c13 17:c7-c13 |
|
||||
| test.cpp:16:7:16:24 | ... + ... | 16:c7-c24 17:c7-c24 18:c7-c7 |
|
||||
| test.cpp:16:12:16:13 | p1 | 16:c12-c13 17:c12-c13 |
|
||||
| test.cpp:16:17:16:24 | global01 | 16:c17-c24 17:c17-c24 |
|
||||
| test.cpp:29:7:29:8 | p0 | 29:c7-c8 31:c7-c8 |
|
||||
| test.cpp:29:7:29:13 | ... + ... | 29:c7-c13 31:c7-c13 |
|
||||
| test.cpp:29:12:29:13 | p1 | 29:c12-c13 31:c12-c13 |
|
||||
| test.cpp:31:7:31:24 | ... + ... | 31:c7-c24 32:c7-c7 |
|
||||
| test.cpp:43:7:43:8 | p0 | 43:c7-c8 45:c7-c8 |
|
||||
| test.cpp:43:7:43:13 | ... + ... | 43:c7-c13 45:c7-c13 |
|
||||
| test.cpp:43:12:43:13 | p1 | 43:c12-c13 45:c12-c13 |
|
||||
| test.cpp:44:9:44:9 | 0 | 44:c9-c9 51:c25-c25 53:c18-c21 56:c39-c42 59:c17-c20 88:c12-c12 |
|
||||
| test.cpp:45:7:45:24 | ... + ... | 45:c7-c24 46:c7-c7 |
|
||||
| test.cpp:53:10:53:13 | (int)... | 53:c10-c13 56:c21-c24 |
|
||||
| test.cpp:53:10:53:13 | * ... | 53:c10-c13 56:c21-c24 |
|
||||
| test.cpp:53:11:53:13 | str | 53:c11-c13 56:c22-c24 |
|
||||
| test.cpp:53:18:53:21 | 0 | 53:c18-c21 56:c39-c42 59:c17-c20 |
|
||||
| test.cpp:56:13:56:16 | (int)... | 56:c13-c16 56:c31-c34 59:c9-c12 |
|
||||
| test.cpp:56:13:56:16 | * ... | 56:c13-c16 56:c31-c34 59:c9-c12 |
|
||||
| test.cpp:56:14:56:16 | ptr | 56:c14-c16 56:c32-c34 56:c47-c49 59:c10-c12 |
|
||||
| test.cpp:62:5:62:10 | result | 62:c5-c10 65:c10-c15 |
|
||||
| test.cpp:77:20:77:30 | (signed short)... | 77:c20-c30 79:c7-c7 |
|
||||
| test.cpp:79:11:79:14 | vals | 79:c11-c14 79:c24-c27 |
|
||||
| test.cpp:105:11:105:12 | (Base *)... | 105:c11-c12 106:c14-c35 107:c11-c12 |
|
||||
| test.cpp:105:11:105:12 | pd | 105:c11-c12 106:c33-c34 |
|
||||
| test.cpp:105:15:105:15 | b | 105:c15-c15 107:c15-c15 109:c10-c10 |
|
||||
| test.cpp:125:11:125:12 | pa | 125:c11-c12 126:c11-c12 128:c3-c4 129:c11-c12 |
|
||||
| test.cpp:125:15:125:15 | x | 125:c15-c15 126:c15-c15 128:c7-c7 |
|
||||
| test.cpp:136:11:136:18 | global_a | 136:c11-c18 137:c11-c18 139:c3-c10 |
|
||||
| test.cpp:136:21:136:21 | x | 136:c21-c21 137:c21-c21 139:c13-c13 |
|
||||
| test.cpp:144:11:144:12 | pa | 144:c11-c12 145:c11-c12 147:c3-c4 149:c11-c12 |
|
||||
| test.cpp:145:15:145:15 | y | 145:c15-c15 147:c7-c7 |
|
||||
| test.cpp:153:11:153:18 | global_a | 153:c11-c18 154:c11-c18 156:c3-c10 |
|
||||
| test.cpp:153:21:153:21 | x | 153:c21-c21 154:c21-c21 |
|
||||
@@ -1,11 +0,0 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.valuenumbering.GlobalValueNumberingImpl
|
||||
|
||||
from GVN g
|
||||
where strictcount(g.getAnExpr()) > 1
|
||||
select g,
|
||||
strictconcat(Location loc |
|
||||
loc = g.getAnExpr().getLocation()
|
||||
|
|
||||
loc.getStartLine() + ":c" + loc.getStartColumn() + "-c" + loc.getEndColumn(), " "
|
||||
)
|
||||
@@ -1,3 +0,0 @@
|
||||
WARNING: Predicate globalValueNumber has been deprecated and may be removed in future (ast_uniqueness.ql:7,13-30)
|
||||
WARNING: Predicate globalValueNumber has been deprecated and may be removed in future (ast_uniqueness.ql:8,30-47)
|
||||
WARNING: Type GVN has been deprecated and may be removed in future (ast_uniqueness.ql:8,18-21)
|
||||
@@ -1,8 +0,0 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.valuenumbering.GlobalValueNumberingImpl
|
||||
|
||||
// Every expression should have exactly one GVN.
|
||||
// So this query should have zero results.
|
||||
from Expr e
|
||||
where count(globalValueNumber(e)) != 1
|
||||
select e, concat(GVN g | g = globalValueNumber(e) | g.getKind(), ", ")
|
||||
@@ -1,130 +0,0 @@
|
||||
WARNING: Predicate globalValueNumber has been deprecated and may be removed in future (diff_ir_expr.ql:8,29-51)
|
||||
| test.cpp:5:3:5:13 | ... = ... | test.cpp:5:3:5:13 | ... = ... | AST only |
|
||||
| test.cpp:6:3:6:13 | ... = ... | test.cpp:6:3:6:13 | ... = ... | AST only |
|
||||
| test.cpp:7:3:7:7 | ... = ... | test.cpp:7:3:7:7 | ... = ... | AST only |
|
||||
| test.cpp:16:3:16:24 | ... = ... | test.cpp:16:3:16:24 | ... = ... | AST only |
|
||||
| test.cpp:17:3:17:24 | ... = ... | test.cpp:17:3:17:24 | ... = ... | AST only |
|
||||
| test.cpp:18:3:18:7 | ... = ... | test.cpp:18:3:18:7 | ... = ... | AST only |
|
||||
| test.cpp:29:3:29:3 | x | test.cpp:31:3:31:3 | x | IR only |
|
||||
| test.cpp:29:3:29:24 | ... = ... | test.cpp:29:3:29:24 | ... = ... | AST only |
|
||||
| test.cpp:30:3:30:17 | call to change_global02 | test.cpp:30:3:30:17 | call to change_global02 | AST only |
|
||||
| test.cpp:31:3:31:3 | x | test.cpp:29:3:29:3 | x | IR only |
|
||||
| test.cpp:31:3:31:24 | ... = ... | test.cpp:31:3:31:24 | ... = ... | AST only |
|
||||
| test.cpp:32:3:32:7 | ... = ... | test.cpp:32:3:32:7 | ... = ... | AST only |
|
||||
| test.cpp:43:3:43:3 | x | test.cpp:45:3:45:3 | x | IR only |
|
||||
| test.cpp:43:3:43:24 | ... = ... | test.cpp:43:3:43:24 | ... = ... | AST only |
|
||||
| test.cpp:43:7:43:24 | ... + ... | test.cpp:45:7:45:24 | ... + ... | IR only |
|
||||
| test.cpp:43:7:43:24 | ... + ... | test.cpp:46:7:46:7 | x | IR only |
|
||||
| test.cpp:43:17:43:24 | global03 | test.cpp:45:17:45:24 | global03 | IR only |
|
||||
| test.cpp:44:3:44:5 | * ... | test.cpp:44:4:44:5 | p2 | IR only |
|
||||
| test.cpp:44:3:44:9 | ... = ... | test.cpp:44:3:44:9 | ... = ... | AST only |
|
||||
| test.cpp:44:4:44:5 | p2 | test.cpp:44:3:44:5 | * ... | IR only |
|
||||
| test.cpp:44:9:44:9 | 0 | test.cpp:51:25:51:25 | 0 | AST only |
|
||||
| test.cpp:44:9:44:9 | 0 | test.cpp:53:18:53:21 | (int)... | AST only |
|
||||
| test.cpp:44:9:44:9 | 0 | test.cpp:56:39:56:42 | (int)... | AST only |
|
||||
| test.cpp:44:9:44:9 | 0 | test.cpp:59:17:59:20 | (int)... | AST only |
|
||||
| test.cpp:44:9:44:9 | 0 | test.cpp:88:12:88:12 | 0 | AST only |
|
||||
| test.cpp:45:3:45:3 | x | test.cpp:43:3:43:3 | x | IR only |
|
||||
| test.cpp:45:3:45:24 | ... = ... | test.cpp:45:3:45:24 | ... = ... | AST only |
|
||||
| test.cpp:45:7:45:24 | ... + ... | test.cpp:43:7:43:24 | ... + ... | IR only |
|
||||
| test.cpp:45:17:45:24 | global03 | test.cpp:43:17:43:24 | global03 | IR only |
|
||||
| test.cpp:46:3:46:7 | ... = ... | test.cpp:46:3:46:7 | ... = ... | AST only |
|
||||
| test.cpp:46:7:46:7 | x | test.cpp:43:7:43:24 | ... + ... | IR only |
|
||||
| test.cpp:51:25:51:25 | 0 | test.cpp:44:9:44:9 | 0 | AST only |
|
||||
| test.cpp:51:25:51:25 | 0 | test.cpp:53:18:53:21 | (int)... | AST only |
|
||||
| test.cpp:51:25:51:25 | 0 | test.cpp:56:39:56:42 | (int)... | AST only |
|
||||
| test.cpp:51:25:51:25 | 0 | test.cpp:59:17:59:20 | (int)... | AST only |
|
||||
| test.cpp:51:25:51:25 | 0 | test.cpp:88:12:88:12 | 0 | AST only |
|
||||
| test.cpp:51:25:51:25 | (unsigned int)... | test.cpp:51:25:51:25 | (unsigned int)... | AST only |
|
||||
| test.cpp:53:10:53:13 | (int)... | test.cpp:53:10:53:13 | (int)... | AST only |
|
||||
| test.cpp:53:10:53:13 | (int)... | test.cpp:56:21:56:24 | (int)... | AST only |
|
||||
| test.cpp:53:18:53:21 | (int)... | test.cpp:44:9:44:9 | 0 | AST only |
|
||||
| test.cpp:53:18:53:21 | (int)... | test.cpp:51:25:51:25 | 0 | AST only |
|
||||
| test.cpp:53:18:53:21 | (int)... | test.cpp:53:18:53:21 | (int)... | AST only |
|
||||
| test.cpp:53:18:53:21 | (int)... | test.cpp:56:39:56:42 | (int)... | AST only |
|
||||
| test.cpp:53:18:53:21 | (int)... | test.cpp:59:17:59:20 | (int)... | AST only |
|
||||
| test.cpp:53:18:53:21 | (int)... | test.cpp:88:12:88:12 | 0 | AST only |
|
||||
| test.cpp:55:5:55:15 | ... = ... | test.cpp:55:5:55:15 | ... = ... | AST only |
|
||||
| test.cpp:56:12:56:25 | (...) | test.cpp:56:12:56:25 | (...) | AST only |
|
||||
| test.cpp:56:12:56:43 | ... && ... | test.cpp:56:12:56:43 | ... && ... | AST only |
|
||||
| test.cpp:56:13:56:16 | (int)... | test.cpp:56:13:56:16 | (int)... | AST only |
|
||||
| test.cpp:56:13:56:16 | (int)... | test.cpp:56:31:56:34 | (int)... | AST only |
|
||||
| test.cpp:56:13:56:16 | (int)... | test.cpp:59:9:59:12 | (int)... | AST only |
|
||||
| test.cpp:56:21:56:24 | (int)... | test.cpp:53:10:53:13 | (int)... | AST only |
|
||||
| test.cpp:56:21:56:24 | (int)... | test.cpp:56:21:56:24 | (int)... | AST only |
|
||||
| test.cpp:56:30:56:43 | (...) | test.cpp:56:30:56:43 | (...) | AST only |
|
||||
| test.cpp:56:31:56:34 | (int)... | test.cpp:56:13:56:16 | (int)... | AST only |
|
||||
| test.cpp:56:31:56:34 | (int)... | test.cpp:56:31:56:34 | (int)... | AST only |
|
||||
| test.cpp:56:31:56:34 | (int)... | test.cpp:59:9:59:12 | (int)... | AST only |
|
||||
| test.cpp:56:39:56:42 | (int)... | test.cpp:44:9:44:9 | 0 | AST only |
|
||||
| test.cpp:56:39:56:42 | (int)... | test.cpp:51:25:51:25 | 0 | AST only |
|
||||
| test.cpp:56:39:56:42 | (int)... | test.cpp:53:18:53:21 | (int)... | AST only |
|
||||
| test.cpp:56:39:56:42 | (int)... | test.cpp:56:39:56:42 | (int)... | AST only |
|
||||
| test.cpp:56:39:56:42 | (int)... | test.cpp:59:17:59:20 | (int)... | AST only |
|
||||
| test.cpp:56:39:56:42 | (int)... | test.cpp:88:12:88:12 | 0 | AST only |
|
||||
| test.cpp:56:47:56:51 | ... ++ | test.cpp:56:47:56:51 | ... ++ | AST only |
|
||||
| test.cpp:59:9:59:12 | (int)... | test.cpp:56:13:56:16 | (int)... | AST only |
|
||||
| test.cpp:59:9:59:12 | (int)... | test.cpp:56:31:56:34 | (int)... | AST only |
|
||||
| test.cpp:59:9:59:12 | (int)... | test.cpp:59:9:59:12 | (int)... | AST only |
|
||||
| test.cpp:59:17:59:20 | (int)... | test.cpp:44:9:44:9 | 0 | AST only |
|
||||
| test.cpp:59:17:59:20 | (int)... | test.cpp:51:25:51:25 | 0 | AST only |
|
||||
| test.cpp:59:17:59:20 | (int)... | test.cpp:53:18:53:21 | (int)... | AST only |
|
||||
| test.cpp:59:17:59:20 | (int)... | test.cpp:56:39:56:42 | (int)... | AST only |
|
||||
| test.cpp:59:17:59:20 | (int)... | test.cpp:59:17:59:20 | (int)... | AST only |
|
||||
| test.cpp:59:17:59:20 | (int)... | test.cpp:88:12:88:12 | 0 | AST only |
|
||||
| test.cpp:62:5:62:12 | ... ++ | test.cpp:62:5:62:12 | ... ++ | AST only |
|
||||
| test.cpp:77:20:77:28 | call to getAValue | test.cpp:79:7:79:7 | v | IR only |
|
||||
| test.cpp:77:20:77:30 | (signed short)... | test.cpp:77:20:77:30 | (signed short)... | AST only |
|
||||
| test.cpp:77:20:77:30 | (signed short)... | test.cpp:79:7:79:7 | v | AST only |
|
||||
| test.cpp:79:7:79:7 | (int)... | test.cpp:79:7:79:7 | (int)... | AST only |
|
||||
| test.cpp:79:7:79:7 | v | test.cpp:77:20:77:28 | call to getAValue | IR only |
|
||||
| test.cpp:79:7:79:7 | v | test.cpp:77:20:77:30 | (signed short)... | AST only |
|
||||
| test.cpp:79:11:79:20 | (int)... | test.cpp:79:11:79:20 | (int)... | AST only |
|
||||
| test.cpp:79:24:79:33 | (int)... | test.cpp:79:24:79:33 | (int)... | AST only |
|
||||
| test.cpp:80:5:80:19 | ... = ... | test.cpp:80:5:80:19 | ... = ... | AST only |
|
||||
| test.cpp:80:9:80:19 | (signed short)... | test.cpp:80:9:80:19 | (signed short)... | AST only |
|
||||
| test.cpp:88:3:88:20 | ... = ... | test.cpp:88:3:88:20 | ... = ... | AST only |
|
||||
| test.cpp:88:12:88:12 | 0 | test.cpp:44:9:44:9 | 0 | AST only |
|
||||
| test.cpp:88:12:88:12 | 0 | test.cpp:51:25:51:25 | 0 | AST only |
|
||||
| test.cpp:88:12:88:12 | 0 | test.cpp:53:18:53:21 | (int)... | AST only |
|
||||
| test.cpp:88:12:88:12 | 0 | test.cpp:56:39:56:42 | (int)... | AST only |
|
||||
| test.cpp:88:12:88:12 | 0 | test.cpp:59:17:59:20 | (int)... | AST only |
|
||||
| test.cpp:88:12:88:12 | (void *)... | test.cpp:88:12:88:12 | (void *)... | AST only |
|
||||
| test.cpp:92:11:92:16 | ... = ... | test.cpp:92:15:92:16 | 10 | IR only |
|
||||
| test.cpp:92:11:92:16 | ... = ... | test.cpp:93:10:93:10 | x | IR only |
|
||||
| test.cpp:92:15:92:16 | 10 | test.cpp:92:11:92:16 | ... = ... | IR only |
|
||||
| test.cpp:92:15:92:16 | 10 | test.cpp:93:10:93:10 | x | IR only |
|
||||
| test.cpp:93:10:93:10 | x | test.cpp:92:11:92:16 | ... = ... | IR only |
|
||||
| test.cpp:93:10:93:10 | x | test.cpp:92:15:92:16 | 10 | IR only |
|
||||
| test.cpp:105:11:105:12 | (Base *)... | test.cpp:105:11:105:12 | (Base *)... | AST only |
|
||||
| test.cpp:105:11:105:12 | (Base *)... | test.cpp:106:14:106:35 | static_cast<Base *>... | AST only |
|
||||
| test.cpp:105:11:105:12 | (Base *)... | test.cpp:107:11:107:12 | pb | AST only |
|
||||
| test.cpp:105:11:105:12 | pd | test.cpp:107:11:107:12 | pb | IR only |
|
||||
| test.cpp:106:14:106:35 | static_cast<Base *>... | test.cpp:105:11:105:12 | (Base *)... | AST only |
|
||||
| test.cpp:106:14:106:35 | static_cast<Base *>... | test.cpp:106:14:106:35 | static_cast<Base *>... | AST only |
|
||||
| test.cpp:106:14:106:35 | static_cast<Base *>... | test.cpp:107:11:107:12 | pb | AST only |
|
||||
| test.cpp:106:33:106:34 | pd | test.cpp:107:11:107:12 | pb | IR only |
|
||||
| test.cpp:107:11:107:12 | pb | test.cpp:105:11:105:12 | (Base *)... | AST only |
|
||||
| test.cpp:107:11:107:12 | pb | test.cpp:105:11:105:12 | pd | IR only |
|
||||
| test.cpp:107:11:107:12 | pb | test.cpp:106:14:106:35 | static_cast<Base *>... | AST only |
|
||||
| test.cpp:107:11:107:12 | pb | test.cpp:106:33:106:34 | pd | IR only |
|
||||
| test.cpp:113:3:113:5 | a | test.cpp:115:3:115:5 | a | IR only |
|
||||
| test.cpp:115:3:115:5 | a | test.cpp:113:3:113:5 | a | IR only |
|
||||
| test.cpp:125:15:125:15 | x | test.cpp:128:7:128:7 | x | AST only |
|
||||
| test.cpp:126:15:126:15 | x | test.cpp:128:7:128:7 | x | AST only |
|
||||
| test.cpp:128:3:128:11 | ... = ... | test.cpp:128:3:128:11 | ... = ... | AST only |
|
||||
| test.cpp:128:7:128:7 | x | test.cpp:125:15:125:15 | x | AST only |
|
||||
| test.cpp:128:7:128:7 | x | test.cpp:126:15:126:15 | x | AST only |
|
||||
| test.cpp:128:11:128:11 | n | test.cpp:129:15:129:15 | x | IR only |
|
||||
| test.cpp:129:15:129:15 | x | test.cpp:128:11:128:11 | n | IR only |
|
||||
| test.cpp:136:21:136:21 | x | test.cpp:139:13:139:13 | x | AST only |
|
||||
| test.cpp:137:21:137:21 | x | test.cpp:139:13:139:13 | x | AST only |
|
||||
| test.cpp:139:3:139:24 | ... = ... | test.cpp:139:3:139:24 | ... = ... | AST only |
|
||||
| test.cpp:139:13:139:13 | x | test.cpp:136:21:136:21 | x | AST only |
|
||||
| test.cpp:139:13:139:13 | x | test.cpp:137:21:137:21 | x | AST only |
|
||||
| test.cpp:144:15:144:15 | x | test.cpp:149:15:149:15 | x | IR only |
|
||||
| test.cpp:145:15:145:15 | y | test.cpp:147:7:147:7 | y | AST only |
|
||||
| test.cpp:147:3:147:18 | ... = ... | test.cpp:147:3:147:18 | ... = ... | AST only |
|
||||
| test.cpp:147:7:147:7 | y | test.cpp:145:15:145:15 | y | AST only |
|
||||
| test.cpp:149:15:149:15 | x | test.cpp:144:15:144:15 | x | IR only |
|
||||
| test.cpp:156:3:156:17 | ... = ... | test.cpp:156:3:156:17 | ... = ... | AST only |
|
||||
@@ -1,15 +0,0 @@
|
||||
import cpp
|
||||
import semmle.code.cpp.valuenumbering.GlobalValueNumberingImpl as AST
|
||||
import semmle.code.cpp.ir.internal.ASTValueNumbering as IR
|
||||
import semmle.code.cpp.ir.IR
|
||||
|
||||
Expr ir(Expr e) { result = IR::globalValueNumber(e).getAnExpr() }
|
||||
|
||||
Expr ast(Expr e) { result = AST::globalValueNumber(e).getAnExpr() }
|
||||
|
||||
from Expr e, Expr evn, string note
|
||||
where
|
||||
evn = ast(e) and not evn = ir(e) and note = "AST only"
|
||||
or
|
||||
evn = ir(e) and not evn = ast(e) and note = "IR only"
|
||||
select e, evn, note
|
||||
@@ -12,6 +12,22 @@ edges
|
||||
| test_free.cpp:152:27:152:27 | pointer to free output argument | test_free.cpp:154:10:154:10 | a | provenance | |
|
||||
| test_free.cpp:207:10:207:10 | pointer to free output argument | test_free.cpp:209:10:209:10 | a | provenance | |
|
||||
| test_free.cpp:301:12:301:14 | pointer to g_free output argument | test_free.cpp:302:12:302:14 | buf | provenance | |
|
||||
| test_free.cpp:319:16:319:16 | pointer to operator delete output argument | test_free.cpp:322:12:322:12 | a | provenance | |
|
||||
| test_free.cpp:343:12:343:24 | *access to array [post update] [ptr] | test_free.cpp:344:12:344:24 | *access to array [ptr] | provenance | |
|
||||
| test_free.cpp:343:12:343:24 | *access to array [post update] [ptr] | test_free.cpp:345:12:345:24 | *access to array [ptr] | provenance | |
|
||||
| test_free.cpp:343:12:343:24 | *access to array [post update] [ptr] | test_free.cpp:346:12:346:24 | *access to array [ptr] | provenance | |
|
||||
| test_free.cpp:343:26:343:28 | pointer to operator delete output argument | test_free.cpp:343:12:343:24 | *access to array [post update] [ptr] | provenance | |
|
||||
| test_free.cpp:344:12:344:24 | *access to array [post update] [ptr] | test_free.cpp:345:12:345:24 | *access to array [ptr] | provenance | |
|
||||
| test_free.cpp:344:12:344:24 | *access to array [post update] [ptr] | test_free.cpp:346:12:346:24 | *access to array [ptr] | provenance | |
|
||||
| test_free.cpp:344:12:344:24 | *access to array [ptr] | test_free.cpp:344:26:344:28 | ptr | provenance | |
|
||||
| test_free.cpp:344:26:344:28 | pointer to operator delete output argument | test_free.cpp:344:12:344:24 | *access to array [post update] [ptr] | provenance | |
|
||||
| test_free.cpp:345:12:345:24 | *access to array [post update] [ptr] | test_free.cpp:346:12:346:24 | *access to array [ptr] | provenance | |
|
||||
| test_free.cpp:345:12:345:24 | *access to array [ptr] | test_free.cpp:345:26:345:28 | ptr | provenance | |
|
||||
| test_free.cpp:345:12:345:24 | *access to array [ptr] | test_free.cpp:345:26:345:28 | ptr | provenance | |
|
||||
| test_free.cpp:345:26:345:28 | pointer to operator delete output argument | test_free.cpp:345:12:345:24 | *access to array [post update] [ptr] | provenance | |
|
||||
| test_free.cpp:346:12:346:24 | *access to array [ptr] | test_free.cpp:346:26:346:28 | ptr | provenance | |
|
||||
| test_free.cpp:346:12:346:24 | *access to array [ptr] | test_free.cpp:346:26:346:28 | ptr | provenance | |
|
||||
| test_free.cpp:346:12:346:24 | *access to array [ptr] | test_free.cpp:346:26:346:28 | ptr | provenance | |
|
||||
nodes
|
||||
| test_free.cpp:11:10:11:10 | pointer to free output argument | semmle.label | pointer to free output argument |
|
||||
| test_free.cpp:14:10:14:10 | a | semmle.label | a |
|
||||
@@ -39,6 +55,26 @@ nodes
|
||||
| test_free.cpp:209:10:209:10 | a | semmle.label | a |
|
||||
| test_free.cpp:301:12:301:14 | pointer to g_free output argument | semmle.label | pointer to g_free output argument |
|
||||
| test_free.cpp:302:12:302:14 | buf | semmle.label | buf |
|
||||
| test_free.cpp:319:16:319:16 | pointer to operator delete output argument | semmle.label | pointer to operator delete output argument |
|
||||
| test_free.cpp:322:12:322:12 | a | semmle.label | a |
|
||||
| test_free.cpp:343:12:343:24 | *access to array [post update] [ptr] | semmle.label | *access to array [post update] [ptr] |
|
||||
| test_free.cpp:343:26:343:28 | pointer to operator delete output argument | semmle.label | pointer to operator delete output argument |
|
||||
| test_free.cpp:344:12:344:24 | *access to array [post update] [ptr] | semmle.label | *access to array [post update] [ptr] |
|
||||
| test_free.cpp:344:12:344:24 | *access to array [ptr] | semmle.label | *access to array [ptr] |
|
||||
| test_free.cpp:344:26:344:28 | pointer to operator delete output argument | semmle.label | pointer to operator delete output argument |
|
||||
| test_free.cpp:344:26:344:28 | ptr | semmle.label | ptr |
|
||||
| test_free.cpp:345:12:345:24 | *access to array [post update] [ptr] | semmle.label | *access to array [post update] [ptr] |
|
||||
| test_free.cpp:345:12:345:24 | *access to array [ptr] | semmle.label | *access to array [ptr] |
|
||||
| test_free.cpp:345:12:345:24 | *access to array [ptr] | semmle.label | *access to array [ptr] |
|
||||
| test_free.cpp:345:26:345:28 | pointer to operator delete output argument | semmle.label | pointer to operator delete output argument |
|
||||
| test_free.cpp:345:26:345:28 | ptr | semmle.label | ptr |
|
||||
| test_free.cpp:345:26:345:28 | ptr | semmle.label | ptr |
|
||||
| test_free.cpp:346:12:346:24 | *access to array [ptr] | semmle.label | *access to array [ptr] |
|
||||
| test_free.cpp:346:12:346:24 | *access to array [ptr] | semmle.label | *access to array [ptr] |
|
||||
| test_free.cpp:346:12:346:24 | *access to array [ptr] | semmle.label | *access to array [ptr] |
|
||||
| test_free.cpp:346:26:346:28 | ptr | semmle.label | ptr |
|
||||
| test_free.cpp:346:26:346:28 | ptr | semmle.label | ptr |
|
||||
| test_free.cpp:346:26:346:28 | ptr | semmle.label | ptr |
|
||||
subpaths
|
||||
#select
|
||||
| test_free.cpp:14:10:14:10 | a | test_free.cpp:11:10:11:10 | pointer to free output argument | test_free.cpp:14:10:14:10 | a | Memory pointed to by $@ may already have been freed by $@. | test_free.cpp:14:10:14:10 | a | a | test_free.cpp:11:5:11:8 | call to free | call to free |
|
||||
@@ -54,3 +90,10 @@ subpaths
|
||||
| test_free.cpp:154:10:154:10 | a | test_free.cpp:152:27:152:27 | pointer to free output argument | test_free.cpp:154:10:154:10 | a | Memory pointed to by $@ may already have been freed by $@. | test_free.cpp:154:10:154:10 | a | a | test_free.cpp:152:22:152:25 | call to free | call to free |
|
||||
| test_free.cpp:209:10:209:10 | a | test_free.cpp:207:10:207:10 | pointer to free output argument | test_free.cpp:209:10:209:10 | a | Memory pointed to by $@ may already have been freed by $@. | test_free.cpp:209:10:209:10 | a | a | test_free.cpp:207:5:207:8 | call to free | call to free |
|
||||
| test_free.cpp:302:12:302:14 | buf | test_free.cpp:301:12:301:14 | pointer to g_free output argument | test_free.cpp:302:12:302:14 | buf | Memory pointed to by $@ may already have been freed by $@. | test_free.cpp:302:12:302:14 | buf | buf | test_free.cpp:301:5:301:10 | call to g_free | call to g_free |
|
||||
| test_free.cpp:322:12:322:12 | a | test_free.cpp:319:16:319:16 | pointer to operator delete output argument | test_free.cpp:322:12:322:12 | a | Memory pointed to by $@ may already have been freed by $@. | test_free.cpp:322:12:322:12 | a | a | test_free.cpp:319:9:319:16 | delete | delete |
|
||||
| test_free.cpp:344:26:344:28 | ptr | test_free.cpp:343:26:343:28 | pointer to operator delete output argument | test_free.cpp:344:26:344:28 | ptr | Memory pointed to by $@ may already have been freed by $@. | test_free.cpp:344:26:344:28 | ptr | ptr | test_free.cpp:343:5:343:28 | delete | delete |
|
||||
| test_free.cpp:345:26:345:28 | ptr | test_free.cpp:343:26:343:28 | pointer to operator delete output argument | test_free.cpp:345:26:345:28 | ptr | Memory pointed to by $@ may already have been freed by $@. | test_free.cpp:345:26:345:28 | ptr | ptr | test_free.cpp:343:5:343:28 | delete | delete |
|
||||
| test_free.cpp:345:26:345:28 | ptr | test_free.cpp:344:26:344:28 | pointer to operator delete output argument | test_free.cpp:345:26:345:28 | ptr | Memory pointed to by $@ may already have been freed by $@. | test_free.cpp:345:26:345:28 | ptr | ptr | test_free.cpp:344:5:344:28 | delete | delete |
|
||||
| test_free.cpp:346:26:346:28 | ptr | test_free.cpp:343:26:343:28 | pointer to operator delete output argument | test_free.cpp:346:26:346:28 | ptr | Memory pointed to by $@ may already have been freed by $@. | test_free.cpp:346:26:346:28 | ptr | ptr | test_free.cpp:343:5:343:28 | delete | delete |
|
||||
| test_free.cpp:346:26:346:28 | ptr | test_free.cpp:344:26:344:28 | pointer to operator delete output argument | test_free.cpp:346:26:346:28 | ptr | Memory pointed to by $@ may already have been freed by $@. | test_free.cpp:346:26:346:28 | ptr | ptr | test_free.cpp:344:5:344:28 | delete | delete |
|
||||
| test_free.cpp:346:26:346:28 | ptr | test_free.cpp:345:26:345:28 | pointer to operator delete output argument | test_free.cpp:346:26:346:28 | ptr | Memory pointed to by $@ may already have been freed by $@. | test_free.cpp:346:26:346:28 | ptr | ptr | test_free.cpp:345:5:345:28 | delete | delete |
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
| test.cpp:128:15:128:16 | v4 |
|
||||
| test.cpp:185:10:185:12 | cpy |
|
||||
| test.cpp:199:10:199:12 | cpy |
|
||||
| test.cpp:208:7:208:7 | a |
|
||||
| test.cpp:214:7:214:7 | a |
|
||||
| test_free.cpp:11:10:11:10 | a |
|
||||
| test_free.cpp:14:10:14:10 | a |
|
||||
| test_free.cpp:16:10:16:10 | a |
|
||||
@@ -104,6 +106,15 @@
|
||||
| test_free.cpp:293:8:293:10 | buf |
|
||||
| test_free.cpp:301:12:301:14 | buf |
|
||||
| test_free.cpp:302:12:302:14 | buf |
|
||||
| test_free.cpp:313:16:313:16 | a |
|
||||
| test_free.cpp:319:16:319:16 | a |
|
||||
| test_free.cpp:322:12:322:12 | a |
|
||||
| test_free.cpp:331:12:331:12 | a |
|
||||
| test_free.cpp:335:12:335:12 | a |
|
||||
| test_free.cpp:343:26:343:28 | ptr |
|
||||
| test_free.cpp:344:26:344:28 | ptr |
|
||||
| test_free.cpp:345:26:345:28 | ptr |
|
||||
| test_free.cpp:346:26:346:28 | ptr |
|
||||
| virtual.cpp:18:10:18:10 | a |
|
||||
| virtual.cpp:19:10:19:10 | c |
|
||||
| virtual.cpp:38:10:38:10 | b |
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
edges
|
||||
| test.cpp:208:7:208:7 | pointer to free output argument | test.cpp:209:2:209:2 | a | provenance | |
|
||||
| test.cpp:214:7:214:7 | pointer to free output argument | test.cpp:215:2:215:2 | a | provenance | |
|
||||
| test_free.cpp:11:10:11:10 | pointer to free output argument | test_free.cpp:12:5:12:5 | a | provenance | |
|
||||
| test_free.cpp:11:10:11:10 | pointer to free output argument | test_free.cpp:13:5:13:6 | * ... | provenance | |
|
||||
| test_free.cpp:42:27:42:27 | pointer to free output argument | test_free.cpp:45:5:45:5 | a | provenance | |
|
||||
@@ -25,7 +27,16 @@ edges
|
||||
| test_free.cpp:294:3:294:3 | *s [post update] [buf] | test_free.cpp:295:12:295:12 | *s [buf] | provenance | |
|
||||
| test_free.cpp:294:3:294:13 | ... = ... | test_free.cpp:294:3:294:3 | *s [post update] [buf] | provenance | |
|
||||
| test_free.cpp:295:12:295:12 | *s [buf] | test_free.cpp:295:14:295:16 | buf | provenance | |
|
||||
| test_free.cpp:313:16:313:16 | pointer to operator delete output argument | test_free.cpp:324:5:324:6 | * ... | provenance | |
|
||||
| test_free.cpp:319:16:319:16 | pointer to operator delete output argument | test_free.cpp:321:5:321:6 | * ... | provenance | |
|
||||
| test_free.cpp:319:16:319:16 | pointer to operator delete output argument | test_free.cpp:324:5:324:6 | * ... | provenance | |
|
||||
| test_free.cpp:322:12:322:12 | pointer to operator delete output argument | test_free.cpp:324:5:324:6 | * ... | provenance | |
|
||||
| test_free.cpp:331:12:331:12 | pointer to operator delete output argument | test_free.cpp:332:5:332:6 | * ... | provenance | |
|
||||
nodes
|
||||
| test.cpp:208:7:208:7 | pointer to free output argument | semmle.label | pointer to free output argument |
|
||||
| test.cpp:209:2:209:2 | a | semmle.label | a |
|
||||
| test.cpp:214:7:214:7 | pointer to free output argument | semmle.label | pointer to free output argument |
|
||||
| test.cpp:215:2:215:2 | a | semmle.label | a |
|
||||
| test_free.cpp:11:10:11:10 | pointer to free output argument | semmle.label | pointer to free output argument |
|
||||
| test_free.cpp:12:5:12:5 | a | semmle.label | a |
|
||||
| test_free.cpp:13:5:13:6 | * ... | semmle.label | * ... |
|
||||
@@ -66,8 +77,19 @@ nodes
|
||||
| test_free.cpp:294:3:294:13 | ... = ... | semmle.label | ... = ... |
|
||||
| test_free.cpp:295:12:295:12 | *s [buf] | semmle.label | *s [buf] |
|
||||
| test_free.cpp:295:14:295:16 | buf | semmle.label | buf |
|
||||
| test_free.cpp:313:16:313:16 | pointer to operator delete output argument | semmle.label | pointer to operator delete output argument |
|
||||
| test_free.cpp:319:16:319:16 | pointer to operator delete output argument | semmle.label | pointer to operator delete output argument |
|
||||
| test_free.cpp:321:5:321:6 | * ... | semmle.label | * ... |
|
||||
| test_free.cpp:322:12:322:12 | pointer to operator delete output argument | semmle.label | pointer to operator delete output argument |
|
||||
| test_free.cpp:324:5:324:6 | * ... | semmle.label | * ... |
|
||||
| test_free.cpp:324:5:324:6 | * ... | semmle.label | * ... |
|
||||
| test_free.cpp:324:5:324:6 | * ... | semmle.label | * ... |
|
||||
| test_free.cpp:331:12:331:12 | pointer to operator delete output argument | semmle.label | pointer to operator delete output argument |
|
||||
| test_free.cpp:332:5:332:6 | * ... | semmle.label | * ... |
|
||||
subpaths
|
||||
#select
|
||||
| test.cpp:209:2:209:2 | a | test.cpp:208:7:208:7 | pointer to free output argument | test.cpp:209:2:209:2 | a | Memory may have been previously freed by $@. | test.cpp:208:2:208:5 | call to free | call to free |
|
||||
| test.cpp:215:2:215:2 | a | test.cpp:214:7:214:7 | pointer to free output argument | test.cpp:215:2:215:2 | a | Memory may have been previously freed by $@. | test.cpp:214:2:214:5 | call to free | call to free |
|
||||
| test_free.cpp:12:5:12:5 | a | test_free.cpp:11:10:11:10 | pointer to free output argument | test_free.cpp:12:5:12:5 | a | Memory may have been previously freed by $@. | test_free.cpp:11:5:11:8 | call to free | call to free |
|
||||
| test_free.cpp:13:5:13:6 | * ... | test_free.cpp:11:10:11:10 | pointer to free output argument | test_free.cpp:13:5:13:6 | * ... | Memory may have been previously freed by $@. | test_free.cpp:11:5:11:8 | call to free | call to free |
|
||||
| test_free.cpp:45:5:45:5 | a | test_free.cpp:42:27:42:27 | pointer to free output argument | test_free.cpp:45:5:45:5 | a | Memory may have been previously freed by $@. | test_free.cpp:42:22:42:25 | call to free | call to free |
|
||||
@@ -84,3 +106,8 @@ subpaths
|
||||
| test_free.cpp:278:15:278:17 | buf | test_free.cpp:277:8:277:13 | pointer to free output argument | test_free.cpp:278:15:278:17 | buf | Memory may have been previously freed by $@. | test_free.cpp:277:3:277:6 | call to free | call to free |
|
||||
| test_free.cpp:283:14:283:16 | buf | test_free.cpp:282:8:282:12 | pointer to free output argument | test_free.cpp:283:14:283:16 | buf | Memory may have been previously freed by $@. | test_free.cpp:282:3:282:6 | call to free | call to free |
|
||||
| test_free.cpp:295:14:295:16 | buf | test_free.cpp:293:8:293:10 | pointer to free output argument | test_free.cpp:295:14:295:16 | buf | Memory may have been previously freed by $@. | test_free.cpp:293:3:293:6 | call to free | call to free |
|
||||
| test_free.cpp:321:5:321:6 | * ... | test_free.cpp:319:16:319:16 | pointer to operator delete output argument | test_free.cpp:321:5:321:6 | * ... | Memory may have been previously freed by $@. | test_free.cpp:319:9:319:16 | delete | delete |
|
||||
| test_free.cpp:324:5:324:6 | * ... | test_free.cpp:313:16:313:16 | pointer to operator delete output argument | test_free.cpp:324:5:324:6 | * ... | Memory may have been previously freed by $@. | test_free.cpp:313:9:313:16 | delete | delete |
|
||||
| test_free.cpp:324:5:324:6 | * ... | test_free.cpp:319:16:319:16 | pointer to operator delete output argument | test_free.cpp:324:5:324:6 | * ... | Memory may have been previously freed by $@. | test_free.cpp:319:9:319:16 | delete | delete |
|
||||
| test_free.cpp:324:5:324:6 | * ... | test_free.cpp:322:12:322:12 | pointer to operator delete output argument | test_free.cpp:324:5:324:6 | * ... | Memory may have been previously freed by $@. | test_free.cpp:322:5:322:12 | delete | delete |
|
||||
| test_free.cpp:332:5:332:6 | * ... | test_free.cpp:331:12:331:12 | pointer to operator delete output argument | test_free.cpp:332:5:332:6 | * ... | Memory may have been previously freed by $@. | test_free.cpp:331:5:331:12 | delete | delete |
|
||||
|
||||
@@ -114,7 +114,7 @@ int main()
|
||||
mc2->method2();
|
||||
delete mc2;
|
||||
}
|
||||
|
||||
|
||||
{
|
||||
void *v1 = malloc(100);
|
||||
int *i2 = (int *)malloc(100);
|
||||
@@ -198,3 +198,19 @@ void test_strndupa_dealloc() {
|
||||
char *cpy = strndupa(msg, 4);
|
||||
free(cpy); // BAD [NOT DETECTED]
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
void test_reassignment() {
|
||||
char *a = (char *)malloc(128);
|
||||
char *b = (char *)malloc(128);
|
||||
|
||||
free(a);
|
||||
a[0] = 0; // BAD
|
||||
|
||||
a = b;
|
||||
a[0] = 0; // GOOD
|
||||
|
||||
free(a);
|
||||
a[0] = 0; // BAD
|
||||
}
|
||||
|
||||
@@ -264,9 +264,9 @@ void test_ref_delete(int *&p) {
|
||||
}
|
||||
|
||||
void test_free_assign() {
|
||||
void *a = malloc(10);
|
||||
void *a = malloc(10);
|
||||
void *b;
|
||||
free(b = a); // GOOD
|
||||
free(b = a); // GOOD
|
||||
}
|
||||
|
||||
struct MyStruct {
|
||||
@@ -300,4 +300,48 @@ void g_free (void*);
|
||||
void test_g_free(char* buf) {
|
||||
g_free(buf);
|
||||
g_free(buf); // BAD
|
||||
}
|
||||
}
|
||||
|
||||
// inspired by real world FPs
|
||||
|
||||
void test_goto() {
|
||||
int *a = (int *)malloc(sizeof(int));
|
||||
|
||||
*a = 1; // GOOD
|
||||
if (condition())
|
||||
{
|
||||
delete a;
|
||||
goto after;
|
||||
}
|
||||
*a = 1; // GOOD
|
||||
if (condition())
|
||||
{
|
||||
delete a;
|
||||
}
|
||||
*a = 1; // BAD (use after free)
|
||||
delete a; // BAD (double free)
|
||||
after:
|
||||
*a = 1; // BAD (use after free)
|
||||
}
|
||||
|
||||
void test_reassign() {
|
||||
int *a = (int *)malloc(sizeof(int));
|
||||
|
||||
*a = 1; // GOOD
|
||||
delete a;
|
||||
*a = 1; // BAD (use after free)
|
||||
a = (int *)malloc(sizeof(int));
|
||||
*a = 1; // GOOD
|
||||
delete a;
|
||||
}
|
||||
|
||||
struct PtrContainer {
|
||||
int *ptr;
|
||||
};
|
||||
|
||||
void test_array(PtrContainer *containers) {
|
||||
delete containers[0].ptr; // GOOD
|
||||
delete containers[1].ptr; // GOOD [FALSE POSITIVE]
|
||||
delete containers[2].ptr; // GOOD [FALSE POSITIVE]
|
||||
delete containers[2].ptr; // BAD (double free)
|
||||
}
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
edges
|
||||
| test.c:8:27:8:30 | **argv | test.c:9:23:9:29 | *access to array | provenance | |
|
||||
| test.c:8:27:8:30 | **argv | test.c:31:22:31:28 | *access to array | provenance | |
|
||||
| test.c:8:27:8:30 | **argv | test.c:57:10:57:16 | *access to array | provenance | |
|
||||
| test.c:8:27:8:30 | **argv | test.c:69:14:69:20 | *access to array | provenance | |
|
||||
| test.c:9:23:9:29 | *access to array | test.c:17:11:17:18 | *fileName | provenance | TaintFunction |
|
||||
| test.c:31:22:31:28 | *access to array | test.c:32:11:32:18 | *fileName | provenance | |
|
||||
| test.c:37:17:37:24 | scanf output argument | test.c:38:11:38:18 | *fileName | provenance | |
|
||||
| test.c:43:17:43:24 | scanf output argument | test.c:44:11:44:18 | *fileName | provenance | |
|
||||
| test.c:48:21:48:26 | *call to getenv | test.c:48:21:48:26 | *call to getenv | provenance | |
|
||||
| test.c:48:21:48:26 | *call to getenv | test.c:49:11:49:17 | *tainted | provenance | |
|
||||
| test.c:54:21:54:26 | *call to getenv | test.c:55:11:55:16 | *buffer | provenance | TaintFunction |
|
||||
| test.c:74:13:74:18 | read output argument | test.c:76:11:76:16 | *buffer | provenance | |
|
||||
| test.c:75:13:75:18 | read output argument | test.c:76:11:76:16 | *buffer | provenance | |
|
||||
nodes
|
||||
| test.c:8:27:8:30 | **argv | semmle.label | **argv |
|
||||
| test.c:9:23:9:29 | *access to array | semmle.label | *access to array |
|
||||
@@ -16,11 +21,23 @@ nodes
|
||||
| test.c:38:11:38:18 | *fileName | semmle.label | *fileName |
|
||||
| test.c:43:17:43:24 | scanf output argument | semmle.label | scanf output argument |
|
||||
| test.c:44:11:44:18 | *fileName | semmle.label | *fileName |
|
||||
| test.c:57:10:57:16 | *access to array | semmle.label | *access to array |
|
||||
| test.c:48:21:48:26 | *call to getenv | semmle.label | *call to getenv |
|
||||
| test.c:48:21:48:26 | *call to getenv | semmle.label | *call to getenv |
|
||||
| test.c:49:11:49:17 | *tainted | semmle.label | *tainted |
|
||||
| test.c:54:21:54:26 | *call to getenv | semmle.label | *call to getenv |
|
||||
| test.c:55:11:55:16 | *buffer | semmle.label | *buffer |
|
||||
| test.c:69:14:69:20 | *access to array | semmle.label | *access to array |
|
||||
| test.c:74:13:74:18 | read output argument | semmle.label | read output argument |
|
||||
| test.c:75:13:75:18 | read output argument | semmle.label | read output argument |
|
||||
| test.c:76:11:76:16 | *buffer | semmle.label | *buffer |
|
||||
subpaths
|
||||
#select
|
||||
| test.c:17:11:17:18 | fileName | test.c:8:27:8:30 | **argv | test.c:17:11:17:18 | *fileName | This argument to a file access function is derived from $@ and then passed to fopen(filename). | test.c:8:27:8:30 | **argv | user input (a command-line argument) |
|
||||
| test.c:32:11:32:18 | fileName | test.c:8:27:8:30 | **argv | test.c:32:11:32:18 | *fileName | This argument to a file access function is derived from $@ and then passed to fopen(filename). | test.c:8:27:8:30 | **argv | user input (a command-line argument) |
|
||||
| test.c:38:11:38:18 | fileName | test.c:37:17:37:24 | scanf output argument | test.c:38:11:38:18 | *fileName | This argument to a file access function is derived from $@ and then passed to fopen(filename). | test.c:37:17:37:24 | scanf output argument | user input (value read by scanf) |
|
||||
| test.c:44:11:44:18 | fileName | test.c:43:17:43:24 | scanf output argument | test.c:44:11:44:18 | *fileName | This argument to a file access function is derived from $@ and then passed to fopen(filename). | test.c:43:17:43:24 | scanf output argument | user input (value read by scanf) |
|
||||
| test.c:57:10:57:16 | access to array | test.c:8:27:8:30 | **argv | test.c:57:10:57:16 | *access to array | This argument to a file access function is derived from $@ and then passed to read(fileName), which calls fopen(filename). | test.c:8:27:8:30 | **argv | user input (a command-line argument) |
|
||||
| test.c:49:11:49:17 | tainted | test.c:48:21:48:26 | *call to getenv | test.c:49:11:49:17 | *tainted | This argument to a file access function is derived from $@ and then passed to fopen(filename). | test.c:48:21:48:26 | *call to getenv | user input (an environment variable) |
|
||||
| test.c:55:11:55:16 | buffer | test.c:54:21:54:26 | *call to getenv | test.c:55:11:55:16 | *buffer | This argument to a file access function is derived from $@ and then passed to fopen(filename). | test.c:54:21:54:26 | *call to getenv | user input (an environment variable) |
|
||||
| test.c:69:14:69:20 | access to array | test.c:8:27:8:30 | **argv | test.c:69:14:69:20 | *access to array | This argument to a file access function is derived from $@ and then passed to readFile(fileName), which calls fopen(filename). | test.c:8:27:8:30 | **argv | user input (a command-line argument) |
|
||||
| test.c:76:11:76:16 | buffer | test.c:74:13:74:18 | read output argument | test.c:76:11:76:16 | *buffer | This argument to a file access function is derived from $@ and then passed to fopen(filename). | test.c:74:13:74:18 | read output argument | user input (buffer read by read) |
|
||||
| test.c:76:11:76:16 | buffer | test.c:75:13:75:18 | read output argument | test.c:76:11:76:16 | *buffer | This argument to a file access function is derived from $@ and then passed to fopen(filename). | test.c:75:13:75:18 | read output argument | user input (buffer read by read) |
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
typedef struct {} FILE;
|
||||
#define FILENAME_MAX 1000
|
||||
typedef unsigned long size_t;
|
||||
typedef signed long ssize_t;
|
||||
|
||||
FILE *fopen(const char *filename, const char *mode);
|
||||
int sprintf(char *s, const char *format, ...);
|
||||
@@ -15,3 +16,4 @@ int scanf(const char *format, ...);
|
||||
void *malloc(size_t size);
|
||||
double strtod(const char *ptr, char **endptr);
|
||||
char *getenv(const char *name);
|
||||
ssize_t read(int fd, void *buffer, size_t count);
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
|
||||
int main(int argc, char** argv) {
|
||||
char *userAndFile = argv[2];
|
||||
|
||||
|
||||
{
|
||||
char fileBuffer[FILENAME_MAX] = "/home/";
|
||||
char *fileName = fileBuffer;
|
||||
@@ -44,6 +44,18 @@ int main(int argc, char** argv) {
|
||||
fopen(fileName, "wb+"); // BAD
|
||||
}
|
||||
|
||||
{
|
||||
char *tainted = getenv("A_STRING");
|
||||
fopen(tainted, "wb+"); // BAD
|
||||
}
|
||||
|
||||
{
|
||||
char buffer[1024];
|
||||
strncpy(buffer, getenv("A_STRING"), 1024);
|
||||
fopen(buffer, "wb+"); // BAD
|
||||
fopen(buffer, "wb+"); // (we don't want a duplicate result here)
|
||||
}
|
||||
|
||||
{
|
||||
char *aNumber = getenv("A_NUMBER");
|
||||
double number = strtod(aNumber, 0);
|
||||
@@ -53,11 +65,18 @@ int main(int argc, char** argv) {
|
||||
}
|
||||
|
||||
{
|
||||
void read(const char *fileName);
|
||||
read(argv[1]); // BAD
|
||||
void readFile(const char *fileName);
|
||||
readFile(argv[1]); // BAD
|
||||
}
|
||||
|
||||
{
|
||||
char buffer[1024];
|
||||
read(0, buffer, 1024);
|
||||
read(0, buffer, 1024);
|
||||
fopen(buffer, "wb+"); // BAD [duplicated with both sources]
|
||||
}
|
||||
}
|
||||
|
||||
void read(char *fileName) {
|
||||
void readFile(char *fileName) {
|
||||
fopen(fileName, "wb+");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
| test.cpp:680:30:680:30 | call to operator[] | This object is destroyed at the end of the full-expression. |
|
||||
| test.cpp:683:31:683:32 | call to at | This object is destroyed at the end of the full-expression. |
|
||||
| test.cpp:689:46:689:58 | pointer to ~vector output argument | This object is destroyed at the end of the full-expression. |
|
||||
| test.cpp:702:27:702:27 | call to operator[] | This object is destroyed at the end of the full-expression. |
|
||||
| test.cpp:727:23:727:23 | call to operator[] | This object is destroyed at the end of the full-expression. |
|
||||
| test.cpp:735:23:735:23 | call to operator[] | This object is destroyed at the end of the full-expression. |
|
||||
@@ -0,0 +1 @@
|
||||
Security/CWE/CWE-416/IteratorToExpiredContainer.ql
|
||||
@@ -1,13 +1,13 @@
|
||||
| test.cpp:165:34:165:38 | call to c_str | The underlying string object is destroyed after the call to 'c_str' returns. |
|
||||
| test.cpp:166:39:166:43 | call to c_str | The underlying string object is destroyed after the call to 'c_str' returns. |
|
||||
| test.cpp:167:44:167:48 | call to c_str | The underlying string object is destroyed after the call to 'c_str' returns. |
|
||||
| test.cpp:169:29:169:33 | call to c_str | The underlying string object is destroyed after the call to 'c_str' returns. |
|
||||
| test.cpp:178:37:178:41 | call to c_str | The underlying string object is destroyed after the call to 'c_str' returns. |
|
||||
| test.cpp:181:39:181:43 | call to c_str | The underlying string object is destroyed after the call to 'c_str' returns. |
|
||||
| test.cpp:183:37:183:41 | call to c_str | The underlying string object is destroyed after the call to 'c_str' returns. |
|
||||
| test.cpp:187:34:187:37 | call to data | The underlying string object is destroyed after the call to 'data' returns. |
|
||||
| test.cpp:188:39:188:42 | call to data | The underlying string object is destroyed after the call to 'data' returns. |
|
||||
| test.cpp:189:44:189:47 | call to data | The underlying string object is destroyed after the call to 'data' returns. |
|
||||
| test.cpp:191:29:191:32 | call to data | The underlying string object is destroyed after the call to 'data' returns. |
|
||||
| test.cpp:193:47:193:51 | call to c_str | The underlying string object is destroyed after the call to 'c_str' returns. |
|
||||
| test.cpp:195:31:195:35 | call to c_str | The underlying string object is destroyed after the call to 'c_str' returns. |
|
||||
| test.cpp:165:34:165:38 | call to c_str | The underlying temporary string object is destroyed after the call to 'c_str' returns. |
|
||||
| test.cpp:166:39:166:43 | call to c_str | The underlying temporary string object is destroyed after the call to 'c_str' returns. |
|
||||
| test.cpp:167:44:167:48 | call to c_str | The underlying temporary string object is destroyed after the call to 'c_str' returns. |
|
||||
| test.cpp:169:29:169:33 | call to c_str | The underlying temporary string object is destroyed after the call to 'c_str' returns. |
|
||||
| test.cpp:178:37:178:41 | call to c_str | The underlying temporary string object is destroyed after the call to 'c_str' returns. |
|
||||
| test.cpp:181:39:181:43 | call to c_str | The underlying temporary string object is destroyed after the call to 'c_str' returns. |
|
||||
| test.cpp:183:37:183:41 | call to c_str | The underlying temporary string object is destroyed after the call to 'c_str' returns. |
|
||||
| test.cpp:187:34:187:37 | call to data | The underlying temporary string object is destroyed after the call to 'data' returns. |
|
||||
| test.cpp:188:39:188:42 | call to data | The underlying temporary string object is destroyed after the call to 'data' returns. |
|
||||
| test.cpp:189:44:189:47 | call to data | The underlying temporary string object is destroyed after the call to 'data' returns. |
|
||||
| test.cpp:191:29:191:32 | call to data | The underlying temporary string object is destroyed after the call to 'data' returns. |
|
||||
| test.cpp:193:47:193:51 | call to c_str | The underlying temporary string object is destroyed after the call to 'c_str' returns. |
|
||||
| test.cpp:195:31:195:35 | call to c_str | The underlying temporary string object is destroyed after the call to 'c_str' returns. |
|
||||
|
||||
@@ -41,99 +41,99 @@
|
||||
| BoxedInt::~BoxedInt | true | 481 | 483 | |
|
||||
| BoxedInt::~BoxedInt | true | 483 | 222 | |
|
||||
| BoxedInt::~BoxedInt | true | 485 | 474 | |
|
||||
| NonTrivial::NonTrivial | false | 543 | 543 | NonTrivial |
|
||||
| NonTrivial::operator= | false | 549 | 549 | operator= |
|
||||
| NonTrivial::~NonTrivial | false | 557 | 557 | ~NonTrivial |
|
||||
| NonTrivial::~NonTrivial | false | 563 | 563 | return ... |
|
||||
| NonTrivial::~NonTrivial | false | 565 | 565 | { ... } |
|
||||
| NonTrivial::~NonTrivial | true | 563 | 557 | |
|
||||
| NonTrivial::~NonTrivial | true | 565 | 563 | |
|
||||
| NonTrivial::NonTrivial | false | 544 | 544 | NonTrivial |
|
||||
| NonTrivial::operator= | false | 550 | 550 | operator= |
|
||||
| NonTrivial::~NonTrivial | false | 558 | 558 | ~NonTrivial |
|
||||
| NonTrivial::~NonTrivial | false | 564 | 564 | return ... |
|
||||
| NonTrivial::~NonTrivial | false | 566 | 566 | { ... } |
|
||||
| NonTrivial::~NonTrivial | true | 564 | 558 | |
|
||||
| NonTrivial::~NonTrivial | true | 566 | 564 | |
|
||||
| __va_list_tag::operator= | false | 66 | 66 | operator= |
|
||||
| __va_list_tag::operator= | false | 72 | 72 | operator= |
|
||||
| early_return | false | 799 | 799 | early_return |
|
||||
| early_return | false | 807 | 807 | declaration |
|
||||
| early_return | false | 812 | 812 | if (...) ... |
|
||||
| early_return | false | 814 | 814 | x |
|
||||
| early_return | false | 816 | 816 | (bool)... |
|
||||
| early_return | false | 820 | 820 | declaration |
|
||||
| early_return | false | 822 | 822 | return ... |
|
||||
| early_return | false | 824 | 824 | { ... } |
|
||||
| early_return | false | 826 | 826 | declaration |
|
||||
| early_return | false | 831 | 831 | return ... |
|
||||
| early_return | false | 833 | 833 | { ... } |
|
||||
| early_return | false | 835 | 835 | inner |
|
||||
| early_return | false | 837 | 837 | call to inner.~NonTrivial |
|
||||
| early_return | false | 838 | 838 | before |
|
||||
| early_return | false | 840 | 840 | call to before.~NonTrivial |
|
||||
| early_return | false | 841 | 841 | inner |
|
||||
| early_return | false | 842 | 842 | call to inner.~NonTrivial |
|
||||
| early_return | false | 843 | 843 | before |
|
||||
| early_return | false | 844 | 844 | call to before.~NonTrivial |
|
||||
| early_return | false | 845 | 845 | after |
|
||||
| early_return | false | 846 | 846 | call to after.~NonTrivial |
|
||||
| early_return | true | 807 | 812 | |
|
||||
| early_return | true | 812 | 814 | |
|
||||
| early_return | true | 814 | 824 | T |
|
||||
| early_return | true | 814 | 826 | F |
|
||||
| early_return | true | 820 | 822 | |
|
||||
| early_return | true | 822 | 841 | |
|
||||
| early_return | true | 824 | 820 | |
|
||||
| early_return | true | 826 | 831 | |
|
||||
| early_return | true | 831 | 845 | |
|
||||
| early_return | true | 833 | 807 | |
|
||||
| early_return | true | 835 | 837 | |
|
||||
| early_return | true | 837 | 826 | |
|
||||
| early_return | true | 838 | 840 | |
|
||||
| early_return | true | 840 | 799 | |
|
||||
| early_return | true | 841 | 842 | |
|
||||
| early_return | true | 842 | 838 | |
|
||||
| early_return | true | 843 | 844 | |
|
||||
| early_return | true | 844 | 799 | |
|
||||
| early_return | true | 845 | 846 | |
|
||||
| early_return | true | 846 | 843 | |
|
||||
| early_throw | false | 749 | 749 | early_throw |
|
||||
| early_throw | false | 757 | 757 | declaration |
|
||||
| early_throw | false | 762 | 762 | if (...) ... |
|
||||
| early_throw | false | 764 | 764 | x |
|
||||
| early_throw | false | 766 | 766 | (bool)... |
|
||||
| early_throw | false | 770 | 770 | declaration |
|
||||
| early_throw | false | 772 | 772 | ExprStmt |
|
||||
| early_throw | false | 774 | 774 | re-throw exception |
|
||||
| early_throw | false | 776 | 776 | { ... } |
|
||||
| early_throw | false | 778 | 778 | declaration |
|
||||
| early_throw | false | 783 | 783 | return ... |
|
||||
| early_throw | false | 785 | 785 | { ... } |
|
||||
| early_throw | false | 787 | 787 | inner |
|
||||
| early_throw | false | 789 | 789 | call to inner.~NonTrivial |
|
||||
| early_throw | false | 790 | 790 | before |
|
||||
| early_throw | false | 792 | 792 | call to before.~NonTrivial |
|
||||
| early_throw | false | 793 | 793 | inner |
|
||||
| early_throw | false | 794 | 794 | call to inner.~NonTrivial |
|
||||
| early_throw | false | 795 | 795 | before |
|
||||
| early_throw | false | 796 | 796 | call to before.~NonTrivial |
|
||||
| early_throw | false | 797 | 797 | after |
|
||||
| early_throw | false | 798 | 798 | call to after.~NonTrivial |
|
||||
| early_throw | true | 757 | 762 | |
|
||||
| early_throw | true | 762 | 764 | |
|
||||
| early_throw | true | 764 | 776 | T |
|
||||
| early_throw | true | 764 | 778 | F |
|
||||
| early_throw | true | 770 | 772 | |
|
||||
| early_throw | true | 772 | 774 | |
|
||||
| early_throw | true | 774 | 793 | |
|
||||
| early_throw | true | 776 | 770 | |
|
||||
| early_throw | true | 778 | 783 | |
|
||||
| early_throw | true | 783 | 797 | |
|
||||
| early_throw | true | 785 | 757 | |
|
||||
| early_throw | true | 787 | 789 | |
|
||||
| early_throw | true | 789 | 778 | |
|
||||
| early_throw | true | 790 | 792 | |
|
||||
| early_throw | true | 792 | 749 | |
|
||||
| early_throw | true | 793 | 794 | |
|
||||
| early_throw | true | 794 | 790 | |
|
||||
| early_throw | true | 795 | 796 | |
|
||||
| early_throw | true | 796 | 749 | |
|
||||
| early_throw | true | 797 | 798 | |
|
||||
| early_throw | true | 798 | 795 | |
|
||||
| early_return | false | 800 | 800 | early_return |
|
||||
| early_return | false | 808 | 808 | declaration |
|
||||
| early_return | false | 813 | 813 | if (...) ... |
|
||||
| early_return | false | 815 | 815 | x |
|
||||
| early_return | false | 817 | 817 | (bool)... |
|
||||
| early_return | false | 821 | 821 | declaration |
|
||||
| early_return | false | 823 | 823 | return ... |
|
||||
| early_return | false | 825 | 825 | { ... } |
|
||||
| early_return | false | 827 | 827 | declaration |
|
||||
| early_return | false | 832 | 832 | return ... |
|
||||
| early_return | false | 834 | 834 | { ... } |
|
||||
| early_return | false | 836 | 836 | before |
|
||||
| early_return | false | 838 | 838 | call to before.~NonTrivial |
|
||||
| early_return | false | 839 | 839 | inner |
|
||||
| early_return | false | 841 | 841 | call to inner.~NonTrivial |
|
||||
| early_return | false | 842 | 842 | inner |
|
||||
| early_return | false | 843 | 843 | call to inner.~NonTrivial |
|
||||
| early_return | false | 844 | 844 | before |
|
||||
| early_return | false | 845 | 845 | call to before.~NonTrivial |
|
||||
| early_return | false | 846 | 846 | after |
|
||||
| early_return | false | 847 | 847 | call to after.~NonTrivial |
|
||||
| early_return | true | 808 | 813 | |
|
||||
| early_return | true | 813 | 815 | |
|
||||
| early_return | true | 815 | 825 | T |
|
||||
| early_return | true | 815 | 827 | F |
|
||||
| early_return | true | 821 | 823 | |
|
||||
| early_return | true | 823 | 839 | |
|
||||
| early_return | true | 825 | 821 | |
|
||||
| early_return | true | 827 | 832 | |
|
||||
| early_return | true | 832 | 846 | |
|
||||
| early_return | true | 834 | 808 | |
|
||||
| early_return | true | 836 | 838 | |
|
||||
| early_return | true | 838 | 800 | |
|
||||
| early_return | true | 839 | 841 | |
|
||||
| early_return | true | 841 | 836 | |
|
||||
| early_return | true | 842 | 843 | |
|
||||
| early_return | true | 843 | 827 | |
|
||||
| early_return | true | 844 | 845 | |
|
||||
| early_return | true | 845 | 800 | |
|
||||
| early_return | true | 846 | 847 | |
|
||||
| early_return | true | 847 | 844 | |
|
||||
| early_throw | false | 750 | 750 | early_throw |
|
||||
| early_throw | false | 758 | 758 | declaration |
|
||||
| early_throw | false | 763 | 763 | if (...) ... |
|
||||
| early_throw | false | 765 | 765 | x |
|
||||
| early_throw | false | 767 | 767 | (bool)... |
|
||||
| early_throw | false | 771 | 771 | declaration |
|
||||
| early_throw | false | 773 | 773 | ExprStmt |
|
||||
| early_throw | false | 775 | 775 | re-throw exception |
|
||||
| early_throw | false | 777 | 777 | { ... } |
|
||||
| early_throw | false | 779 | 779 | declaration |
|
||||
| early_throw | false | 784 | 784 | return ... |
|
||||
| early_throw | false | 786 | 786 | { ... } |
|
||||
| early_throw | false | 788 | 788 | before |
|
||||
| early_throw | false | 790 | 790 | call to before.~NonTrivial |
|
||||
| early_throw | false | 791 | 791 | inner |
|
||||
| early_throw | false | 793 | 793 | call to inner.~NonTrivial |
|
||||
| early_throw | false | 794 | 794 | inner |
|
||||
| early_throw | false | 795 | 795 | call to inner.~NonTrivial |
|
||||
| early_throw | false | 796 | 796 | before |
|
||||
| early_throw | false | 797 | 797 | call to before.~NonTrivial |
|
||||
| early_throw | false | 798 | 798 | after |
|
||||
| early_throw | false | 799 | 799 | call to after.~NonTrivial |
|
||||
| early_throw | true | 758 | 763 | |
|
||||
| early_throw | true | 763 | 765 | |
|
||||
| early_throw | true | 765 | 777 | T |
|
||||
| early_throw | true | 765 | 779 | F |
|
||||
| early_throw | true | 771 | 773 | |
|
||||
| early_throw | true | 773 | 775 | |
|
||||
| early_throw | true | 775 | 791 | |
|
||||
| early_throw | true | 777 | 771 | |
|
||||
| early_throw | true | 779 | 784 | |
|
||||
| early_throw | true | 784 | 798 | |
|
||||
| early_throw | true | 786 | 758 | |
|
||||
| early_throw | true | 788 | 790 | |
|
||||
| early_throw | true | 790 | 750 | |
|
||||
| early_throw | true | 791 | 793 | |
|
||||
| early_throw | true | 793 | 788 | |
|
||||
| early_throw | true | 794 | 795 | |
|
||||
| early_throw | true | 795 | 779 | |
|
||||
| early_throw | true | 796 | 797 | |
|
||||
| early_throw | true | 797 | 750 | |
|
||||
| early_throw | true | 798 | 799 | |
|
||||
| early_throw | true | 799 | 796 | |
|
||||
| for_decl_bind | false | 153 | 153 | for_decl_bind |
|
||||
| for_decl_bind | false | 161 | 161 | for(...;...;...) ... |
|
||||
| for_decl_bind | false | 164 | 164 | call to BoxedInt |
|
||||
@@ -194,108 +194,108 @@
|
||||
| for_decl_bind | true | 225 | 219 | |
|
||||
| for_decl_bind | true | 226 | 227 | |
|
||||
| for_decl_bind | true | 227 | 182 | |
|
||||
| for_loop_scope | false | 698 | 698 | for_loop_scope |
|
||||
| for_loop_scope | false | 706 | 706 | declaration |
|
||||
| for_loop_scope | false | 711 | 711 | for(...;...;...) ... |
|
||||
| for_loop_scope | false | 716 | 716 | x |
|
||||
| for_loop_scope | false | 720 | 720 | 10 |
|
||||
| for_loop_scope | false | 721 | 721 | ... < ... |
|
||||
| for_loop_scope | false | 726 | 726 | declaration |
|
||||
| for_loop_scope | false | 728 | 728 | { ... } |
|
||||
| for_loop_scope | false | 730 | 730 | declaration |
|
||||
| for_loop_scope | false | 732 | 732 | x |
|
||||
| for_loop_scope | false | 734 | 734 | ++ ... |
|
||||
| for_loop_scope | false | 736 | 736 | return ... |
|
||||
| for_loop_scope | false | 738 | 738 | { ... } |
|
||||
| for_loop_scope | false | 740 | 740 | for_scope |
|
||||
| for_loop_scope | false | 742 | 742 | call to for_scope.~NonTrivial |
|
||||
| for_loop_scope | false | 743 | 743 | inner_scope |
|
||||
| for_loop_scope | false | 745 | 745 | call to inner_scope.~NonTrivial |
|
||||
| for_loop_scope | false | 746 | 746 | outer_scope |
|
||||
| for_loop_scope | false | 748 | 748 | call to outer_scope.~NonTrivial |
|
||||
| for_loop_scope | true | 706 | 711 | |
|
||||
| for_loop_scope | true | 711 | 730 | |
|
||||
| for_loop_scope | true | 716 | 720 | |
|
||||
| for_loop_scope | true | 720 | 721 | |
|
||||
| for_loop_scope | true | 721 | 728 | T |
|
||||
| for_loop_scope | true | 721 | 740 | F |
|
||||
| for_loop_scope | true | 726 | 743 | |
|
||||
| for_loop_scope | true | 728 | 726 | |
|
||||
| for_loop_scope | true | 730 | 716 | |
|
||||
| for_loop_scope | true | 732 | 734 | |
|
||||
| for_loop_scope | true | 734 | 716 | |
|
||||
| for_loop_scope | true | 736 | 746 | |
|
||||
| for_loop_scope | true | 738 | 706 | |
|
||||
| for_loop_scope | true | 740 | 742 | |
|
||||
| for_loop_scope | true | 742 | 736 | |
|
||||
| for_loop_scope | true | 743 | 745 | |
|
||||
| for_loop_scope | true | 745 | 732 | |
|
||||
| for_loop_scope | true | 746 | 748 | |
|
||||
| for_loop_scope | true | 748 | 698 | |
|
||||
| gotos | false | 608 | 608 | gotos |
|
||||
| gotos | false | 616 | 616 | declaration |
|
||||
| gotos | false | 621 | 621 | if (...) ... |
|
||||
| gotos | false | 623 | 623 | x |
|
||||
| gotos | false | 625 | 625 | (bool)... |
|
||||
| gotos | false | 626 | 626 | goto ... |
|
||||
| gotos | false | 628 | 628 | x |
|
||||
| gotos | false | 630 | 630 | ++ ... |
|
||||
| gotos | false | 632 | 632 | initializer for y |
|
||||
| gotos | false | 643 | 643 | declaration |
|
||||
| gotos | false | 645 | 645 | label ...: |
|
||||
| gotos | false | 647 | 647 | declaration |
|
||||
| gotos | false | 649 | 649 | if (...) ... |
|
||||
| gotos | false | 651 | 651 | y |
|
||||
| gotos | false | 653 | 653 | (bool)... |
|
||||
| gotos | false | 654 | 654 | goto ... |
|
||||
| gotos | false | 656 | 656 | declaration |
|
||||
| gotos | false | 658 | 658 | { ... } |
|
||||
| gotos | false | 660 | 660 | label ...: |
|
||||
| gotos | false | 662 | 662 | ExprStmt |
|
||||
| gotos | false | 664 | 664 | x |
|
||||
| gotos | false | 666 | 666 | -- ... |
|
||||
| gotos | false | 668 | 668 | return ... |
|
||||
| gotos | false | 670 | 670 | { ... } |
|
||||
| gotos | false | 672 | 672 | nt2 |
|
||||
| gotos | false | 674 | 674 | call to nt2.~NonTrivial |
|
||||
| gotos | false | 675 | 675 | nt3 |
|
||||
| gotos | false | 676 | 676 | call to nt3.~NonTrivial |
|
||||
| gotos | false | 677 | 677 | nt2 |
|
||||
| gotos | false | 678 | 678 | call to nt2.~NonTrivial |
|
||||
| gotos | false | 679 | 679 | nt1 |
|
||||
| gotos | false | 681 | 681 | call to nt1.~NonTrivial |
|
||||
| gotos | true | 616 | 621 | |
|
||||
| gotos | true | 621 | 623 | |
|
||||
| gotos | true | 623 | 626 | T |
|
||||
| gotos | true | 623 | 658 | F |
|
||||
| gotos | true | 626 | 645 | |
|
||||
| gotos | true | 628 | 630 | |
|
||||
| gotos | true | 630 | 645 | |
|
||||
| gotos | true | 632 | 628 | |
|
||||
| gotos | true | 643 | 632 | |
|
||||
| gotos | true | 643 | 645 | |
|
||||
| gotos | true | 645 | 647 | |
|
||||
| gotos | true | 647 | 649 | |
|
||||
| gotos | true | 649 | 651 | |
|
||||
| gotos | true | 651 | 654 | T |
|
||||
| gotos | true | 651 | 656 | F |
|
||||
| gotos | true | 654 | 677 | |
|
||||
| gotos | true | 656 | 675 | |
|
||||
| gotos | true | 658 | 643 | |
|
||||
| gotos | true | 660 | 662 | |
|
||||
| gotos | true | 662 | 664 | |
|
||||
| gotos | true | 664 | 666 | |
|
||||
| gotos | true | 666 | 668 | |
|
||||
| gotos | true | 668 | 679 | |
|
||||
| gotos | true | 670 | 616 | |
|
||||
| gotos | true | 672 | 674 | |
|
||||
| gotos | true | 674 | 660 | |
|
||||
| gotos | true | 675 | 676 | |
|
||||
| gotos | true | 676 | 672 | |
|
||||
| gotos | true | 677 | 678 | |
|
||||
| gotos | true | 678 | 660 | |
|
||||
| gotos | true | 679 | 681 | |
|
||||
| gotos | true | 681 | 608 | |
|
||||
| for_loop_scope | false | 699 | 699 | for_loop_scope |
|
||||
| for_loop_scope | false | 707 | 707 | declaration |
|
||||
| for_loop_scope | false | 712 | 712 | for(...;...;...) ... |
|
||||
| for_loop_scope | false | 717 | 717 | x |
|
||||
| for_loop_scope | false | 721 | 721 | 10 |
|
||||
| for_loop_scope | false | 722 | 722 | ... < ... |
|
||||
| for_loop_scope | false | 727 | 727 | declaration |
|
||||
| for_loop_scope | false | 729 | 729 | { ... } |
|
||||
| for_loop_scope | false | 731 | 731 | declaration |
|
||||
| for_loop_scope | false | 733 | 733 | x |
|
||||
| for_loop_scope | false | 735 | 735 | ++ ... |
|
||||
| for_loop_scope | false | 737 | 737 | return ... |
|
||||
| for_loop_scope | false | 739 | 739 | { ... } |
|
||||
| for_loop_scope | false | 741 | 741 | for_scope |
|
||||
| for_loop_scope | false | 743 | 743 | call to for_scope.~NonTrivial |
|
||||
| for_loop_scope | false | 744 | 744 | inner_scope |
|
||||
| for_loop_scope | false | 746 | 746 | call to inner_scope.~NonTrivial |
|
||||
| for_loop_scope | false | 747 | 747 | outer_scope |
|
||||
| for_loop_scope | false | 749 | 749 | call to outer_scope.~NonTrivial |
|
||||
| for_loop_scope | true | 707 | 712 | |
|
||||
| for_loop_scope | true | 712 | 731 | |
|
||||
| for_loop_scope | true | 717 | 721 | |
|
||||
| for_loop_scope | true | 721 | 722 | |
|
||||
| for_loop_scope | true | 722 | 729 | T |
|
||||
| for_loop_scope | true | 722 | 741 | F |
|
||||
| for_loop_scope | true | 727 | 744 | |
|
||||
| for_loop_scope | true | 729 | 727 | |
|
||||
| for_loop_scope | true | 731 | 717 | |
|
||||
| for_loop_scope | true | 733 | 735 | |
|
||||
| for_loop_scope | true | 735 | 717 | |
|
||||
| for_loop_scope | true | 737 | 747 | |
|
||||
| for_loop_scope | true | 739 | 707 | |
|
||||
| for_loop_scope | true | 741 | 743 | |
|
||||
| for_loop_scope | true | 743 | 737 | |
|
||||
| for_loop_scope | true | 744 | 746 | |
|
||||
| for_loop_scope | true | 746 | 733 | |
|
||||
| for_loop_scope | true | 747 | 749 | |
|
||||
| for_loop_scope | true | 749 | 699 | |
|
||||
| gotos | false | 609 | 609 | gotos |
|
||||
| gotos | false | 617 | 617 | declaration |
|
||||
| gotos | false | 622 | 622 | if (...) ... |
|
||||
| gotos | false | 624 | 624 | x |
|
||||
| gotos | false | 626 | 626 | (bool)... |
|
||||
| gotos | false | 627 | 627 | goto ... |
|
||||
| gotos | false | 629 | 629 | x |
|
||||
| gotos | false | 631 | 631 | ++ ... |
|
||||
| gotos | false | 633 | 633 | initializer for y |
|
||||
| gotos | false | 644 | 644 | declaration |
|
||||
| gotos | false | 646 | 646 | label ...: |
|
||||
| gotos | false | 648 | 648 | declaration |
|
||||
| gotos | false | 650 | 650 | if (...) ... |
|
||||
| gotos | false | 652 | 652 | y |
|
||||
| gotos | false | 654 | 654 | (bool)... |
|
||||
| gotos | false | 655 | 655 | goto ... |
|
||||
| gotos | false | 657 | 657 | declaration |
|
||||
| gotos | false | 659 | 659 | { ... } |
|
||||
| gotos | false | 661 | 661 | label ...: |
|
||||
| gotos | false | 663 | 663 | ExprStmt |
|
||||
| gotos | false | 665 | 665 | x |
|
||||
| gotos | false | 667 | 667 | -- ... |
|
||||
| gotos | false | 669 | 669 | return ... |
|
||||
| gotos | false | 671 | 671 | { ... } |
|
||||
| gotos | false | 673 | 673 | nt2 |
|
||||
| gotos | false | 675 | 675 | call to nt2.~NonTrivial |
|
||||
| gotos | false | 676 | 676 | nt2 |
|
||||
| gotos | false | 677 | 677 | call to nt2.~NonTrivial |
|
||||
| gotos | false | 678 | 678 | nt3 |
|
||||
| gotos | false | 679 | 679 | call to nt3.~NonTrivial |
|
||||
| gotos | false | 680 | 680 | nt1 |
|
||||
| gotos | false | 682 | 682 | call to nt1.~NonTrivial |
|
||||
| gotos | true | 617 | 622 | |
|
||||
| gotos | true | 622 | 624 | |
|
||||
| gotos | true | 624 | 627 | T |
|
||||
| gotos | true | 624 | 659 | F |
|
||||
| gotos | true | 627 | 646 | |
|
||||
| gotos | true | 629 | 631 | |
|
||||
| gotos | true | 631 | 646 | |
|
||||
| gotos | true | 633 | 629 | |
|
||||
| gotos | true | 644 | 633 | |
|
||||
| gotos | true | 644 | 646 | |
|
||||
| gotos | true | 646 | 648 | |
|
||||
| gotos | true | 648 | 650 | |
|
||||
| gotos | true | 650 | 652 | |
|
||||
| gotos | true | 652 | 655 | T |
|
||||
| gotos | true | 652 | 657 | F |
|
||||
| gotos | true | 655 | 673 | |
|
||||
| gotos | true | 657 | 678 | |
|
||||
| gotos | true | 659 | 644 | |
|
||||
| gotos | true | 661 | 663 | |
|
||||
| gotos | true | 663 | 665 | |
|
||||
| gotos | true | 665 | 667 | |
|
||||
| gotos | true | 667 | 669 | |
|
||||
| gotos | true | 669 | 680 | |
|
||||
| gotos | true | 671 | 617 | |
|
||||
| gotos | true | 673 | 675 | |
|
||||
| gotos | true | 675 | 661 | |
|
||||
| gotos | true | 676 | 677 | |
|
||||
| gotos | true | 677 | 661 | |
|
||||
| gotos | true | 678 | 679 | |
|
||||
| gotos | true | 679 | 676 | |
|
||||
| gotos | true | 680 | 682 | |
|
||||
| gotos | true | 682 | 609 | |
|
||||
| if_decl_bind | false | 375 | 375 | if_decl_bind |
|
||||
| if_decl_bind | false | 383 | 383 | if (...) ... |
|
||||
| if_decl_bind | false | 386 | 386 | call to operator int |
|
||||
@@ -350,45 +350,45 @@
|
||||
| if_decl_bind | true | 435 | 383 | |
|
||||
| if_decl_bind | true | 437 | 439 | |
|
||||
| if_decl_bind | true | 439 | 424 | |
|
||||
| never_destructs | false | 682 | 682 | never_destructs |
|
||||
| never_destructs | false | 687 | 687 | declaration |
|
||||
| never_destructs | false | 692 | 692 | label ...: |
|
||||
| never_destructs | false | 694 | 694 | goto ... |
|
||||
| never_destructs | false | 696 | 696 | { ... } |
|
||||
| never_destructs | true | 687 | 692 | |
|
||||
| never_destructs | true | 692 | 694 | |
|
||||
| never_destructs | true | 694 | 692 | |
|
||||
| never_destructs | true | 696 | 687 | |
|
||||
| never_destructs | false | 683 | 683 | never_destructs |
|
||||
| never_destructs | false | 688 | 688 | declaration |
|
||||
| never_destructs | false | 693 | 693 | label ...: |
|
||||
| never_destructs | false | 695 | 695 | goto ... |
|
||||
| never_destructs | false | 697 | 697 | { ... } |
|
||||
| never_destructs | true | 688 | 693 | |
|
||||
| never_destructs | true | 693 | 695 | |
|
||||
| never_destructs | true | 695 | 693 | |
|
||||
| never_destructs | true | 697 | 688 | |
|
||||
| operator delete | false | 476 | 476 | operator delete |
|
||||
| operator new | false | 499 | 499 | operator new |
|
||||
| simple | false | 871 | 871 | simple |
|
||||
| simple | false | 876 | 876 | declaration |
|
||||
| simple | false | 881 | 881 | return ... |
|
||||
| simple | false | 883 | 883 | { ... } |
|
||||
| simple | false | 885 | 885 | nt |
|
||||
| simple | false | 887 | 887 | call to nt.~NonTrivial |
|
||||
| simple | true | 876 | 881 | |
|
||||
| simple | true | 881 | 885 | |
|
||||
| simple | true | 883 | 876 | |
|
||||
| simple | true | 885 | 887 | |
|
||||
| simple | true | 887 | 871 | |
|
||||
| simple2 | false | 847 | 847 | simple2 |
|
||||
| simple2 | false | 852 | 852 | declaration |
|
||||
| simple2 | false | 857 | 857 | declaration |
|
||||
| simple2 | false | 862 | 862 | return ... |
|
||||
| simple2 | false | 864 | 864 | { ... } |
|
||||
| simple2 | false | 866 | 866 | one |
|
||||
| simple2 | false | 868 | 868 | call to one.~NonTrivial |
|
||||
| simple2 | false | 869 | 869 | two |
|
||||
| simple2 | false | 870 | 870 | call to two.~NonTrivial |
|
||||
| simple2 | true | 852 | 857 | |
|
||||
| simple2 | true | 857 | 862 | |
|
||||
| simple2 | true | 862 | 869 | |
|
||||
| simple2 | true | 864 | 852 | |
|
||||
| simple2 | true | 866 | 868 | |
|
||||
| simple2 | true | 868 | 847 | |
|
||||
| simple2 | true | 869 | 870 | |
|
||||
| simple2 | true | 870 | 866 | |
|
||||
| simple | false | 872 | 872 | simple |
|
||||
| simple | false | 877 | 877 | declaration |
|
||||
| simple | false | 882 | 882 | return ... |
|
||||
| simple | false | 884 | 884 | { ... } |
|
||||
| simple | false | 886 | 886 | nt |
|
||||
| simple | false | 888 | 888 | call to nt.~NonTrivial |
|
||||
| simple | true | 877 | 882 | |
|
||||
| simple | true | 882 | 886 | |
|
||||
| simple | true | 884 | 877 | |
|
||||
| simple | true | 886 | 888 | |
|
||||
| simple | true | 888 | 872 | |
|
||||
| simple2 | false | 848 | 848 | simple2 |
|
||||
| simple2 | false | 853 | 853 | declaration |
|
||||
| simple2 | false | 858 | 858 | declaration |
|
||||
| simple2 | false | 863 | 863 | return ... |
|
||||
| simple2 | false | 865 | 865 | { ... } |
|
||||
| simple2 | false | 867 | 867 | one |
|
||||
| simple2 | false | 869 | 869 | call to one.~NonTrivial |
|
||||
| simple2 | false | 870 | 870 | two |
|
||||
| simple2 | false | 871 | 871 | call to two.~NonTrivial |
|
||||
| simple2 | true | 853 | 858 | |
|
||||
| simple2 | true | 858 | 863 | |
|
||||
| simple2 | true | 863 | 870 | |
|
||||
| simple2 | true | 865 | 853 | |
|
||||
| simple2 | true | 867 | 869 | |
|
||||
| simple2 | true | 869 | 848 | |
|
||||
| simple2 | true | 870 | 871 | |
|
||||
| simple2 | true | 871 | 867 | |
|
||||
| switch_decl_bind | false | 276 | 276 | switch_decl_bind |
|
||||
| switch_decl_bind | false | 284 | 284 | switch (...) ... |
|
||||
| switch_decl_bind | false | 287 | 287 | call to operator int |
|
||||
@@ -444,21 +444,21 @@
|
||||
| switch_decl_bind | true | 310 | 313 | |
|
||||
| switch_decl_bind | true | 313 | 315 | |
|
||||
| switch_decl_bind | true | 315 | 317 | |
|
||||
| switch_decl_bind | true | 317 | 371 | |
|
||||
| switch_decl_bind | true | 317 | 368 | |
|
||||
| switch_decl_bind | true | 319 | 324 | |
|
||||
| switch_decl_bind | true | 324 | 326 | |
|
||||
| switch_decl_bind | true | 326 | 328 | |
|
||||
| switch_decl_bind | true | 328 | 330 | |
|
||||
| switch_decl_bind | true | 330 | 332 | |
|
||||
| switch_decl_bind | true | 332 | 334 | |
|
||||
| switch_decl_bind | true | 334 | 373 | |
|
||||
| switch_decl_bind | true | 334 | 371 | |
|
||||
| switch_decl_bind | true | 336 | 338 | |
|
||||
| switch_decl_bind | true | 338 | 340 | |
|
||||
| switch_decl_bind | true | 340 | 342 | |
|
||||
| switch_decl_bind | true | 342 | 344 | |
|
||||
| switch_decl_bind | true | 344 | 348 | |
|
||||
| switch_decl_bind | true | 348 | 349 | |
|
||||
| switch_decl_bind | true | 349 | 368 | |
|
||||
| switch_decl_bind | true | 349 | 373 | |
|
||||
| switch_decl_bind | true | 351 | 300 | |
|
||||
| switch_decl_bind | true | 351 | 319 | |
|
||||
| switch_decl_bind | true | 351 | 336 | |
|
||||
@@ -501,10 +501,11 @@
|
||||
| while_decl_bind | true | 241 | 251 | |
|
||||
| while_decl_bind | true | 243 | 241 | |
|
||||
| while_decl_bind | true | 251 | 259 | T |
|
||||
| while_decl_bind | true | 251 | 271 | F |
|
||||
| while_decl_bind | true | 251 | 274 | F |
|
||||
| while_decl_bind | true | 253 | 255 | |
|
||||
| while_decl_bind | true | 255 | 257 | |
|
||||
| while_decl_bind | true | 257 | 274 | |
|
||||
| while_decl_bind | true | 257 | 243 | |
|
||||
| while_decl_bind | true | 257 | 271 | |
|
||||
| while_decl_bind | true | 259 | 253 | |
|
||||
| while_decl_bind | true | 261 | 263 | |
|
||||
| while_decl_bind | true | 263 | 265 | |
|
||||
@@ -512,6 +513,5 @@
|
||||
| while_decl_bind | true | 267 | 228 | |
|
||||
| while_decl_bind | true | 269 | 236 | |
|
||||
| while_decl_bind | true | 271 | 273 | |
|
||||
| while_decl_bind | true | 273 | 261 | |
|
||||
| while_decl_bind | true | 274 | 275 | |
|
||||
| while_decl_bind | true | 275 | 243 | |
|
||||
| while_decl_bind | true | 275 | 261 | |
|
||||
|
||||
@@ -16,6 +16,11 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
{
|
||||
private readonly ILogger logger;
|
||||
|
||||
/// <summary>
|
||||
/// Contains the dependencies found in the parsed assets files.
|
||||
/// </summary>
|
||||
public DependencyContainer Dependencies { get; } = new();
|
||||
|
||||
internal Assets(ILogger logger)
|
||||
{
|
||||
this.logger = logger;
|
||||
@@ -72,7 +77,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
/// "json.net"
|
||||
/// }
|
||||
/// </summary>
|
||||
private void AddPackageDependencies(JObject json, DependencyContainer dependencies)
|
||||
private void AddPackageDependencies(JObject json, string jsonPath)
|
||||
{
|
||||
// If there is more than one framework we need to pick just one.
|
||||
// To ensure stability we pick one based on the lexicographic order of
|
||||
@@ -86,7 +91,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
|
||||
if (references is null)
|
||||
{
|
||||
logger.LogDebug("No references found in the targets section in the assets file.");
|
||||
logger.LogDebug($"No references found in the targets section in '{jsonPath}'");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -107,13 +112,13 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
// If this is a framework reference then include everything.
|
||||
if (FrameworkPackageNames.AllFrameworks.Any(framework => name.StartsWith(framework)))
|
||||
{
|
||||
dependencies.AddFramework(name);
|
||||
Dependencies.AddFramework(name);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
info.Compile
|
||||
.ForEach(r => dependencies.Add(name, r.Key));
|
||||
.ForEach(r => Dependencies.Add(name, r.Key));
|
||||
});
|
||||
|
||||
return;
|
||||
@@ -149,7 +154,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
/// "microsoft.netcore.app.ref"
|
||||
/// }
|
||||
/// </summary>
|
||||
private void AddFrameworkDependencies(JObject json, DependencyContainer dependencies)
|
||||
private void AddFrameworkDependencies(JObject json, string jsonPath)
|
||||
{
|
||||
|
||||
var frameworks = json
|
||||
@@ -158,7 +163,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
|
||||
if (frameworks is null)
|
||||
{
|
||||
logger.LogDebug("No framework section in assets.json.");
|
||||
logger.LogDebug($"No framework section in '{jsonPath}'.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -172,13 +177,13 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
|
||||
if (references is null)
|
||||
{
|
||||
logger.LogDebug("No framework references in assets.json.");
|
||||
logger.LogDebug($"No framework references in '{jsonPath}'.");
|
||||
return;
|
||||
}
|
||||
|
||||
references
|
||||
.Properties()
|
||||
.ForEach(f => dependencies.AddFramework($"{f.Name}.Ref".ToLowerInvariant()));
|
||||
.ForEach(f => Dependencies.AddFramework($"{f.Name}.Ref".ToLowerInvariant()));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -186,13 +191,13 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
/// (together with used package information) required for compilation.
|
||||
/// </summary>
|
||||
/// <returns>True if parsing succeeds, otherwise false.</returns>
|
||||
public bool TryParse(string json, DependencyContainer dependencies)
|
||||
public bool TryParse(string json)
|
||||
{
|
||||
try
|
||||
{
|
||||
var obj = JObject.Parse(json);
|
||||
AddPackageDependencies(obj, dependencies);
|
||||
AddFrameworkDependencies(obj, dependencies);
|
||||
AddPackageDependencies(obj, json);
|
||||
AddFrameworkDependencies(obj, json);
|
||||
return true;
|
||||
}
|
||||
catch (Exception e)
|
||||
@@ -217,19 +222,24 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
}
|
||||
}
|
||||
|
||||
public static DependencyContainer GetCompilationDependencies(ILogger logger, IEnumerable<string> assets)
|
||||
/// <summary>
|
||||
/// Add the dependencies from the assets file to the dependencies.
|
||||
/// </summary>
|
||||
/// <param name="asset">Path to an assets file.</param>
|
||||
public void AddDependencies(string asset)
|
||||
{
|
||||
var parser = new Assets(logger);
|
||||
var dependencies = new DependencyContainer();
|
||||
assets.ForEach(asset =>
|
||||
if (TryReadAllText(asset, logger, out var json))
|
||||
{
|
||||
if (TryReadAllText(asset, logger, out var json))
|
||||
{
|
||||
parser.TryParse(json, dependencies);
|
||||
}
|
||||
});
|
||||
return dependencies;
|
||||
TryParse(json);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add the dependencies from the assets files to the dependencies.
|
||||
/// </summary>
|
||||
/// <param name="assets">Collection of paths to assets files.</param>
|
||||
public void AddDependenciesRange(IEnumerable<string> assets) =>
|
||||
assets.ForEach(AddDependencies);
|
||||
}
|
||||
|
||||
internal static class JsonExtensions
|
||||
|
||||
@@ -12,7 +12,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
/// <summary>
|
||||
/// Paths to dependencies required for compilation.
|
||||
/// </summary>
|
||||
public List<string> Paths { get; } = new();
|
||||
public HashSet<string> Paths { get; } = new();
|
||||
|
||||
/// <summary>
|
||||
/// Packages that are used as a part of the required dependencies.
|
||||
@@ -45,7 +45,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
var p = package.Replace('/', Path.DirectorySeparatorChar);
|
||||
var d = dependency.Replace('/', Path.DirectorySeparatorChar);
|
||||
|
||||
// In most cases paths in asset files point to dll's or the empty _._ file.
|
||||
// In most cases paths in assets files point to dll's or the empty _._ file.
|
||||
// That is, for _._ we don't need to add anything.
|
||||
if (Path.GetFileName(d) == "_._")
|
||||
{
|
||||
@@ -68,4 +68,18 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
Packages.Add(GetPackageName(p));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal static class DependencyContainerExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Flatten a list of containers into a single container.
|
||||
/// </summary>
|
||||
public static DependencyContainer Flatten(this IEnumerable<DependencyContainer> containers, DependencyContainer init) =>
|
||||
containers.Aggregate(init, (acc, container) =>
|
||||
{
|
||||
acc.Paths.UnionWith(container.Paths);
|
||||
acc.Packages.UnionWith(container.Packages);
|
||||
return acc;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,8 +3,6 @@ using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Semmle.Util;
|
||||
@@ -152,7 +150,8 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
var sourceGenerators = new ISourceGenerator[]
|
||||
{
|
||||
new ImplicitUsingsGenerator(fileContent, logger, tempWorkingDirectory),
|
||||
new WebViewGenerator(fileProvider, fileContent, dotnet, this, logger, tempWorkingDirectory, usedReferences.Keys)
|
||||
new RazorGenerator(fileProvider, fileContent, dotnet, this, logger, tempWorkingDirectory, usedReferences.Keys),
|
||||
new ResxGenerator(fileProvider, fileContent, dotnet, this, logger, nugetPackageRestorer, tempWorkingDirectory, usedReferences.Keys),
|
||||
};
|
||||
|
||||
foreach (var sourceGenerator in sourceGenerators)
|
||||
@@ -190,6 +189,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
|
||||
private HashSet<string> AddFrameworkDlls(HashSet<AssemblyLookupLocation> dllLocations)
|
||||
{
|
||||
logger.LogInfo("Adding .NET Framework DLLs");
|
||||
var frameworkLocations = new HashSet<string>();
|
||||
|
||||
var frameworkReferences = Environment.GetEnvironmentVariable(EnvironmentVariableNames.DotnetFrameworkReferences);
|
||||
@@ -255,35 +255,6 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
}
|
||||
}
|
||||
|
||||
private void SelectNewestFrameworkPath(string frameworkPath, string frameworkType, ISet<AssemblyLookupLocation> dllLocations, ISet<string> frameworkLocations)
|
||||
{
|
||||
var versionFolders = GetPackageVersionSubDirectories(frameworkPath);
|
||||
if (versionFolders.Length > 1)
|
||||
{
|
||||
var versions = string.Join(", ", versionFolders.Select(d => d.Name));
|
||||
logger.LogDebug($"Found multiple {frameworkType} DLLs in NuGet packages at {frameworkPath}. Using the latest version ({versionFolders[0].Name}) from: {versions}.");
|
||||
}
|
||||
|
||||
var selectedFrameworkFolder = versionFolders.FirstOrDefault()?.FullName;
|
||||
if (selectedFrameworkFolder is null)
|
||||
{
|
||||
logger.LogDebug($"Found {frameworkType} DLLs in NuGet packages at {frameworkPath}, but no version folder was found.");
|
||||
selectedFrameworkFolder = frameworkPath;
|
||||
}
|
||||
|
||||
dllLocations.Add(selectedFrameworkFolder);
|
||||
frameworkLocations.Add(selectedFrameworkFolder);
|
||||
logger.LogDebug($"Found {frameworkType} DLLs in NuGet packages at {selectedFrameworkFolder}.");
|
||||
}
|
||||
|
||||
private static DirectoryInfo[] GetPackageVersionSubDirectories(string packagePath)
|
||||
{
|
||||
return new DirectoryInfo(packagePath)
|
||||
.EnumerateDirectories("*", new EnumerationOptions { MatchCasing = MatchCasing.CaseInsensitive, RecurseSubdirectories = false })
|
||||
.OrderByDescending(d => d.Name) // TODO: Improve sorting to handle pre-release versions.
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
private void RemoveFrameworkNugetPackages(ISet<AssemblyLookupLocation> dllLocations, int fromIndex = 0)
|
||||
{
|
||||
var packagesInPrioOrder = FrameworkPackageNames.NetFrameworks;
|
||||
@@ -310,10 +281,12 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
{
|
||||
foreach (var fp in frameworkPaths)
|
||||
{
|
||||
dotnetFrameworkVersionVariantCount += GetPackageVersionSubDirectories(fp.Path!).Length;
|
||||
dotnetFrameworkVersionVariantCount += NugetPackageRestorer.GetOrderedPackageVersionSubDirectories(fp.Path!).Length;
|
||||
}
|
||||
|
||||
SelectNewestFrameworkPath(frameworkPath.Path, ".NET Framework", dllLocations, frameworkLocations);
|
||||
var folder = nugetPackageRestorer.GetNewestNugetPackageVersionFolder(frameworkPath.Path, ".NET Framework");
|
||||
dllLocations.Add(folder);
|
||||
frameworkLocations.Add(folder);
|
||||
RemoveFrameworkNugetPackages(dllLocations, frameworkPath.Index + 1);
|
||||
return;
|
||||
}
|
||||
@@ -331,7 +304,7 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
if (runtimeLocation is null)
|
||||
{
|
||||
logger.LogInfo("No .NET Desktop Runtime location found. Attempting to restore the .NET Framework reference assemblies manually.");
|
||||
runtimeLocation = nugetPackageRestorer.TryRestoreLatestNetFrameworkReferenceAssemblies();
|
||||
runtimeLocation = nugetPackageRestorer.TryRestore(FrameworkPackageNames.LatestNetFrameworkReferenceAssemblies);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -371,7 +344,9 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
// First try to find ASP.NET Core assemblies in the NuGet packages
|
||||
if (GetPackageDirectory(FrameworkPackageNames.AspNetCoreFramework) is string aspNetCorePackage)
|
||||
{
|
||||
SelectNewestFrameworkPath(aspNetCorePackage, "ASP.NET Core", dllLocations, frameworkLocations);
|
||||
var folder = nugetPackageRestorer.GetNewestNugetPackageVersionFolder(aspNetCorePackage, "ASP.NET Core");
|
||||
dllLocations.Add(folder);
|
||||
frameworkLocations.Add(folder);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -387,7 +362,9 @@ namespace Semmle.Extraction.CSharp.DependencyFetching
|
||||
{
|
||||
if (GetPackageDirectory(FrameworkPackageNames.WindowsDesktopFramework) is string windowsDesktopApp)
|
||||
{
|
||||
SelectNewestFrameworkPath(windowsDesktopApp, "Windows Desktop App", dllLocations, frameworkLocations);
|
||||
var folder = nugetPackageRestorer.GetNewestNugetPackageVersionFolder(windowsDesktopApp, "Windows Desktop App");
|
||||
dllLocations.Add(folder);
|
||||
frameworkLocations.Add(folder);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user