Compare commits

..

270 Commits

Author SHA1 Message Date
Cornelius Riemenschneider
205209c324 Remove dev_dependency from buildifier_prebuilt.
Otherwise, including any targets from //:BUILD.bazel
in something that gets invoked from the internal build system
will result in a missing dependency error.
This is relevant for C#, where I add a file export
to `LICENSE` to the top-level `BUILD.bazel` file.
2024-05-06 10:31:17 +02:00
Mathias Vorreiter Pedersen
5d5e31378b Merge pull request #16415 from MathiasVP/cleanup-ir-variables 2024-05-03 18:49:11 +01:00
Jeroen Ketema
5cde3fa697 Merge pull request #16414 from jketema/range-based-for-loop-destructor-fix
C++: Correctly handle destructors at the end of range-based for-loops in the IR
2024-05-03 19:38:45 +02:00
Geoffrey White
eb0621ab7a Merge pull request #16406 from geoffw0/test1
C++: Add test case for reassignment to UseAfterFree.ql.
2024-05-03 15:32:58 +01:00
Geoffrey White
c0cf1c7c8c Merge pull request #16402 from geoffw0/stringlifetimedoc
C++: Improve UseOfStringAfterLifetimeEnds doc.
2024-05-03 15:04:07 +01:00
Mathias Vorreiter Pedersen
d5475c4a89 C++: Delete predicate that I introduced by mistake. 2024-05-03 14:48:01 +01:00
Mathias Vorreiter Pedersen
7ca54a6f94 C++: Sync identical files. 2024-05-03 13:51:04 +01:00
Mathias Vorreiter Pedersen
e8cb8b4f81 C++: Convert IR variables to an abstract base class and use final alias'ing to ensure that we don't accidentially extend the abstract base class. 2024-05-03 13:50:50 +01:00
Jeroen Ketema
ba64cf3016 C++: Correctly handle destructors at the end of range-based for-loops in the IR 2024-05-03 14:38:37 +02:00
Geoffrey White
807e6795a7 Apply suggestions from code review
Co-authored-by: mc <42146119+mchammer01@users.noreply.github.com>
2024-05-03 11:40:56 +01:00
Paolo Tranquilli
880262d462 Merge pull request #16393 from github/redsun82/lfs
Bazel: improved lazy lfs files
2024-05-03 12:37:41 +02:00
Michael Nebel
95ff5bae65 Merge pull request #16297 from michaelnebel/java/improveapitelemetry
Java: Identify more APIs as supported in the telemetry queries.
2024-05-03 12:34:19 +02:00
Paolo Tranquilli
6cbe16e0c2 Bazel: add progress reporting 2024-05-03 12:00:15 +02:00
Mathias Vorreiter Pedersen
75615f2817 Merge pull request #16373 from jketema/destructors-block-fix
C++: Update test results after extractor changes
2024-05-03 10:17:40 +01:00
Michael Nebel
c07bf65eb6 Update java/ql/lib/semmle/code/java/dataflow/FlowSources.qll
Co-authored-by: Owen Mansel-Chan <62447351+owen-mc@users.noreply.github.com>
2024-05-03 11:13:05 +02:00
Michael Nebel
8def1c2c13 Java: Address review comments and some other code quality improvements. 2024-05-03 11:11:52 +02:00
Rasmus Wriedt Larsen
1b90f22e84 Merge pull request #16400 from RasmusWL/accept-ci-fixes
.expected script: Handle multiple job failure URLs
2024-05-03 09:58:47 +02:00
Paolo Tranquilli
ecdf62376d Bazel: clean up git_lfs_probe.py 2024-05-03 09:21:57 +02:00
Paolo Tranquilli
96d69ca49c Merge branch 'main' into redsun82/lfs 2024-05-02 18:05:50 +02:00
Paolo Tranquilli
daea674095 Bazel: cover standard https git credentials in git_lfs_probe.py 2024-05-02 18:02:22 +02:00
Geoffrey White
315f439135 C++: Add test case for reassignment to UseAfterFree.ql. 2024-05-02 16:40:28 +01:00
Geoffrey White
e4cf7df38f C++: Edits to the .qhelp based on suggestions. 2024-05-02 16:00:31 +01:00
Geoffrey White
b8b3689251 C++: Autoformat. 2024-05-02 15:49:56 +01:00
Geoffrey White
0693bf9e75 C++: Improve UseOfStringAfterLifetimeEnds qhelp, references and alert message. 2024-05-02 15:40:27 +01:00
Rasmus Wriedt Larsen
ccad70897d Add --dont-wait option 2024-05-02 15:39:07 +02:00
Rasmus Wriedt Larsen
3239af9973 Handle multiple job failure URLs
CI has changed how jobs are being run 🤷
2024-05-02 15:31:56 +02:00
Mathias Vorreiter Pedersen
f7113e0105 Merge pull request #16345 from MathiasVP/cleanup-ssa-and-iterator-flow
C++: Clean up SSA and stop relying on memory edges for iterator flow
2024-05-02 14:21:25 +01:00
Rasmus Wriedt Larsen
2cff081f2b Minor fixes to CI script.
I had problems with proper resolution of codeql_repo_dir with old python installation, this fixes it
2024-05-02 15:13:50 +02:00
Tamás Vajk
f99cb3f649 Merge pull request #16396 from tamasvajk/buildless/opt-out-feed-check
C#: Change nuget feed responsiveness checking to be opt-out
2024-05-02 15:04:28 +02:00
Tamás Vajk
dfdd79d8cf Merge pull request #16395 from tamasvajk/buildless/logs1
C#: Add file path to log messages in assets.json parsing
2024-05-02 15:03:57 +02:00
Mathias Vorreiter Pedersen
b912918d8b C++: Fix QLDoc. 2024-05-02 13:32:52 +01:00
Harry Maclean
ef88f3ed09 Merge pull request #16377 from hmac/hmac-sanitization-fp
Ruby: Fix StringSubstitutionCall charpred
2024-05-02 13:31:01 +01:00
Tamas Vajk
d909f2bc4f Fix expected test output 2024-05-02 13:32:01 +02:00
Owen Mansel-Chan
9bfb189fa7 Merge pull request #16392 from owen-mc/external-flow/standardize-empty-model-yml
External flow: standardize `empty.model.yml`
2024-05-02 11:01:47 +01:00
Mathias Vorreiter Pedersen
322fa36359 C++: Fix QLDoc. 2024-05-02 10:37:49 +01:00
Mathias Vorreiter Pedersen
4a47e11a16 C++: Fix QLDoc. 2024-05-02 10:36:40 +01:00
Owen Mansel-Chan
83249cd9c2 Fix grammar in comment 2024-05-02 09:59:48 +01:00
Tamas Vajk
c6185b30ba C#: Change nuget feed responsiveness checking to be opt-out 2024-05-02 10:25:12 +02:00
Tamas Vajk
9ce08c586c C#: Add file path to log messages in assets.json parsing 2024-05-02 10:14:26 +02:00
Harry Maclean
7d92ec5ddf Merge pull request #16378 from hmac/hmac-sanitization-wording
Ruby: fix wording in rb/request-without-cert-validation
2024-05-02 08:00:28 +01:00
Paolo Tranquilli
9157dee0db Bazel: integrate download_and_extract into lfs_smudge 2024-05-02 08:53:51 +02:00
Paolo Tranquilli
677520aa8e Bazel: improved lazy lfs files
This reintroduces lazy lfs file rules that were removed in
https://github.com/github/codeql/pull/16117, now improved.

The new rules will make the actual file download go through bazel's
download manager, which includes:
* caching into the repository cache
* sane limiting of concurrent downloads
* retries

The bulk of the work is done by `git_lfs_probe.py`, which will use the
LFS protocol (with authentication via SSH) to output short lived
download URLs that can be consumed by `repository_ctx.download`.
2024-05-02 06:38:26 +02:00
Owen Mansel-Chan
16dcc0969b Standardise comment explaining why extensible predicates must be defined 2024-05-01 22:00:01 +01:00
Owen Mansel-Chan
09e59ccf44 Name files with empty definitions of MaD extensible predicates to erowdmpty.model.yml 2024-05-01 21:39:38 +01:00
Mathias Vorreiter Pedersen
a8f2cbc2b1 Merge pull request #16331 from mario-campos/mario-campos/guarded-free
Cpp: new experimental query cpp/guarded-free
2024-05-01 17:32:44 +01:00
Harry Maclean
c00d0d302d Ruby: fix wording in rb/request-without-cert-validation 2024-05-01 17:25:58 +01:00
Mario Campos
5a7a1dc92e C++: forgot to import semmle.code.cpp.controlflow.Guards 2024-05-01 11:00:19 -05:00
Mario Campos
c480431ec0 C++: simplify cpp/guarded-free
This new form is more declarative by use of the `GuardCondition`. Thanks to the tireless effort of @MathiasVP!
2024-05-01 10:59:16 -05:00
Harry Maclean
f7fc2e0b00 Ruby: Fix StringSubstitutionCall charpred
Some missing parens meant this class targeted way more things than
intended.
2024-05-01 16:14:58 +01:00
Michael B. Gale
397e641f2f Merge pull request #16375 from github/mbg/go/allow-version-suffixes
Go: Allow version suffixes
2024-05-01 15:41:54 +01:00
Michael B. Gale
00cbfaf40e Go: Allow version suffixes 2024-05-01 15:00:45 +01:00
Mathias Vorreiter Pedersen
dc4604f5a5 Merge pull request #16367 from MathiasVP/better-documentation-for-iterator-to-expired-container
C++: Improve documentation for `cpp/iterator-to-expired-container`
2024-05-01 11:56:27 +01:00
Mathias Vorreiter Pedersen
40b6e1624f Update cpp/ql/src/Security/CWE/CWE-416/IteratorToExpiredContainer.qhelp
Co-authored-by: mc <42146119+mchammer01@users.noreply.github.com>
2024-05-01 11:41:23 +01:00
Mathias Vorreiter Pedersen
22e843abc6 Update cpp/ql/src/Security/CWE/CWE-416/IteratorToExpiredContainer.qhelp
Co-authored-by: mc <42146119+mchammer01@users.noreply.github.com>
2024-05-01 11:41:16 +01:00
Jeroen Ketema
3c70a2d7df C++: Update test results after extractor changes 2024-05-01 12:30:38 +02:00
Jeroen Ketema
541effb8cb Merge pull request #16369 from jketema/destructors-init-stmt
C++: Update IR tests after better handling of init statements in the extractor
2024-05-01 10:47:03 +02:00
Anders Schack-Mulligen
248ffa15a2 Merge pull request #16318 from aschackmull/dataflow/doublyboundedfasttc
Dataflow: Use doublyBoundedFastTC.
2024-05-01 09:48:23 +02:00
Jeroen Ketema
5843326b5c C++: Update IR tests after better handling of init statements in the extractor 2024-04-30 21:12:30 +02:00
Mathias Vorreiter Pedersen
3a2b0a2feb Merge pull request #16366 from MathiasVP/fix-ir-for-destructors-in-switch
C++: Fix IR destructor calls on `JumpStmt`s
2024-04-30 18:26:54 +01:00
Mathias Vorreiter Pedersen
07dd6d5c8d C++: Align 'break' statements. 2024-04-30 16:40:23 +01:00
Mathias Vorreiter Pedersen
708d12624f C++: Update documentation on 'cpp/iterator-to-expired-container'. 2024-04-30 16:32:32 +01:00
Mathias Vorreiter Pedersen
3eddd3114f C++: Accept test changes. 2024-04-30 16:14:30 +01:00
Mathias Vorreiter Pedersen
61ce7252e6 C++: Update the alert message in 'cpp/iterator-to-expired-container'. 2024-04-30 16:12:54 +01:00
Mathias Vorreiter Pedersen
b86aeb68ae Merge pull request #16364 from MathiasVP/ir-guards-with-boolean
C++: Support `IRGuard`s with no implicit boolean conversion
2024-04-30 16:07:32 +01:00
Mathias Vorreiter Pedersen
cf025e1924 C++: Accept test changes. 2024-04-30 15:47:53 +01:00
Mathias Vorreiter Pedersen
a200ced2d6 C++: Fix IR generation for jump statements. 2024-04-30 15:46:46 +01:00
Mathias Vorreiter Pedersen
c04e59611b Merge pull request #16355 from MathiasVP/promote-iterator-to-expired-container-out-of-experimental
C++: Promote `cpp/iterator-to-expired-container` out of experimental
2024-04-30 15:45:56 +01:00
Mathias Vorreiter Pedersen
c5a87c95d8 C++: Add tests that incorrectly call destructors twice. 2024-04-30 15:39:00 +01:00
Henry Mercer
797f675285 Merge pull request #16365 from github/post-release-prep/codeql-cli-2.17.2
Post-release preparation for codeql-cli-2.17.2
2024-04-30 14:51:01 +01:00
Mathias Vorreiter Pedersen
c32c810ae7 C++: Add a test with a 'short' type. 2024-04-30 14:48:21 +01:00
Mathias Vorreiter Pedersen
32fe084630 Update cpp/ql/lib/semmle/code/cpp/controlflow/IRGuards.qll
Co-authored-by: Jeroen Ketema <93738568+jketema@users.noreply.github.com>
2024-04-30 14:42:30 +01:00
Ian Lynagh
0715c4ac5a Merge pull request #16341 from igfoo/igfoo/ODASA_BUILD_ERROR_DIR
Java: Remove support for deprecated ODASA_BUILD_ERROR_DIR env var
2024-04-30 13:18:51 +01:00
github-actions[bot]
99928b82ed Post-release preparation for codeql-cli-2.17.2 2024-04-30 12:15:35 +00:00
Rasmus Wriedt Larsen
377c6b4cc8 Merge pull request #12557 from felickz/patch-1
add  security-severity score to code scanning query list
2024-04-30 13:48:22 +02:00
Mathias Vorreiter Pedersen
2939c89f7a C++: Accept test changes. 2024-04-30 12:04:42 +01:00
Mathias Vorreiter Pedersen
bb6cc92728 C++: Support guards without implicit boolean conversions. 2024-04-30 12:04:35 +01:00
Mathias Vorreiter Pedersen
d736426529 C++: Support guards without implicit boolean conversions. 2024-04-30 11:45:58 +01:00
Mathias Vorreiter Pedersen
806d42852c C++: Add test in C file with pointer type guard. 2024-04-30 11:33:22 +01:00
Henry Mercer
8e251ee54f Merge pull request #16363 from github/release-prep/2.17.2
Release preparation for version 2.17.2
2024-04-30 11:29:06 +01:00
github-actions[bot]
5228d94d42 Release preparation for version 2.17.2 2024-04-30 10:25:51 +00:00
Geoffrey White
7d9f78b2de Merge pull request #16328 from geoffw0/pathinj
C++: Reduce duplication from cpp/path-injection
2024-04-30 10:06:40 +01:00
Erik Krogh Kristensen
7e839792da Merge pull request #16330 from erik-krogh/del-deps-apr-2024
All: delete outdated deprecations
2024-04-30 10:43:39 +02:00
Paolo Tranquilli
98106f31c1 Merge pull request #16358 from github/redsun82/registry-override
Bazel: add empty registry override
2024-04-30 09:09:46 +02:00
Ian Lynagh
676bcf39a5 Java: Remove support for deprecated ODASA_BUILD_ERROR_DIR env var 2024-04-29 18:02:28 +01:00
Paolo Tranquilli
a28f87fff0 Bazel: add empty registry override
This will unblock work in parallel on two separate PRs that require
patching different modules.
2024-04-29 18:01:09 +02:00
Mathias Vorreiter Pedersen
94364f724e C++: Remove CP between all sinks and all states in 'cpp/iterator-to-expired-container'. 2024-04-29 16:46:00 +01:00
Harry Maclean
607ed2efb4 Merge pull request #16354 from hmac/hmac-incomplete-hostname-fp
Ruby: Reduce FPs for rb/incomplete-hostname-regexp
2024-04-29 14:40:44 +01:00
Michael Nebel
a304e2d8d6 Merge pull request #16248 from michaelnebel/csharp/groupsprojectbeforerestore
C#: Restore projects and collect dependencies for projects in the same folder sequentially.
2024-04-29 14:05:40 +02:00
yoff
1c611fecde Merge pull request #16155 from yoff/python/MaD-method-arg-tests 2024-04-29 12:59:57 +02:00
Harry Maclean
51bc8e917e Ruby: Reduce FPs for rb/incomplete-hostname-regexp
Arguments in calls to `match[?]` should only be considered regular
expression interpretations if the `match` refers to the standard library
method, not a method in source code.
2024-04-29 11:19:34 +01:00
Mathias Vorreiter Pedersen
0fa5a1f274 C++: Add change note. 2024-04-29 11:17:53 +01:00
Mathias Vorreiter Pedersen
5c454bdd8c C++: Compute and add severity. 2024-04-29 11:09:42 +01:00
Mathias Vorreiter Pedersen
f194c70e8a C++: Set precision to medium. 2024-04-29 11:08:08 +01:00
Mathias Vorreiter Pedersen
179270ffc1 C++: Move 'cpp/iterator-to-expired-container' out of experimental. 2024-04-29 11:07:55 +01:00
Harry Maclean
8ccedd658a Merge pull request #16349 from hmac/hmac-uri-open
Ruby: Add URI.open example to rb/kernel-open qhelp
2024-04-29 09:42:39 +01:00
Mathias Vorreiter Pedersen
401717d739 C++: Add a missing taint step and accept test changes. 2024-04-29 09:38:42 +01:00
Mathias Vorreiter Pedersen
527409d05f C++: Fix iterator return types and accept test changes. 2024-04-29 09:38:42 +01:00
Mathias Vorreiter Pedersen
d3d2e2188d C++: Accept test changes. 2024-04-29 09:38:42 +01:00
Mathias Vorreiter Pedersen
141af7cc87 C++: Subclasses for both 'begin' and 'end'. 2024-04-29 09:38:42 +01:00
Mathias Vorreiter Pedersen
6e3dddede0 C++: Use iterator flow in dataflow. 2024-04-29 09:38:42 +01:00
Mathias Vorreiter Pedersen
683fe26034 C++: Add iterator flow based on dataflow SSA. 2024-04-29 09:38:41 +01:00
Mathias Vorreiter Pedersen
ea1b8a3999 C++: Implement 'getAnUltimateDefinition' on SSA definitions. 2024-04-29 09:38:41 +01:00
Mathias Vorreiter Pedersen
5f0efc19fa C++: Accept test changes. 2024-04-29 09:38:41 +01:00
Michael Nebel
d62e888b86 C#: Code quality improvements. 2024-04-29 09:27:12 +02:00
Mathias Vorreiter Pedersen
50775d0c53 C++: Get rid of 'UseImpl' in TSsaDefOrUse so that it now only contains definitions. 2024-04-29 00:02:05 +01:00
Mathias Vorreiter Pedersen
9874d40d29 C++: Make 'getAddressOperand' available on 'DefImpl'. 2024-04-28 23:41:18 +01:00
Mathias Vorreiter Pedersen
044ee9b08a C++: Delete old iterator flow using memory edges. 2024-04-28 23:41:13 +01:00
Harry Maclean
8b23f6db10 Ruby: Add URI.open example to rb/kernel-open qhelp 2024-04-27 09:53:54 +01:00
Mathias Vorreiter Pedersen
3c2206728d Merge pull request #16333 from MathiasVP/fix-guards-on-pointers 2024-04-26 21:33:08 +01:00
Jeroen Ketema
8c87cb83bb Merge pull request #16342 from jketema/destructors-cleanup
C++: Don't emit destructor calls as part of 'TranslatedResultCopy' as this has already been done in some other 'TranslatedExpr'.
2024-04-26 22:05:00 +02:00
Mathias Vorreiter Pedersen
c9ce642e7a Merge pull request #16339 from MathiasVP/one-less-stage
C++: Remove a stage by properly caching `getResultIRType`
2024-04-26 16:52:16 +01:00
Mathias Vorreiter Pedersen
d18cdee0bc C++: Accept test changes. 2024-04-26 16:19:33 +01:00
Mathias Vorreiter Pedersen
b78537dd74 C++: Allow comparisons with pointer types in IRGuards. 2024-04-26 16:19:24 +01:00
Mathias Vorreiter Pedersen
e78091e9d0 C++: Sync identical files. 2024-04-26 16:19:02 +01:00
Mathias Vorreiter Pedersen
c10e00d389 C++: Add a subclass for constant instructions with pointer type. 2024-04-26 16:18:52 +01:00
Mathias Vorreiter Pedersen
bf61114284 C++: Add a test with pointer comparisons and float comparisons. 2024-04-26 16:17:45 +01:00
erik-krogh
800d7546fa change all the change-notes to breaking 2024-04-26 17:17:23 +02:00
Mathias Vorreiter Pedersen
d6c57de650 C++: Convert one of the tests to also test the 'absolute' versions of the GuardCondition predicates. 2024-04-26 16:11:19 +01:00
Mathias Vorreiter Pedersen
6147a38bea Merge pull request #16337 from MathiasVP/cache-second-level-scope
DataFlow: Cache `getSecondLevelScope`
2024-04-26 15:49:11 +01:00
Jeroen Ketema
67fb866efa C++: Update test results 2024-04-26 16:38:39 +02:00
Mathias Vorreiter Pedersen
4b0a217420 C++: Don't emit destructor calls as part of 'TranslatedResultCopy' as this has already been done in some other 'TranslatedExpr'. 2024-04-26 16:25:05 +02:00
Mario Campos
3195f0c828 Use more specific hasGlobalName() for stdlib function free(3)
Based on the CodeQL documentation's example of strncpy(3) and strlen(3): https://codeql.github.com/docs/codeql-language-guides/hash-consing-and-value-numbering/#example-query
2024-04-26 09:10:40 -05:00
Tamás Vajk
a707e14495 Merge pull request #16338 from tamasvajk/buildless/extractor-timing
C#: Store buildless extraction timing information and return in telem…
2024-04-26 15:59:01 +02:00
Tamas Vajk
1d45e3a558 C#: Store buildless extraction timing information and return in telemetry query 2024-04-26 14:59:31 +02:00
Mathias Vorreiter Pedersen
70e9c48a47 C++: Also implement the predicate in the raw stage. 2024-04-26 13:48:13 +01:00
Mathias Vorreiter Pedersen
dcc4ad2550 C++: Sync identical files. 2024-04-26 13:45:15 +01:00
Mathias Vorreiter Pedersen
54cadcfe9b C++: Forward to a cached predicate in a cached module instead of caching the predicate in 'Instruction.qll' to include it in the cached stage of the other predicates. 2024-04-26 13:44:45 +01:00
Rasmus Lerchedahl Petersen
3716b8c6a0 Python: update test to reflect correct behaviour
also add comments
2024-04-26 14:21:15 +02:00
Rasmus Lerchedahl Petersen
9f7edf378e Python: fix tests
The way to expose the `self` arguemnt
is to call an instance method on the class,
not on the instance...
2024-04-26 14:21:15 +02:00
Rasmus Lerchedahl Petersen
4f46ce1133 Python: add test for Argument[0, self, self:] for instance methods 2024-04-26 14:21:15 +02:00
Michael Nebel
f95b33049e Java: Improve the Api sources and sinks implementation. 2024-04-26 14:12:41 +02:00
Mathias Vorreiter Pedersen
2482519cd3 DataFlow: Cached second level scope. 2024-04-26 13:09:59 +01:00
Asger F
e44d4c45aa Merge pull request #16323 from asgerf/js/expose-internal-module-naming
JS: Expose InternalModuleNaming
2024-04-26 13:57:26 +02:00
erik-krogh
14d88eb3ce add change-notes 2024-04-26 12:56:28 +02:00
Michael Nebel
b754706e44 Java: Update SupportedExternalApi expected test output. 2024-04-26 12:39:46 +02:00
Michael Nebel
9db32f4d26 Java: Identify more APIs as supported in the telemetry queries (as QL defined sinks). 2024-04-26 12:39:46 +02:00
Michael Nebel
acb2bbb2a3 Java: Identify more APIs as supported in the telemetry queries (as QL defined sources). 2024-04-26 12:39:46 +02:00
Michael Nebel
06f987ad58 Java: Add test example of a supported sink defined in QL. 2024-04-26 12:39:46 +02:00
erik-krogh
0468c5d0bf delete some tests of the old GVN library 2024-04-26 07:58:35 +02:00
erik-krogh
e55f2c5309 reinroduce GLobalValueNumbering.qll, that one was supposed to stay 2024-04-26 06:52:57 +02:00
Mario Campos
d7c784ef2f Initial commit of experimental query cpp/guarded-free. 2024-04-25 16:29:37 -05:00
erik-krogh
fb376a1cfd revert the deletion of explorationLimit. It'll be deleted along with the entire class later 2024-04-25 22:31:11 +02:00
erik-krogh
baa31e1469 delete outdated deprecations 2024-04-25 22:19:28 +02:00
Jeroen Ketema
8d962a5c28 Merge pull request #16322 from jketema/child-stmt
C++: Print destructors for children of statements that are again statements
2024-04-25 22:17:35 +02:00
Jeroen Ketema
389df35fb7 Merge branch 'main' into child-stmt 2024-04-25 21:47:06 +02:00
Geoffrey White
aa80dd41da Merge pull request #16329 from geoffw0/multibyte
C++: Fix typo.
2024-04-25 17:26:40 +01:00
Geoffrey White
553871678a C++: Change note. 2024-04-25 16:52:01 +01:00
Geoffrey White
15123a7b40 C++: Reduce duplication. 2024-04-25 16:49:22 +01:00
Geoffrey White
bbd80ec7a4 C++: Add some more test cases. 2024-04-25 16:44:52 +01:00
Florin Coada
1d421b3b28 Merge pull request #16326 from github/changedocs/2.17.1
Update codeql-changelog index.rst to include codeql-cli-2.17.1
2024-04-25 16:08:41 +01:00
Michael B. Gale
a87b991d78 Merge pull request #16325 from github/mbg/go/use-parse-instead-of-parselax 2024-04-25 15:20:36 +01:00
Geoffrey White
0fb71e24cb C++: Fix typo. 2024-04-25 14:52:56 +01:00
Florin Coada
14d04903dc Update codeql-changelog index.rst to include codeql-cli-2.17.1 2024-04-25 14:40:44 +01:00
Michael Nebel
181a063bb9 C#: Update expected test output. 2024-04-25 15:38:39 +02:00
Michael Nebel
131d0b911f C#: Inline dependency collection from asset files per group. 2024-04-25 15:35:08 +02:00
Michael Nebel
0124b0749f C#: Do not run dotnet restore in parallel for projects in the same folder. 2024-04-25 15:35:07 +02:00
Michael Nebel
6daf80cdd0 C#: Add integration test with multiple project files that have disjoint dependencies. 2024-04-25 15:35:07 +02:00
Tamás Vajk
9c139b591f Merge pull request #16321 from tamasvajk/buildless/log-messages
C#: Improve log messages
2024-04-25 15:12:37 +02:00
Michael B. Gale
b8cfff6d19 Go: Use Parse instead of ParseLax, since we need toolchain directives 2024-04-25 14:10:26 +01:00
Michael B. Gale
f33d7ee80d Go: Add unit tests for hasInvalidToolchainVersion 2024-04-25 14:09:47 +01:00
Michael B. Gale
15a6308c72 Go: Refactor condition for EmitInvalidToolchainVersion into separate function 2024-04-25 14:04:00 +01:00
Tamas Vajk
dd9183c345 Code quality improvements 2024-04-25 14:38:26 +02:00
Asger F
d0c9e3f7ad JS: Expose InternalModuleNaming 2024-04-25 13:33:17 +02:00
Asger F
9082972842 Merge pull request #16061 from RasmusWL/js-extractor-fix
JS: More robust CommonJS/ES2015 detection logic for extractor
2024-04-25 13:26:56 +02:00
Jeroen Ketema
05819a52ef C++: Print destructors for children of statements that are again statements 2024-04-25 13:25:42 +02:00
Nick Rolfe
116873c9b0 Merge pull request #16314 from github/nickrolfe/rb-sensitive
Ruby: do fewer regexp matches in SensitiveActions
2024-04-25 11:56:41 +01:00
Rasmus Wriedt Larsen
290b0fc4ab Merge pull request #16308 from asgerf/js/model-generation-quote
JS: Fix naming issue in generated models
2024-04-25 11:36:36 +02:00
Paolo Tranquilli
332d118d93 Merge pull request #16315 from github/redsun82/buildifier
Bazel: introduce buildifier formatting
2024-04-25 10:48:18 +02:00
Owen Mansel-Chan
82bbecc9c4 Merge pull request #16307 from owen-mc/go/fix/incomplete-hostname-regex
Go: fix flow through string concatenation in `go/incomplete-hostname-regex`
2024-04-25 09:43:51 +01:00
Tamas Vajk
15c1fd9425 C#: Improve log messages 2024-04-25 10:39:53 +02:00
Rasmus Wriedt Larsen
13ff9412a4 Merge pull request #16252 from RasmusWL/move-dataflow-tests
Python: Move dataflow tests out of experimental
2024-04-25 10:05:06 +02:00
Jeroen Ketema
9d24b5afa6 Merge pull request #16319 from jketema/ir-comment-fix
C++: Fix comment in IR test
2024-04-25 09:59:58 +02:00
Jeroen Ketema
95ec4e8d26 C++: Fix comment in IR test 2024-04-24 21:47:47 +02:00
Tom Hvitved
17e0cc5648 Merge pull request #16313 from hvitved/dataflow/fix-bad-join3
Data flow: Fix bad join
2024-04-24 17:09:14 +02:00
Paolo Tranquilli
196b6d7a1d CI: simplify reporting 2024-04-24 16:43:38 +02:00
Paolo Tranquilli
9def57250d CI: make reporting better 2024-04-24 16:35:50 +02:00
Paolo Tranquilli
9af9873e04 CI: add names to steps 2024-04-24 16:20:54 +02:00
Paolo Tranquilli
9f5782b67b Bazel: introduce buildifier formatting
This introduces tooling and enforcement for formatting bazel files.

The tooling is provided as a bazel run target from
[keith/buildifier-prebuilt](https://github.com/keith/buildifier-prebuilt).

This is used in a [`pre-commit`](https://pre-commit.com/) hook for those
having that installed. In turn this is used in a CI check. Relying on a
`pre-commit` action gives us easy checking that buildifying did not
change anything in the files and printing the diff, without having to
hand-roll the check ourselves.

This enforcement will make usage of gazelle easier, as gazelle itself
might reformat files, even outside of `go`. Having them properly
formatted will allow gazelle to leave them unchanged, without needing
to configure awkward exclude directives.
2024-04-24 15:49:48 +02:00
Owen Mansel-Chan
c61177cf42 Add change note 2024-04-24 14:21:59 +01:00
Owen Mansel-Chan
4140942479 Update tests 2024-04-24 14:19:33 +01:00
Owen Mansel-Chan
fd306ed79b Exclude constant names from sources to avoid duplicate results 2024-04-24 14:19:30 +01:00
Owen Mansel-Chan
8962307291 Add second good go file to tests 2024-04-24 14:19:29 +01:00
Owen Mansel-Chan
0000c72329 Remove attempt at avoiding duplicate alerts 2024-04-24 14:19:26 +01:00
Owen Mansel-Chan
3ef7a0932a Add flow through string concatenation 2024-04-24 14:19:25 +01:00
Tamás Vajk
f29d2c21bd Merge pull request #16312 from tamasvajk/fix/buildless/file-lookup
C#: Fix `global.json` and `packages.config` lookup
2024-04-24 15:05:55 +02:00
Tamás Vajk
3b44b131b9 Merge pull request #16311 from tamasvajk/fix/resx
C#: Do not download `Microsoft.CodeAnalysis.ResxSourceGenerator` when…
2024-04-24 13:49:55 +02:00
Tamas Vajk
4a97f95890 Improve code quality 2024-04-24 13:47:25 +02:00
Tamás Vajk
84ea3a9a2c Merge pull request #16310 from tamasvajk/buildless/nuget_versions
C#: Add integration test with multiple versions of the same nuget pac…
2024-04-24 13:33:27 +02:00
Nick Rolfe
8f2e51faa6 Ruby: do fewer regexp matches in SensitiveActions 2024-04-24 12:32:49 +01:00
Owen Mansel-Chan
f828f8ea65 Merge pull request #16250 from owen-mc/go/rename-untrusted-flow-source
Go: Rename `UntrustedFlowSource` to `RemoteFlowSource` to match other language libraries
2024-04-24 11:37:00 +01:00
Tom Hvitved
95d579d9de Data flow: Fix bad join
```
Evaluated relational algebra for predicate _DataFlowImpl::Impl<HardcodedDataInterpretedAsCodeQuery::HardcodedDataInterpretedAsCodeFlow::C>::ret__#count_range@d112335l with tuple counts:
            285176  ~2%    {3} r1 = SCAN `_DataFlowDispatch::DataFlowCall.getEnclosingCallable/0#dispred#b7b78b19_DataFlowImpl::Impl<Hardcoded__#shared` OUTPUT In.1, In.0, In.2
        3265592261  ~3%    {5}    | JOIN WITH `DataFlowImpl::Impl<HardcodedDataInterpretedAsCodeQuery::HardcodedDataInterpretedAsCodeFlow::C>::returnCallEdge1/4#d02cae42_2301#join_rhs` ON FIRST 2 OUTPUT Lhs.0, Lhs.2, Rhs.2, Lhs.1, Rhs.3
             39070  ~8%    {6}    | JOIN WITH `DataFlowImplCommon::Cached::viableImplInCallContextExt/2#58e931ad` ON FIRST 3 OUTPUT Lhs.0, Lhs.3, Lhs.1, Lhs.2, Lhs.4, _
             39070  ~0%    {6}    | REWRITE WITH Out.5 := 1
                           return r1
```
2024-04-24 12:22:28 +02:00
Tamas Vajk
f3daba510b C#: Fix global.json and packages.config lookup 2024-04-24 11:57:45 +02:00
Tamas Vajk
88e67715a1 C#: Do not download Microsoft.CodeAnalysis.ResxSourceGenerator when there are no resx files to process 2024-04-24 11:53:29 +02:00
Tamas Vajk
53eb753346 C#: Add integration test with multiple versions of the same nuget package 2024-04-24 11:50:43 +02:00
Mathias Vorreiter Pedersen
037114b336 Merge pull request #16309 from geoffw0/newtests
C++: Add test cases
2024-04-24 10:06:51 +01:00
Nick Rolfe
af72c0848e Merge pull request #16306 from github/nickrolfe/js-sensitive
JS: do fewer regexp matches in SensitiveActions
2024-04-24 09:49:44 +01:00
Tamás Vajk
de58ee5a22 Merge pull request #16225 from tamasvajk/buildless/resx
C#: Add resource generator
2024-04-24 10:10:45 +02:00
Tom Hvitved
a1a93c7331 Merge pull request #16304 from hvitved/csharp/fix-bad-join
C#: Fix a bad join
2024-04-24 08:11:25 +02:00
Asger F
db07c162e4 JS: Allow generated models to use (package) 2024-04-23 20:25:55 +02:00
Asger F
9d00f660f1 Update ModelGeneration.expected 2024-04-23 20:08:21 +02:00
Owen Mansel-Chan
0311888fd4 Update change note
Co-authored-by: Michael B. Gale <mbg@github.com>
2024-04-23 19:07:02 +01:00
Asger F
e4f23b31c6 JS: Add quotes around package name to correct parsing 2024-04-23 20:04:23 +02:00
Geoffrey White
57a53891e9 C++: Effect of recent QL changes. 2024-04-23 18:12:05 +01:00
Geoffrey White
b6703bc25c C++: Add test cases inspired by QA results differences. 2024-04-23 18:06:12 +01:00
Nick Rolfe
003d208574 JS: do fewer regexp matches in SensitiveActions 2024-04-23 15:31:38 +01:00
Tom Hvitved
d8d7688f88 C#: Fix another bad join 2024-04-23 15:39:59 +02:00
Anders Schack-Mulligen
830b83f653 Dataflow: Use doublyBoundedFastTC. 2024-04-23 13:07:20 +02:00
Mathias Vorreiter Pedersen
3592e76269 Merge pull request #16302 from MathiasVP/fieldflowbranchlimit-follow-up-1
C++: `fieldFlowBranchLimit` follow-up (1)
2024-04-23 11:35:49 +01:00
Tom Hvitved
6aa4c5c187 C#: Fix a bad join 2024-04-23 11:47:55 +02:00
Michael B. Gale
fb8ee07b43 Merge pull request #16262 from github/dependabot/go_modules/go/ql/integration-tests/all-platforms/go/two-go-mods-not-nested/src/subdir1/golang.org/x/net-0.23.0 2024-04-23 10:44:54 +01:00
Michael B. Gale
4ccff1a630 Merge pull request #16263 from github/dependabot/go_modules/go/ql/integration-tests/all-platforms/go/ninja-sample/src/golang.org/x/net-0.23.0 2024-04-23 10:44:17 +01:00
Michael B. Gale
4b7160d4b2 Merge pull request #16267 from github/dependabot/go_modules/go/ql/integration-tests/all-platforms/go/go-mod-without-version/src/golang.org/x/net-0.23.0 2024-04-23 10:43:43 +01:00
Michael B. Gale
5cce5008a3 Merge pull request #16264 from github/dependabot/go_modules/go/ql/integration-tests/all-platforms/go/single-go-work-not-in-root/src/modules/subdir2/golang.org/x/net-0.23.0 2024-04-23 10:42:53 +01:00
Michael B. Gale
5b6ce56ca2 Merge pull request #16268 from github/dependabot/go_modules/go/ql/integration-tests/all-platforms/go/single-go-mod-not-in-root/src/subdir/golang.org/x/net-0.23.0 2024-04-23 10:42:24 +01:00
Michael B. Gale
2b81b6c323 Merge pull request #16265 from github/dependabot/go_modules/go/ql/integration-tests/all-platforms/go/mixed-layout/src/module/golang.org/x/net-0.23.0 2024-04-23 10:41:50 +01:00
Mathias Vorreiter Pedersen
a39d8b7c7c C++: Ensure that each node type gets mapped to an instruction by 'getAnInstruction'. 2024-04-23 09:44:30 +01:00
Rasmus Wriedt Larsen
1bc085c8f7 Python: Fixup for callGraphConfig 2024-04-23 09:42:35 +02:00
Rasmus Wriedt Larsen
bb00d6919a Python: Move dataflow TestUtil to importable location 2024-04-23 09:40:59 +02:00
Rasmus Wriedt Larsen
e0e405bb31 Python: replace dataflow-test location in files 2024-04-23 09:40:59 +02:00
Rasmus Wriedt Larsen
ce711f7d2f Python: Move dataflow tests out of experimental 2024-04-23 09:40:44 +02:00
Tamas Vajk
f20812d8ad Code quality improvement 2024-04-22 15:12:01 +02:00
Tamas Vajk
05f3c64172 Fix code review findings 2024-04-22 14:46:24 +02:00
dependabot[bot]
dae187eb0b Bump golang.org/x/net
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.0.0-20200505041828-1ed23360d12c to 0.23.0.
- [Commits](https://github.com/golang/net/commits/v0.23.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-19 09:46:00 +00:00
dependabot[bot]
7f195d0257 Bump golang.org/x/net
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.0.0-20200505041828-1ed23360d12c to 0.23.0.
- [Commits](https://github.com/golang/net/commits/v0.23.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-19 09:46:00 +00:00
dependabot[bot]
a8162baada Bump golang.org/x/net
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.0.0-20200505041828-1ed23360d12c to 0.23.0.
- [Commits](https://github.com/golang/net/commits/v0.23.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-19 09:46:00 +00:00
dependabot[bot]
ef53184c10 Bump golang.org/x/net
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.0.0-20200505041828-1ed23360d12c to 0.23.0.
- [Commits](https://github.com/golang/net/commits/v0.23.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-19 09:45:59 +00:00
dependabot[bot]
9d38c255f5 Bump golang.org/x/net
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.0.0-20200505041828-1ed23360d12c to 0.23.0.
- [Commits](https://github.com/golang/net/commits/v0.23.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-19 09:45:58 +00:00
dependabot[bot]
4de4525528 Bump golang.org/x/net
Bumps [golang.org/x/net](https://github.com/golang/net) from 0.0.0-20200505041828-1ed23360d12c to 0.23.0.
- [Commits](https://github.com/golang/net/commits/v0.23.0)

---
updated-dependencies:
- dependency-name: golang.org/x/net
  dependency-type: direct:production
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-04-19 09:45:57 +00:00
Owen Mansel-Chan
79b4890794 Also rename .expected files 2024-04-18 14:17:04 +01:00
Owen Mansel-Chan
dc985c2c98 Add change note 2024-04-18 12:55:59 +01:00
Owen Mansel-Chan
b6f6bdc6f4 Make RemoteFlowAsSource private
`UntrustedFlowAsSource` should have been private. Since we are deprecating them anyway
we may as well make the replacement private (and make it use `instanceof`). The deprecation
comments have been updated.
2024-04-18 12:31:38 +01:00
Owen Mansel-Chan
a49b43fdf6 Add deprecated version of renamed public classes 2024-04-18 11:49:54 +01:00
Owen Mansel-Chan
317c335269 Rename test query files 2024-04-18 11:49:42 +01:00
Owen Mansel-Chan
db06c08141 Rename UntrustedSource to RemoteSource
Including renaming some files (in the experimental folder).
2024-04-18 11:49:30 +01:00
Owen Mansel-Chan
f39301f533 Fix "an remote" and similar
Preserve case, allow for "a `Remote" etc.
2024-04-18 11:49:18 +01:00
Owen Mansel-Chan
a6646021d0 Rename Untrusted Flow to Remote Flow
Not matching case but preserving original case.
2024-04-18 11:49:05 +01:00
Owen Mansel-Chan
d967b2baa3 Rename UntrustedFlowAsSource to RemoteFlowAsSource 2024-04-18 11:48:04 +01:00
Owen Mansel-Chan
a4df20da85 Rename UntrustedFlowSource to RemoteFlowSource
Relaxed match case requirement. Again skipped one instance in an old
change note.
2024-04-17 21:40:46 +01:00
Owen Mansel-Chan
81eaa6e327 Rename UntrustedFlowSource to RemoteFlowSource
Relaxed whole word requirement. Again skipped one instance in an old
change note.
2024-04-17 21:35:50 +01:00
Owen Mansel-Chan
5fba9895c6 Rename UntrustedFlowSource to RemoteFlowSource
Only the whole word. Skipped one instance in an old change note.
2024-04-17 21:27:32 +01:00
Asger F
64321b314f Merge branch 'main' into js-extractor-fix 2024-04-17 20:55:54 +02:00
Tamas Vajk
7b5f2c7d94 Fix expected test result on Windows 2024-04-17 15:12:51 +02:00
Tamas Vajk
41e666c724 Parse and use RootNamespace from project files 2024-04-17 14:01:52 +02:00
Tamas Vajk
88f6e04339 Make Resx extraction opt-in 2024-04-17 13:49:05 +02:00
Tamas Vajk
b560ab1a73 Fix condition for running dotnet source generators 2024-04-17 13:44:03 +02:00
Tamas Vajk
3626c814ac Run dotnet source generators on files grouped by projects 2024-04-17 13:40:03 +02:00
Tamas Vajk
bef556e208 Improve log messages 2024-04-17 11:46:27 +02:00
Tamas Vajk
5a5fc79b3b Fix regex to recognize prerelease version string 2024-04-17 11:46:27 +02:00
Tamas Vajk
9926c817de Code quality improvements 2024-04-17 11:46:26 +02:00
Tamas Vajk
53902c824d Fix integration tests 2024-04-17 11:46:26 +02:00
Tamas Vajk
3c5675b3fb WIP: Hardcode namespace for Resx generation 2024-04-17 11:46:26 +02:00
Tamas Vajk
3154a11b43 List members in resx test 2024-04-17 10:47:44 +02:00
Tamas Vajk
1ff4c0daf3 Restore and use Microsoft.CodeAnalysis.ResxSourceGenerator 2024-04-17 10:41:47 +02:00
Chad Bentz
f77f91ef49 move security-severity to end of column list in csv
Co-authored-by: Rasmus Wriedt Larsen <rasmuswriedtlarsen@gmail.com>
2024-04-16 16:02:15 -04:00
Tamas Vajk
79fe5f851b C#: Add resource generator 2024-04-16 14:30:53 +02:00
Tamas Vajk
407837afc4 C#: Refactor dotnet source generator execution 2024-04-16 10:20:23 +02:00
Chad Bentz
78ddb998a2 Merge branch 'main' into patch-1 2024-04-12 09:09:43 -04:00
Rasmus Wriedt Larsen
f33222c83b JS: Add change-note 2024-04-02 11:10:53 +02:00
Rasmus Wriedt Larsen
df463e51c1 JS: Extractor: Fix experimental flag value for NodeJSDetectorTests 2024-03-26 17:02:47 +01:00
Rasmus Wriedt Larsen
60944a9bcb JS: Accept new trap files
As I see it, these all seem to have invalid code initially anyway, but
this is definitely something a JS expert should review :)
2024-03-26 17:01:57 +01:00
Rasmus Wriedt Larsen
1d51d182ec JS: Extractor: Explain how to make replaceExpectedOutput work now with bazel 2024-03-26 17:01:57 +01:00
Rasmus Wriedt Larsen
04a0740ccb JS: Extractor: More robust ES2015 checking
Created shared AbstractDetector to not duplicate all the tedious logic
;)

I took inspiration from the tests in  `javascript/extractor/tests/esnext/input/dynamic-import.js`
2024-03-26 17:01:57 +01:00
Rasmus Wriedt Larsen
cd84500c56 JS: Extractor: Separate base detector logic into own file
Should hopefully make it easier to review these changes to have it split into its' own commit :)
2024-03-26 17:01:57 +01:00
Rasmus Wriedt Larsen
0515b12305 JS: Add example of bad NodeJS detection
Notice the TRAP lines

```
is_module(#20001)
is_es2015_module(#20001)
```
2024-03-25 11:36:21 +01:00
Chad Bentz
b12f4d97f8 Merge branch 'main' into patch-1 2024-01-17 09:25:28 -05:00
Chad Bentz
ee3085e15e Update generate-code-scanning-query-list.py 2023-12-14 14:09:14 -05:00
Chad Bentz
53e96e5adf Merge branch 'main' into patch-1 2023-10-25 10:00:16 -04:00
Chad Bentz
6f60eb9e1a Merge branch 'main' into patch-1 2023-08-09 14:31:26 -04:00
Chad Bentz
845f384df6 Merge branch 'main' into patch-1 2023-08-04 17:57:53 -04:00
Chad Bentz
39c52c9ecf add security-severity to code scanning query list 2023-03-16 11:27:23 -04:00
791 changed files with 7745 additions and 3997 deletions

View File

@@ -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
View 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
View 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
View 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

View File

@@ -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?$

View File

@@ -0,0 +1,9 @@
load("@buildifier_prebuilt//:rules.bzl", "buildifier")
buildifier(
name = "buildifier",
exclude_patterns = [
"./.git/*",
],
lint_mode = "fix",
)

View File

@@ -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(

View File

@@ -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"
]
}
}

View File

@@ -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.

View File

@@ -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.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* Parameters of functions without definitions now have `ParameterNode`s.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* Source models have been added for the standard library function `getc` (and variations).

View File

@@ -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.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* Source, sink and flow models for the ZeroMQ (ZMQ) networking library have been added.

View 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.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.12.11
lastReleaseVersion: 0.13.0

View File

@@ -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

View File

@@ -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

View File

@@ -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()
}

View File

@@ -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
)
}
}

View File

@@ -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

View File

@@ -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

View File

@@ -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 |

View File

@@ -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() }
}

View File

@@ -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.
*/

View File

@@ -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`.
*

View File

@@ -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() }
}

View File

@@ -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.
*/

View File

@@ -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

View File

@@ -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 {

View File

@@ -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) {

View File

@@ -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() }
}

View File

@@ -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.
*/

View File

@@ -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`.
*

View File

@@ -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
}
}

View File

@@ -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)
}

View File

@@ -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.

View File

@@ -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>;

View File

@@ -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>

View File

@@ -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."

View File

@@ -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`.
}
}

View File

@@ -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>

View File

@@ -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."

View File

@@ -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.

View File

@@ -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.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.9.10
lastReleaseVersion: 0.9.11

View File

@@ -0,0 +1,11 @@
void test()
{
char *foo = malloc(100);
// BAD
if (foo)
free(foo);
// GOOD
free(foo);
}

View 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>

View 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"

View File

@@ -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 |

View File

@@ -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()

View File

@@ -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()

View File

@@ -1,4 +0,0 @@
import cpp
from Function fn
where not exists(fn.getDeclaringType()) and is_relevant_result(fn.getFile())

View File

@@ -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()

View File

@@ -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()

View File

@@ -1,6 +0,0 @@
import cpp
predicate is_relevant_result(File file)
{
not file.getRelativePath().matches("c/extractor/edg%")
}

View File

@@ -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

View File

@@ -1,5 +1,5 @@
name: codeql/cpp-queries
version: 0.9.11-dev
version: 0.9.12-dev
groups:
- cpp
- queries

View File

@@ -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 |

View File

@@ -1 +0,0 @@
experimental/Security/CWE/CWE-416/IteratorToExpiredContainer.ql

View File

@@ -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 |

View File

@@ -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 | ... != ... |

View File

@@ -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 |

View File

@@ -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 |

View File

@@ -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 |

View File

@@ -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, _)
)
}

View File

@@ -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) {
}
}

View File

@@ -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);
}
}

View File

@@ -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 | * ... |

View File

@@ -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
}
}

View File

@@ -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<>

View File

@@ -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
}
}

View File

@@ -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>:

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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 |

View File

@@ -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(), " "
)

View File

@@ -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)

View File

@@ -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(), ", ")

View File

@@ -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 |

View File

@@ -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

View File

@@ -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 |

View File

@@ -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 |

View File

@@ -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 |

View File

@@ -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
}

View File

@@ -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)
}

View File

@@ -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) |

View File

@@ -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);

View File

@@ -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+");
}

View File

@@ -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. |

View File

@@ -0,0 +1 @@
Security/CWE/CWE-416/IteratorToExpiredContainer.ql

View File

@@ -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. |

View File

@@ -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 | |

View File

@@ -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

View File

@@ -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;
});
}
}

View File

@@ -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