Compare commits

..

430 Commits

Author SHA1 Message Date
Jean Helie
c080ee92fd ML: update expected tests outputs 2022-04-08 13:46:37 +02:00
Jean Helie
7a95c4a465 ML: add defensive check to ensure Unknown endpoints cannot also be NotASink 2022-04-08 13:46:37 +02:00
Asger F
e5f2b830f3 Merge pull request #8577 from asgerf/fix-mad-warning
JS/Ruby: Fix regexp in MaD checking
2022-03-28 15:29:16 +02:00
Asger F
f22df765ed Merge pull request #8533 from asgerf/mad-receiver-token
JS/Ruby: Represent non-positional arguments with Argument/Parameter tokens
2022-03-28 15:28:52 +02:00
Asger Feldthaus
0b30ecf36a Ruby: add select clause back to Summaries.ql 2022-03-28 13:57:50 +02:00
Asger Feldthaus
d5bcd14733 Sync ApiGraphModels.qll 2022-03-28 12:43:55 +02:00
Asger Feldthaus
7e6206ed36 JS: Fix the regexp for valid MaD token arguments 2022-03-28 12:43:43 +02:00
Arthur Baars
af1d949d06 Merge pull request #8489 from aibaars/regex-refactor
Ruby: refactor regex libraries
2022-03-28 12:17:00 +02:00
Erik Krogh Kristensen
c98d024c0e Merge pull request #8575 from erik-krogh/qlFixTypo
QL: fix Import::getImportString
2022-03-28 11:41:59 +02:00
Arthur Baars
accdd9499a Ruby: drop unused predicates that do not exist in Python variant 2022-03-28 11:32:52 +02:00
Erik Krogh Kristensen
7ac6f5849c fix Import::getImportString 2022-03-28 11:04:18 +02:00
Mathias Vorreiter Pedersen
57c39e9642 Merge pull request #8574 from erik-krogh/qlForQlFixes
QL: two small improvements
2022-03-28 09:26:43 +01:00
Erik Krogh Kristensen
77aff04429 add a getImportString utility predicate to Import 2022-03-28 10:14:27 +02:00
Erik Krogh Kristensen
d4c8f42336 add QLDoc to the child relation for TopLevel 2022-03-28 09:54:08 +02:00
yoff
5efc19c39d Merge pull request #7806 from erik-krogh/pyDef
Python: Add def nodes to API graphs
2022-03-28 08:09:14 +02:00
Edoardo Pirovano
8faabb837a Merge pull request #8561 from erik-krogh/latestTools
QL: use latest tools in codeql-action/init
2022-03-25 15:12:58 -04:00
Erik Krogh Kristensen
21192b7593 use latest tools in codeql-action/init 2022-03-25 19:26:10 +01:00
Andrew Eisenberg
5fb84a774b Merge pull request #8553 from github/aeisenberg/cpp-suites
Suites: Remove self-referential `from` directives
2022-03-25 09:15:53 -07:00
Michael Nebel
79f3da8af1 Merge pull request #8506 from michaelnebel/java/generalize-generate-flow-model
Java/C#: Generalize script for generating flow models.
2022-03-25 16:20:53 +01:00
Geoffrey White
2014599f88 Merge pull request #8318 from geoffw0/cwe497b
C++: New query cpp/potential-system-data-exposure
2022-03-25 14:55:00 +00:00
Taus
b75ac4e827 Merge pull request #8540 from tausbn/python-add-points-to-call-graph-meta-query
Python: Add call graph meta-query
2022-03-25 15:36:33 +01:00
Erik Krogh Kristensen
9e71d9bada Merge pull request #8556 from erik-krogh/bumpAction
QL: update codeql-action version in QL-for-QL
2022-03-25 14:46:31 +01:00
Erik Krogh Kristensen
68c07fe1c0 pin the commit of codeql-action in the remaining steps/workflows 2022-03-25 14:35:44 +01:00
Erik Krogh Kristensen
8f377f4101 pin the commit
Co-authored-by: Esben Sparre Andreasen <esbena@github.com>
2022-03-25 14:19:29 +01:00
Erik Krogh Kristensen
cf57eb825c update codeql-action version in QL-for-QL 2022-03-25 13:37:27 +01:00
Taus
d56caa2398 Merge pull request #8547 from RasmusWL/regexstring-imports
Python: Import framework-modeling in `regex.qll`
2022-03-25 13:26:04 +01:00
Geoffrey White
9f3fd57534 Merge branch 'main' into cwe497b 2022-03-25 11:57:30 +00:00
Mathias Vorreiter Pedersen
c115c68247 Merge pull request #8542 from MathiasVP/public-iterated-dominance-frontier
C++: Use `iterated (post)dominance frontier` algorithm in `IRBlock`
2022-03-25 11:51:15 +00:00
Jeroen Ketema
b91914bd89 Merge pull request #8534 from jketema/bitwise-ctor-field-init
C++: Handle bitwise copies in copy constructors
2022-03-25 12:47:57 +01:00
Geoffrey White
e377eebdbc C++: More 'adversary' -> 'malicious user' and related doc changes. 2022-03-25 11:34:37 +00:00
Geoffrey White
11074b6d77 Update cpp/ql/src/Security/CWE/CWE-497/PotentiallyExposedSystemData.ql
Co-authored-by: mc <42146119+mchammer01@users.noreply.github.com>
2022-03-25 11:08:07 +00:00
Geoffrey White
6b6ee61d3f Apply suggestions from code review
Co-authored-by: mc <42146119+mchammer01@users.noreply.github.com>
2022-03-25 11:06:46 +00:00
Jeroen Ketema
94f014d948 C++: Update tests for handling of bitwise copies in copy constructors 2022-03-25 11:43:01 +01:00
Jeroen Ketema
b18b86b2e2 C++: Remove check for value-less literals in constructors 2022-03-25 11:43:01 +01:00
Chris Smowton
f0168d00d1 Merge pull request #8529 from github/smowton/admin/commons-lang3-test-typo
Java: Fix harmless search-replace mistake
2022-03-25 10:36:00 +00:00
Asger Feldthaus
8e2ffc2508 Ruby: add the inline test expectations 2022-03-25 11:31:22 +01:00
Asger Feldthaus
5703f63afa Ruby: use InlineFlowTest in Summaries.ql test 2022-03-25 11:18:52 +01:00
Erik Krogh Kristensen
cf94c93b1a Merge pull request #8481 from erik-krogh/schemeChain
JS: recognize string replacement chains as scheme checks in js/incomplete-url-scheme-check
2022-03-25 11:13:10 +01:00
Andrew Eisenberg
99f14af56a Suites: Remove self-referential from directives
Fixes https://github.com/github/codeql/issues/8412

See https://github.com/github/codeql/issues/8412#issuecomment-1078281668
for more detail.
2022-03-24 14:19:20 -07:00
Tom Hvitved
e12b6df118 Merge pull request #8484 from hvitved/ruby/constant-value-rework
Ruby: Rework `getConstantValue` implementation
2022-03-24 14:32:31 +01:00
Rasmus Wriedt Larsen
d51aaf2f91 Python: Import framework-modeling in regex.qll 2022-03-24 14:28:44 +01:00
Mathias Vorreiter Pedersen
80630972b1 Merge branch 'main' into public-iterated-dominance-frontier 2022-03-24 12:50:29 +00:00
Rasmus Wriedt Larsen
98c0d73ffe Merge pull request #8524 from RasmusWL/ruby-update-ssrf-concept
Ruby: Minor change of SSRF concept
2022-03-24 13:48:06 +01:00
Chris Smowton
005a020f04 Merge pull request #8508 from igfoo/igfoo/error_elements
Java: Add ErrorExpr, ErrorStmt
2022-03-24 10:39:14 +00:00
Arthur Baars
15801fcc85 Apply suggestions from code review
Co-authored-by: Nick Rolfe <nickrolfe@github.com>
2022-03-24 11:37:03 +01:00
Arthur Baars
eef0da09bb Ruby: move RegExpTreeView.qll out of 'internal' 2022-03-24 11:37:03 +01:00
Arthur Baars
1a9aaf4543 Apply suggestions from code review
Co-authored-by: yoff <lerchedahl@gmail.com>
2022-03-24 11:37:03 +01:00
Arthur Baars
5f787144c0 Add change note 2022-03-24 11:37:03 +01:00
Arthur Baars
3c434931ec Ruby: make ParseRegExp.qll and RegExpTreeView.qll internal libraries 2022-03-24 11:37:03 +01:00
Arthur Baars
74aea81fe3 Ruby: refactor regex libraries 2022-03-24 11:37:02 +01:00
Arthur Baars
496aab78a7 Merge pull request #8535 from aibaars/setter-method-arg-location
Ruby: fix location of setter-call argument
2022-03-24 11:26:13 +01:00
Tom Hvitved
eff7cf6396 Merge pull request #8538 from hvitved/ruby/regexpterm-location-perf
Ruby: Fix bad join-order in `RegExpTerm::hasLocationInfo`
2022-03-24 10:01:12 +01:00
Tom Hvitved
2699412160 Merge pull request #8543 from hmac/hmac/test-naming-fix
Ruby: Fix bad name of lambda in test
2022-03-24 09:46:04 +01:00
Harry Maclean
28a430a2f2 Ruby: Fix bad name of lambda in test
This isn't the identity function, so it's confusing for it to be named
so.
2022-03-24 12:44:41 +13:00
Harry Maclean
3b4206cebf Merge pull request #8517 from hmac/hmac/lambda-captured-var
Ruby: fix bug with captured variable reads in lambdas
2022-03-24 10:00:19 +13:00
Mathias Vorreiter Pedersen
61c944201f Merge pull request #8461 from Paul1nh0/dev_cve_2016_6480
Add query for double-fetch vulnerability
2022-03-23 18:15:05 +00:00
Asger Feldthaus
b0b795dbbb JS: Autoformat 2022-03-23 19:15:01 +01:00
Mathias Vorreiter Pedersen
c76a323246 C++/C#: Sync identical files. 2022-03-23 17:27:25 +00:00
Mathias Vorreiter Pedersen
1b4fb45089 C++: Use the iterated (post)dominance frontier algorithm in the public '(post)dominanceFrontier' predicate on 'IRBlocks'. 2022-03-23 17:27:16 +00:00
Asger Feldthaus
69eb24e748 Ruby: fix toCsv representation of argument/parameter positions 2022-03-23 18:11:09 +01:00
Asger Feldthaus
6870a19ace Ruby: autoformat 2022-03-23 18:06:12 +01:00
Asger Feldthaus
0d51804b5e Ruby: update a comment mentioning Receiver 2022-03-23 18:06:12 +01:00
Asger Feldthaus
ce54eb3c78 Ruby: Add Argument[foo:] syntax for keyword arguments 2022-03-23 18:06:12 +01:00
Asger Feldthaus
c923b9bb9b Ruby: Replace Receiver with Argument[self] 2022-03-23 18:06:12 +01:00
Asger Feldthaus
ec30a0f975 Ruby: replace BlockArgument with Argument[block] 2022-03-23 18:06:12 +01:00
Asger Feldthaus
6d84baf276 Ruby: Support self,block in Argument/Parameter tokens 2022-03-23 18:06:12 +01:00
Asger Feldthaus
95122b2b6c JS: Support Argument[this] token 2022-03-23 18:06:12 +01:00
Asger Feldthaus
d476f976fe JS: Support Parameter[this] token 2022-03-23 18:06:12 +01:00
Taus
af888f7604 Python: Add call graph meta-query 2022-03-23 16:36:28 +00:00
CodeQL CI
ac29d5f51b Merge pull request #8523 from asgerf/js/api-graph-receiver-label
Approved by erik-krogh
2022-03-23 15:31:12 +00:00
Mathias Vorreiter Pedersen
8b8f0ca6e5 Merge pull request #8479 from geoffw0/widecharperf
C++: Fix expensive getWideCharType().
2022-03-23 14:22:17 +00:00
Anna Railton
41418e729e Merge pull request #8536 from github/codeql-ci/js-atm-new-release
JS: Bump version numbers of ML-powered packs after 0.2.0 release
2022-03-23 14:16:11 +00:00
Tom Hvitved
13be99196f Ruby: Fix bad join-order in RegExpTerm::hasLocationInfo
Before:
```
[2022-03-23 14:50:16] (776s) Tuple counts for RegExpTreeView::RegExpTerm::hasLocationInfo#dispred#f0820431#ffffff/6@5f6cf7if after 1m4s:
                      707103    ~7%     {2} r1 = SCAN Literal::StringlikeLiteral::getNumberOfComponents#dispred#f0820431#ff OUTPUT In.0, (In.1 - 1)
                      64721     ~0%     {5} r2 = JOIN r1 WITH RegExpTreeView::RegExpTerm#7783c185#ffff_1023#join_rhs ON FIRST 1 OUTPUT Lhs.0, Lhs.1, Rhs.1 'this', Rhs.2, Rhs.3
                      64721     ~0%     {5} r3 = JOIN r2 WITH Literal::StringlikeLiteral::getComponent#dispred#f0820431#fff ON FIRST 2 OUTPUT Rhs.2, Lhs.0, Lhs.2 'this', Lhs.3, Lhs.4
                      64721     ~0%     {5} r4 = JOIN r3 WITH AST::AstNode::getLocation#dispred#f0820431#bf ON FIRST 1 OUTPUT Rhs.1, Lhs.1, Lhs.2 'this', Lhs.3, Lhs.4
                      64721     ~3%     {6} r5 = JOIN r4 WITH Locations::Location::hasLocationInfo#dispred#f0820431#ffffff ON FIRST 1 OUTPUT Rhs.1 'filepath', Lhs.1, Lhs.2 'this', Lhs.3, Lhs.4, Rhs.4 'endline'
                      353247577 ~1%     {10} r6 = JOIN r5 WITH Locations::Location::hasLocationInfo#dispred#f0820431#ffffff_1023#join_rhs ON FIRST 1 OUTPUT Lhs.1, 0, Lhs.2 'this', Lhs.3, Lhs.4, Lhs.0 'filepath', Lhs.5 'endline', Rhs.1, Rhs.2 'startline', Rhs.3
                      353247577 ~0%     {9} r7 = JOIN r6 WITH Literal::StringlikeLiteral::getComponent#dispred#f0820431#fff ON FIRST 2 OUTPUT Rhs.2, Lhs.7, Lhs.2 'this', Lhs.3, Lhs.4, Lhs.5 'filepath', Lhs.6 'endline', Lhs.8 'startline', Lhs.9
                      64721     ~2%     {6} r8 = JOIN r7 WITH AST::AstNode::getLocation#dispred#f0820431#bf ON FIRST 2 OUTPUT Lhs.2 'this', Lhs.5 'filepath', Lhs.7 'startline', (Lhs.8 + Lhs.3), Lhs.6 'endline', ((Lhs.8 + Lhs.4) - 1)
                                        return r8
```

After:
```
[2022-03-23 14:58:35] (247s) Tuple counts for RegExpTreeView::RegExpTerm::componentHasLocationInfo#f0820431#fbfffff/7@de55ac7l after 1.1s:
                      12956   ~0%     {3} r1 = SCAN files OUTPUT In.0, 0, In.1 'filepath'
                      9850785 ~0%     {7} r2 = JOIN r1 WITH locations_default_102345#join_rhs ON FIRST 1 OUTPUT Rhs.1, 0, Lhs.2 'filepath', Rhs.2 'startline', Rhs.3 'startcolumn', Rhs.4 'endline', Rhs.5 'endcolumn'
                      823486  ~0%     {8} r3 = JOIN r2 WITH AST::AstNode::getLocation#dispred#f0820431#bf_10#join_rhs ON FIRST 1 OUTPUT 0, Rhs.1, 0, Lhs.2 'filepath', Lhs.3 'startline', Lhs.4 'startcolumn', Lhs.5 'endline', Lhs.6 'endcolumn'
                      698251  ~4%     {7} r4 = JOIN r3 WITH Literal::StringlikeLiteral::getComponent#dispred#f0820431#fff_120#join_rhs ON FIRST 2 OUTPUT Rhs.2, 0, Lhs.3 'filepath', Lhs.4 'startline', Lhs.5 'startcolumn', Lhs.6 'endline', Lhs.7 'endcolumn'
                      64721   ~1%     {7} r5 = JOIN r4 WITH RegExpTreeView::RegExpTerm#7783c185#ffff_10#join_rhs ON FIRST 1 OUTPUT Rhs.1 'this', 0, Lhs.2 'filepath', Lhs.3 'startline', Lhs.4 'startcolumn', Lhs.5 'endline', Lhs.6 'endcolumn'
                                      return r5

[2022-03-23 14:58:35] (247s) Tuple counts for RegExpTreeView::RegExpTerm::hasLocationInfo#dispred#f0820431#ffffff/6@ad66b12q after 53ms:
                      707103 ~7%     {2} r1 = SCAN Literal::StringlikeLiteral::getNumberOfComponents#dispred#f0820431#ff OUTPUT In.0, (In.1 - 1)
                      64721  ~0%     {4} r2 = JOIN r1 WITH RegExpTreeView::RegExpTerm#7783c185#ffff_1023#join_rhs ON FIRST 1 OUTPUT Rhs.1 'this', Lhs.1, Rhs.2, Rhs.3
                      64721  ~5%     {5} r3 = JOIN r2 WITH project#RegExpTreeView::RegExpTerm::componentHasLocationInfo#f0820431#bffffff ON FIRST 2 OUTPUT Lhs.0 'this', Rhs.2 'filepath', Lhs.2, Lhs.3, Rhs.3 'endline'
                      64721  ~2%     {6} r4 = JOIN r3 WITH project#RegExpTreeView::RegExpTerm::componentHasLocationInfo#f0820431#fbfffff ON FIRST 2 OUTPUT Lhs.0 'this', Lhs.1 'filepath', Rhs.2 'startline', (Rhs.3 + Lhs.2), Lhs.4 'endline', ((Rhs.3 + Lhs.3) - 1)
                                     return r4
```
2022-03-23 14:55:06 +01:00
Geoffrey White
9ae1ec69dc C++: Autoformat. 2022-03-23 13:37:39 +00:00
Michael Nebel
6804e20e4a Merge pull request #8451 from michaelnebel/csharp/modelgenerator-improvements
C#: Model generator improvements and more tests
2022-03-23 13:30:58 +01:00
Arthur Baars
06a99c3987 Ruby: fix location of setter-call argument 2022-03-23 12:55:52 +01:00
github-actions[bot]
1e620c99c6 JS: Bump patch version of ML-powered library and query packs post-release 2022-03-23 11:53:34 +00:00
github-actions[bot]
dc0c8374d2 JS: Bump minor version of ML-powered library and query packs 2022-03-23 11:47:53 +00:00
github-actions[bot]
2b42d84ccd JS: Bump patch version of ML-powered model pack post-release 2022-03-23 11:47:53 +00:00
github-actions[bot]
6fbc0e6e32 JS: Bump ML model pack dependency of ML-powered model building and query packs 2022-03-23 11:47:53 +00:00
github-actions[bot]
8d13662315 JS: Bump minor version of ML-powered model pack 2022-03-23 11:47:08 +00:00
yoff
647d37492d Merge pull request #8289 from tausbn/python-remove-with-test-syntax-error
Python: Fix syntax error in `with` test output
2022-03-23 12:25:11 +01:00
Mathias Vorreiter Pedersen
a81024a485 Merge pull request #8525 from MathiasVP/more-precise-is-before
C++: Consider columns in `Location.isBefore`
2022-03-23 11:04:34 +00:00
Mathias Vorreiter Pedersen
0eab54d385 Merge pull request #8491 from jketema/command-line-injection-with-flow-state
C++: Use flow states in `cpp/command-line-injection`
2022-03-23 11:03:29 +00:00
Michael Nebel
b204f783fb C#: Remove special handling of bulk types. 2022-03-23 11:26:49 +01:00
Rasmus Wriedt Larsen
671889372b Ruby: Update wording of change-note
Co-authored-by: Nick Rolfe <nickrolfe@github.com>
2022-03-23 11:26:41 +01:00
Rasmus Wriedt Larsen
e66932c728 Ruby: Make deprecated getURL work with new modeling
So an "old" query using the deprecated predicate, will still find the
same results, even when the modeling has been updated.
2022-03-23 11:22:34 +01:00
Tom Hvitved
4bcd4d75a9 Address review comments 2022-03-23 11:22:25 +01:00
Asger Feldthaus
f2285709bd JS: Change note 2022-03-23 10:42:51 +01:00
Asger Feldthaus
59d5c54432 JS: Update test output from knex 2022-03-23 10:42:51 +01:00
Asger Feldthaus
73071bdc08 JS: Change getAParameter to not return the receiver 2022-03-23 10:42:51 +01:00
Asger Feldthaus
6bef5a70b3 JS: Add dedicated API graph label for receiver, instead of parameter -1 2022-03-23 10:42:51 +01:00
Mathias Vorreiter Pedersen
a84ee50af0 Update cpp/ql/src/change-notes/2022-03-21-command-line-injection-with-flow-states.md 2022-03-23 09:35:41 +00:00
Michael Nebel
bbe28bc668 Java: Do not explicitly require python3 when executing the GenerateFlowModel.py. 2022-03-23 10:35:32 +01:00
Michael Nebel
7eddc1e7ec Java: Adjust scripts for new location. 2022-03-23 10:35:32 +01:00
Michael Nebel
7fc11be787 Java: Move generate_flow_model file into a shared models-as-data script folder. 2022-03-23 10:35:32 +01:00
Michael Nebel
bd89de3c43 Java: Make sure to use python3 during workflow execution (required for python string interpolation). 2022-03-23 10:35:32 +01:00
Michael Nebel
6c9d1a3edb Java: Make standalone library for shared functionality. 2022-03-23 10:35:32 +01:00
Michael Nebel
9564f8bf5c Java: Put remainings parts of the generator code into the class. 2022-03-23 10:35:32 +01:00
Michael Nebel
20414c0e56 Java: Move Generator creation into class definition. 2022-03-23 10:35:32 +01:00
Michael Nebel
3f33cdf688 Java: Introduce generator class. 2022-03-23 10:35:32 +01:00
Michael Nebel
6ed1424679 Java: Refactor language specific parts into variable. 2022-03-23 10:35:32 +01:00
Michael Nebel
1ac988323a Java: Add dry-run optional paramteter to generator script. 2022-03-23 10:35:31 +01:00
Michael Nebel
586fd5a43b Java: Rename file for generating flow models. 2022-03-23 10:35:31 +01:00
Rasmus Wriedt Larsen
bbf60b875e Merge pull request #8476 from RasmusWL/shared-concepts-scaffolding
Python/JS/Ruby: Shared concepts scaffolding
2022-03-23 10:22:42 +01:00
Paul1nh0
5a1dc61d9d modify arguments check logic
As far as I can tell, root cause of double-fetech issue is read from the same user mode memory twice, so it makes sense that only check whether user mode pointer is same or not
2022-03-23 11:20:08 +08:00
Paul1nh0
6a6cd61d83 automated using CodeQL for VSCode extension 2022-03-23 09:37:45 +08:00
Mathias Vorreiter Pedersen
01929d484e Merge pull request #8526 from MathiasVP/internal-diagmetric-queries-ql
C++: Add internal `ExtractionError` query
2022-03-22 17:26:38 +00:00
Owen Mansel-Chan
efc0d95535 Merge pull request #8528 from github/smowton/admin/fix-go-doc-links
Fix broken links
2022-03-22 16:25:41 +00:00
Taus
f9120167b4 Python: Fix syntax error in with test output
Depends on an internal PR. The two lines in question were caused by
the insertion of an extra node due to the failure to parse a trailing
comma corrcetly.
2022-03-22 16:22:03 +00:00
Rasmus Wriedt Larsen
64a5c5d9aa Ruby: Keep getURL predicate for easier deprecation
Notice that we still don't fully keep our standard deprecation support,
since the new `getAUrlPart` is still abstract, and therefore will cause
compile errors if not implemented.
2022-03-22 16:48:14 +01:00
Paul1nh0
f2728f5284 delete some unused code 2022-03-22 23:20:30 +08:00
Chris Smowton
b5c05a580d Java: Fix harmless search-replace mistake 2022-03-22 14:42:09 +00:00
yoff
47e062cfb9 Merge pull request #8486 from aibaars/incomplete-hostname-python
Python: switch to shared implementation of IncompleteHostnameRegExp.ql
2022-03-22 15:06:14 +01:00
Erik Krogh Kristensen
8ae04e04d4 Merge pull request #8509 from erik-krogh/fpXss
JS: filter away reads of .src that end in a URL sink for js/xss-through-dom
2022-03-22 14:51:17 +01:00
Mathias Vorreiter Pedersen
c35b385383 C++: Fix 'implicit this' warning. 2022-03-22 13:32:46 +00:00
Tom Hvitved
c06508570a Ruby: Cache ConstantReadAccess::getValue 2022-03-22 14:15:07 +01:00
Paul1nh0
afe4a8435f Using globalValueNumber to match same arguments 2022-03-22 21:14:07 +08:00
Chris Smowton
35af797683 Fix broken links 2022-03-22 12:34:22 +00:00
Mathias Vorreiter Pedersen
93346a574f C++: Add a new 'Location.isBefore' predicate that also considers columns. 2022-03-22 12:16:53 +00:00
Mathias Vorreiter Pedersen
c6c3206031 C++: Add example of 'goto' on the same line as the destination label. 2022-03-22 12:11:29 +00:00
Mathias Vorreiter Pedersen
5cdf0b5ee2 Merge pull request #8507 from geoffw0/sde-perf
C++: Make getUnderlyingType nomagic
2022-03-22 11:12:44 +00:00
Paul1nh0
d476493c3e Add double-fetch.ql under CWE-362 directory 2022-03-22 19:08:44 +08:00
Paul1nh0
dd4e82126c remove to another directory 2022-03-22 19:06:53 +08:00
Paul1nh0
2dad2c477b query description added 2022-03-22 19:06:03 +08:00
Geoffrey White
5d5904d6c8 C++: Autoformat. 2022-03-22 10:55:04 +00:00
Mathias Vorreiter Pedersen
5cbd86519b C++: Add internal extraction errors query and modify the 'code-scanning-selectors' to exclude internal queries. 2022-03-22 10:52:02 +00:00
Michael Nebel
b95a332ded C#: Simplify the isCollectionType predicate. 2022-03-22 11:25:14 +01:00
Rasmus Wriedt Larsen
9254b2904e Ruby: Adjust HttpClients test 2022-03-22 11:19:55 +01:00
Rasmus Wriedt Larsen
6bd9d82610 Merge pull request #8061 from RasmusWL/orm
Python: Add data-flow through Django ORM models
2022-03-22 11:14:08 +01:00
Rasmus Wriedt Larsen
945b52fc46 Ruby: autoformat
😳
2022-03-22 10:59:26 +01:00
Michael Nebel
1d45996001 Merge pull request #8466 from michaelnebel/csharp/refactor-aspartial
C#: Refactor asPartial to allow re-use.
2022-03-22 10:54:54 +01:00
Rasmus Wriedt Larsen
68de6a4e3c Ruby: Add change-note 2022-03-22 10:53:55 +01:00
Rasmus Wriedt Larsen
9c2fc1b415 Ruby: client request: getUrl => getAUrlPart
This is a port of the same change in Python from
f8fc583af3

The description of that commit was:

> I think `getUrl` is a bit too misleading, since from the name, I would
> only ever expect ONE result for one request being made.
>
> `getAUrlPart` captures that there could be multiple results, and that
> they might not constitute a whole URl.
>
> Which is the same naming I used when I tried to model this a long time ago
> a80860cdc6/python/ql/lib/semmle/python/web/Http.qll (L102-L111)
2022-03-22 10:53:55 +01:00
Rasmus Wriedt Larsen
311cbb4e13 Merge branch 'main' into shared-concepts-scaffolding 2022-03-22 10:36:33 +01:00
Rasmus Wriedt Larsen
414764ccee Concepts: Minor rewrite in qldoc
As suggested by @hmac
2022-03-22 10:33:58 +01:00
Rasmus Wriedt Larsen
e50a9421a6 JS: Update dataflow import in ConceptsImports.qll
Co-authored-by: Erik Krogh Kristensen <erik-krogh@github.com>
2022-03-22 10:32:20 +01:00
Erik Krogh Kristensen
099d91ba6f update qldoc 2022-03-22 10:27:21 +01:00
Tom Hvitved
99ddfb489f Ruby: Rework getConstantValue implementation 2022-03-22 10:07:44 +01:00
Erik Krogh Kristensen
ea065b7d8a Merge pull request #8521 from erik-krogh/getRubyMoreInSync
Ruby: sync ExponentialBackTracking.qll
2022-03-22 09:59:20 +01:00
Erik Krogh Kristensen
90a6717932 sync ExponentialBackTracking.qll for ruby 2022-03-22 09:27:04 +01:00
Tamás Vajk
36c7e10195 Merge pull request #8519 from github/revert-8294-tamasvajk/fix/mad-adjustments
Revert "Fix MaD workflows to be more resilient to missing files"
2022-03-22 09:19:14 +01:00
Tamás Vajk
87e1641772 Revert "Fix MaD workflows to be more resilient to missing files" 2022-03-22 09:08:56 +01:00
Tamás Vajk
80fb021e32 Merge pull request #8294 from github/tamasvajk/fix/mad-adjustments
Fix MaD workflows to be more resilient to missing files
2022-03-22 09:02:37 +01:00
Harry Maclean
99b5c580a5 Ruby: Fix captured reads in lambdas
These were previously identified as method calls. The fix is to
recognise lambdas as a scope which can inherit variables from its
parent.
2022-03-22 15:35:43 +13:00
Harry Maclean
c891e62a0e Ruby: Add some tests for method calls in lambdas
This reveals a bug where we identify reads of captured variables in
lambdas as method calls. This is fixed in a followup commit.
2022-03-22 15:33:22 +13:00
Harry Maclean
3e8bc8b0f2 Merge pull request #8224 from github/hmac/http-to-file-access
Ruby: Add rb/http-to-file-access query
2022-03-22 13:46:36 +13:00
Jeroen Ketema
2d9b630fa8 C++: Fix ExecTainted.ql formatting 2022-03-21 23:28:58 +01:00
Harry Maclean
b1ae548f4c Ruby: Fix doc comment formatting 2022-03-22 11:10:09 +13:00
Harry Maclean
c2d4bc50c9 Add missing file doc comment 2022-03-22 11:10:09 +13:00
Harry Maclean
91a7e9405c Share HttpToFileAccessQuery between JS and Ruby
There's so little in this query that it may not be worth sharing, but
it's an interesting exercise in figuring out how we do it nicely.
2022-03-22 11:10:08 +13:00
Harry Maclean
130d93dded Ruby: Make HttpToFileAccess more specific
Only consider sources from HTTP requests, rather than any remote flow
source.
2022-03-22 11:09:08 +13:00
Harry Maclean
fac17384c3 Ruby: Add RequestInputAccess concept
This sits in between RemoteFlowSource and specific classes like
ParamsSource from ActionController. It represents any user-controller
input from an incoming HTTP request.

This more closely aligns our concepts with the JS library, and allows us
to specifically target sources from HTTP requests in the
HttpToFileAccess query.
2022-03-22 11:09:08 +13:00
Harry Maclean
ff1d96c922 Ruby: Add rb/http-to-file-access query 2022-03-22 11:09:08 +13:00
Jeroen Ketema
b79eb6d10d C++: Encode string value of data flow nodes in ExecState 2022-03-21 21:29:42 +01:00
Harry Maclean
6c18e1d7ac Merge pull request #8272 from hmac/hmac/tainted-format-string 2022-03-22 08:37:47 +13:00
Mathias Vorreiter Pedersen
aff76b7295 Merge pull request #8512 from github/fix-dead-select-clause-link
Fix dead link in `CONTRIBUTING.md`
2022-03-21 17:39:07 +00:00
Mathias Vorreiter Pedersen
2e55fd6be3 Update CONTRIBUTING.md
Co-authored-by: intrigus-lgtm <60750685+intrigus-lgtm@users.noreply.github.com>
2022-03-21 16:49:59 +00:00
Mathias Vorreiter Pedersen
cf54006c86 Fix dead link in CONTRIBUTING.md
cc @felicitymay.
2022-03-21 16:05:57 +00:00
Erik Krogh Kristensen
c8385a1e80 js/xss-through-dom: filter away reads of .src that end in a URL sink 2022-03-21 16:48:59 +01:00
Rasmus Wriedt Larsen
758a81cc0f Python: Remove import of Concepts in DataFlowPrivate
As discussed in PR review
2022-03-21 16:22:15 +01:00
Arthur Baars
79cd7bf8ed Python: create semmle/python/dataflow/new/Regex.qll 2022-03-21 15:57:19 +01:00
Michael Nebel
92f8a90f31 C#: Introduce a collectionType predicate. 2022-03-21 14:44:38 +01:00
Michael Nebel
8e2277e4f3 C#: Improve some of the QL Doc string. 2022-03-21 14:24:51 +01:00
Michael Nebel
d31ef371ec Merge pull request #8391 from michaelnebel/csharp/gvn-interface
C#: Deprecate the StructuralComparisonConfiguration interface and use sameGvn instead.
2022-03-21 14:10:53 +01:00
Geoffrey White
97fef4b3a5 C++: Switch strategy to nomagic. 2022-03-21 12:58:06 +00:00
Ian Lynagh
7295a5d313 Java: Add an upgrade script 2022-03-21 11:51:36 +00:00
Ian Lynagh
6284362868 Java: Update stats 2022-03-21 11:44:19 +00:00
Geoffrey White
7f825c12eb C++: Make getUnderlyingType 'nomagic'. 2022-03-21 11:12:18 +00:00
Jeroen Ketema
e05227d3fe C++: Add change note for the cpp/command-line-injection changes 2022-03-21 11:30:39 +01:00
Jeroen Ketema
8b4c42dd07 C++: Add cpp/command-line-injection test using a wrapper macro 2022-03-21 11:19:54 +01:00
Alex Ford
c891c53835 Merge pull request #8395 from alexrford/ruby/clear-text-storage
Ruby: add `rb/clear-text-storage-sensitive-data` query
2022-03-21 10:05:39 +00:00
CodeQL CI
b04c46f96d Merge pull request #8478 from asgerf/js/store-load-flow-context-sensitivity-bug
Approved by erik-krogh
2022-03-21 08:54:51 +00:00
Harry Maclean
5a6da827d0 Ruby: Avoid FP in TaintedFormatString query
Kernel#printf supports two call signatures:

    printf(String, *args)
    printf(IO, String, *args)

We want to identify the String argument, which is the format string.
Previously we would return the 0th and 1st arguments, which gives some
FPs when the 1st arg is not a format string.

We now try to rule out the trivial case by checking if arg 0 has a
string value, and then assuming it is the format string. Otherwise we
fall back to returning both arguments.

This still has some false positive potential, but less than previously.
2022-03-21 12:51:47 +13:00
Harry Maclean
5dcf0ad759 Ruby: Make IOPrintfCall more sensitive
It will now identify cases like this:

    file = File.open "foo.txt", "a"
    file.printf(params[:format], arg)
2022-03-21 12:51:47 +13:00
Harry Maclean
c253bddbe0 Ruby: Make getFormatArgument 0-indexed 2022-03-21 12:51:47 +13:00
Harry Maclean
c73dc8ad0c Ruby: Add change note for rb/tainted-format-string 2022-03-21 12:51:47 +13:00
Harry Maclean
10a411e5cc Ruby: Remove duplicate CWE reference 2022-03-21 12:51:47 +13:00
Harry Maclean
d79a6ddcb2 Ruby: Improve qhelp for rb/tainted-format-string 2022-03-21 12:51:47 +13:00
Harry Maclean
0cfe37dff4 Share TaintedFormatString between Ruby and JS 2022-03-21 12:51:46 +13:00
Harry Maclean
4249e30824 Ruby: Test tainted interpolated format arg 2022-03-21 12:51:18 +13:00
Harry Maclean
63199024a2 Add missing QLDoc 2022-03-21 12:51:18 +13:00
Harry Maclean
f6215d4c7e Ruby: Add rb/tainted-format-string query 2022-03-21 12:51:18 +13:00
Jeroen Ketema
f8198c3123 C++: Use flow states in cpp/command-line-injection 2022-03-18 20:06:45 +01:00
Robert Marsh
4bf35ad188 Merge pull request #8483 from jketema/command-line-injection-test-cases-with-calls
C++: Add additional command line injection tests
2022-03-18 15:05:12 -04:00
Arthur Baars
beef8e29bc Merge pull request #8332 from hvitved/ruby/regexp-taint-flow
Ruby: Use taint tracking instead of type tracking to define `regExpSource`
2022-03-18 18:24:02 +01:00
Arthur Baars
9412b331db Revert "Revert "Python: switch to shared implementation of IncompleteHostnameRegExp.ql""
This reverts commit 6d24591416.
2022-03-18 16:31:22 +01:00
Jeroen Ketema
d37ef1b5ca C++: Add command line injection test that currently results in a false positive 2022-03-18 16:12:09 +01:00
Arthur Baars
117fb5be7d Merge pull request #7917 from aibaars/incomplete-hostname
Ruby: IncompleteHostnameRegExp.ql
2022-03-18 16:00:09 +01:00
Tom Hvitved
1437aefe9d Ruby: Use taint tracking instead of type tracking to define regExpSource 2022-03-18 14:48:12 +01:00
Tom Hvitved
d97eaba070 Ruby: Add dataflow/taintracking copies for use in libraries 2022-03-18 14:48:12 +01:00
Arthur Baars
4a27928728 Ruby/JS add missing ^ in qhelp 2022-03-18 14:00:10 +01:00
Jeroen Ketema
459870ac1e C++: Add additional command line injection tests 2022-03-18 13:42:27 +01:00
Arthur Baars
431b60506e Merge remote-tracking branch 'upstream/main' into incomplete-hostname 2022-03-18 13:05:34 +01:00
Arthur Baars
6d24591416 Revert "Python: switch to shared implementation of IncompleteHostnameRegExp.ql"
This reverts commit ce50f35dda.
2022-03-18 13:02:55 +01:00
Chris Smowton
767453520e Merge pull request #8032 from JLLeitschuh/feat/JLL/check_os
Java: Add Guard Classes for checking OS & unify System Property Access
2022-03-18 11:20:36 +00:00
Asger Feldthaus
26b7edccd4 JS: Change note 2022-03-18 11:59:36 +01:00
Erik Krogh Kristensen
693c77f3df add test for string replacement chains of URL schemes 2022-03-18 11:05:59 +01:00
Asger F
929419abba Merge pull request #8254 from asgerf/ruby/mad-prototype
Ruby: initial prototype of models-as-data
2022-03-18 10:48:33 +01:00
Erik Krogh Kristensen
235aa9c24e recognize string replacement chains as scheme checks in js/incomplete-url-scheme-check 2022-03-18 10:37:20 +01:00
Mathias Vorreiter Pedersen
8bf172913e Merge pull request #8474 from hvitved/flow-state-changing-steps-should-be-in-path-explanation-alternative
Dataflow: Flow-state changing steps should always be in path explanations
2022-03-18 09:08:36 +00:00
Asger Feldthaus
8753632193 JS: Fix bug in reachableFromStoreBase 2022-03-17 17:30:46 +01:00
Asger Feldthaus
8c6ca6582e JS: Add test showing missing flow 2022-03-17 17:30:46 +01:00
Geoffrey White
ff3bedcab9 C++: Fix expensive getWideCharType(). 2022-03-17 14:41:57 +00:00
Mathias Vorreiter Pedersen
abe30457ee Python: Accept test changes. 2022-03-17 14:03:58 +01:00
Tom Hvitved
79ea2a3a9c Data flow: Sync files 2022-03-17 14:03:58 +01:00
Tom Hvitved
4df12dc6e6 Data flow: State-changing taint steps should not be stepped over by the big step relation 2022-03-17 14:03:58 +01:00
Rasmus Wriedt Larsen
2b9408b0c3 Concepts: Add some architecture documentation 2022-03-17 13:49:10 +01:00
Harry Maclean
36c421346b Introduce ConceptsShared.qll 2022-03-17 13:49:10 +01:00
Erik Krogh Kristensen
870521bd1e Merge pull request #8473 from erik-krogh/redundantAnyCast
QL: expand redundant-inline-cast, and rename to redundant-cast
2022-03-17 10:41:50 +01:00
Erik Krogh Kristensen
fe94421d32 rename redundant-inline-cast to redundant-cast 2022-03-17 10:25:40 +01:00
Erik Krogh Kristensen
86398a8c65 Merge pull request #8304 from erik-krogh/xssUrl
JS: Refactor the XSS / Client-side-url queries
2022-03-17 09:13:09 +01:00
Erik Krogh Kristensen
aa8b7c8679 update reference to deprecated class name 2022-03-16 22:32:54 +01:00
Erik Krogh Kristensen
6cdc38748c update expected output 2022-03-16 22:32:09 +01:00
Erik Krogh Kristensen
d8a5947a08 simplify TaintedUrlSuffix::source() to only consider window.location based sources 2022-03-16 22:32:09 +01:00
Erik Krogh Kristensen
b3de5d94a6 move PrefixStringSanitizer to the Query.qll file, and have it extend LabeledSanitizerGuardNode 2022-03-16 22:32:09 +01:00
Erik Krogh Kristensen
562dce57e8 rename isXSSSink to isXssSink 2022-03-16 22:32:09 +01:00
Erik Krogh Kristensen
f083e87fa1 refactor the js/xss query to use three flowlabels and one configuration 2022-03-16 22:32:08 +01:00
Erik Krogh Kristensen
87842bb8b7 add client-side-url sinks that may execute JavaScript as XSS sinks 2022-03-16 22:32:08 +01:00
Erik Krogh Kristensen
b471fec149 split interpretsArgumentsAsURL out of interpretsArgumentsAsHTML, and use it to generalize AttributeUrlSink 2022-03-16 22:32:08 +01:00
Erik Krogh Kristensen
2576e1f655 add utility predicate to get client-side remote-flow-sources that contain a URL query/fragment 2022-03-16 22:32:08 +01:00
Erik Krogh Kristensen
67e6a4c716 add a isXSSSink predicate to the client-side-url-redirection sinks 2022-03-16 22:32:08 +01:00
Erik Krogh Kristensen
fc79242674 add tests 2022-03-16 22:32:08 +01:00
Erik Krogh Kristensen
559f03ebbc remove unnecessary module qualifier 2022-03-16 22:32:07 +01:00
Erik Krogh Kristensen
2d9d383c55 remove unused import 2022-03-16 22:32:07 +01:00
Arthur Baars
1a51f0cf56 Ruby: regex: fix getGroupNumber
non-capture groups should not have a group number
2022-03-16 18:50:51 +01:00
Michael Nebel
4a68b74aa3 C#: Re-use the asPartialModel for DataFlowPrivate in tests. 2022-03-16 17:02:00 +01:00
Michael Nebel
115cef2484 C#: Move asPartialModel into DataFlowPrivate (to enable re-use). 2022-03-16 16:44:24 +01:00
Michael Nebel
138eb485c6 C#: Address review comments. 2022-03-16 16:00:48 +01:00
Jeroen Ketema
7a9a9d833a Merge pull request #8435 from jketema/all-the-barriers
Add flow state versions of isBarrierIn, isBarrierOut, and isBarrierGuard
2022-03-16 15:50:19 +01:00
Michael Nebel
68f24cda0b Merge pull request #8462 from michaelnebel/csharp/capture-models-fix-bad-join-order
C#: Fix bad join order in returnNodeAsOutput.
2022-03-16 15:46:17 +01:00
Asger Feldthaus
e1976da7f9 JS: Autoformat 2022-03-16 15:01:17 +01:00
Dave Bartolomeo
e669ffa22e Merge pull request #8320 from jketema/structured-binding-array
C++: Handle initialization of structured bindings via bitwise copy in extractor
2022-03-16 09:41:31 -04:00
Ian Lynagh
565f607096 Java: Add a changenote for ErrorExpr/ErrorStmt 2022-03-16 13:20:33 +00:00
Asger F
228570129e Merge branch 'main' into ruby/mad-prototype 2022-03-16 13:50:31 +01:00
Asger Feldthaus
e168da4c5f Shared: make a predicate private 2022-03-16 13:48:56 +01:00
Michael Nebel
5f7b5ec5df C#: Fix bad join order in returnNodeAsOutput. 2022-03-16 13:44:11 +01:00
Asger Feldthaus
8cef512234 Ruby: ensure ApiGraphs.qll imports its entry points 2022-03-16 13:40:14 +01:00
Asger Feldthaus
e3fbaf5d8f Shared: prefer exists(var) instead of var = any(string s) 2022-03-16 13:37:08 +01:00
Asger Feldthaus
102540072e Shared: remove documentation prone to falling out of date 2022-03-16 13:32:55 +01:00
Nick Rolfe
f6681f30c6 Merge pull request #8399 from github/nickrolfe/simple_symbol_constant_value
Ruby: implement getComponent(n) for simple and hash-key symbols
2022-03-16 12:10:39 +00:00
Asger Feldthaus
2ca45ef9f9 Ruby: support BlockArgument in identifying access path 2022-03-16 12:51:14 +01:00
Nick Rolfe
94ce578ea4 Ruby: implement getComponent(n) for simple and hash-key symbols 2022-03-16 11:43:46 +00:00
Asger Feldthaus
c9355095e3 Ruby: Use Receiver instead of Argument[-1] in ActiveStorage 2022-03-16 12:37:21 +01:00
Asger Feldthaus
71f195d1e0 Ruby: add test for Receiver in summary 2022-03-16 12:37:21 +01:00
Arthur Baars
6b323eeda8 Update expected output 2022-03-16 12:34:03 +01:00
Arthur Baars
ab93b3784b Merge remote-tracking branch 'upstream/main' into incomplete-hostname 2022-03-16 12:31:12 +01:00
Arthur Baars
852f05bfb7 Address comment 2022-03-16 12:26:39 +01:00
Nick Rolfe
76918238f0 Ruby: test ExprCfgNode::getConstantValue() 2022-03-16 11:21:57 +00:00
Geoffrey White
95a63a69a5 Merge branch 'main' into cwe497b 2022-03-16 11:09:46 +00:00
Asger Feldthaus
f140c13261 JS: Sync ApiGraphModels.qll and update accordingly 2022-03-16 12:04:41 +01:00
Asger Feldthaus
2b02a173c1 Ruby: canonicalize callables based on package;type;path instead of input;output;kind 2022-03-16 12:04:41 +01:00
Asger Feldthaus
d8b4bc81ff JS: Rename EntryPoint.getNode -> getANode 2022-03-16 12:04:39 +01:00
Chris Smowton
b11340c829 Change note tense and detail level 2022-03-16 10:34:25 +00:00
Rasmus Wriedt Larsen
ae1ba11d57 Merge branch 'main' into orm 2022-03-16 11:23:14 +01:00
Paul1nh0
85b22647ac Add query for double-fetch vulnerability 2022-03-16 18:16:49 +08:00
Asger Feldthaus
33ca55770c Ruby: EntryPoint.getNode -> getANode 2022-03-16 11:02:26 +01:00
Asger Feldthaus
ecf7073bf1 Shared: codeql -> ql in code blocks 2022-03-16 11:00:24 +01:00
Rasmus Wriedt Larsen
f1e6271d20 Python: Apply suggestions from code review
Co-authored-by: yoff <lerchedahl@gmail.com>
2022-03-16 10:53:19 +01:00
Rasmus Wriedt Larsen
461e2f3663 Python: Apply suggestions from code review
Co-authored-by: yoff <lerchedahl@gmail.com>
2022-03-16 10:43:20 +01:00
Michael Nebel
8b16c1f585 C#: Add some test cases for inheritance. 2022-03-16 10:40:49 +01:00
Michael Nebel
e69ea8f577 C#: Add some testcases for generics. 2022-03-16 10:20:55 +01:00
Michael Nebel
814947b876 C#: Add some test cases for methods that are not properly exposed and will this not get their summary captured. 2022-03-16 09:47:14 +01:00
Michael Nebel
a555e04b55 C#: Bulk array flow. 2022-03-16 09:30:15 +01:00
Michael Nebel
226a874a74 C#: Test cases for IEnumerable. 2022-03-16 09:22:18 +01:00
Michael Nebel
ec6dab89d8 C#: Update the Summary model generator with better support for IEnumerable typed parameters. 2022-03-16 09:21:02 +01:00
Jeroen Ketema
d51cbe2525 C++: Update IR tests for handling of bitwise copy with explicit source 2022-03-15 23:22:37 +01:00
Jeroen Ketema
8be02b164c C++: Add IR tests exposing incorrect translation due to unhandled bitwise copy
These tests are in addition to exisiting tests involving default copy
constructors, which suffer from the same problem, i.e., the extractor not
handling bitwise copies.
2022-03-15 23:22:37 +01:00
Geoffrey White
92d748e006 C++: Fix ODR/dbcheck issue in test. 2022-03-15 20:00:19 +00:00
Ian Lynagh
2116e6d120 Java: Add ErrorExpr, ErrorStmt 2022-03-15 17:30:19 +00:00
Jonathan Leitschuh
09cc8ee09e Add tests for StandardSystemProperty 2022-03-15 12:37:42 -04:00
Geoffrey White
46f3f28a11 C++: Fix broken merge. 2022-03-15 14:53:25 +00:00
Michael Nebel
4f2678fc72 C#: Add some testcases for model generation of methods using Lists. 2022-03-15 15:44:06 +01:00
Michael Nebel
a9bbe6889b C#: Use CollectionType instead of ArrayType when generating models. 2022-03-15 15:41:46 +01:00
Geoffrey White
71e0da738d Merge branch 'main' into cwe497b 2022-03-15 13:29:32 +00:00
Chris Smowton
451661dd20 Improve guard class names 2022-03-15 11:46:54 +00:00
Geoffrey White
28315df405 Merge branch 'main' into cwe497b 2022-03-15 11:23:00 +00:00
Jeroen Ketema
157a36bc4f Use node variable in all disjuncts 2022-03-15 11:55:35 +01:00
Jeroen Ketema
9a0e94f389 Add flow state versions of isBarrierIn, isBarrierOut, and isBarrierGuard 2022-03-15 11:55:34 +01:00
Asger Feldthaus
d628dc0b52 Ruby: sync ApiGraphModels.qll 2022-03-15 10:52:41 +01:00
Asger Feldthaus
82750638c6 JS: Verify models even if package is not used in database 2022-03-15 10:51:44 +01:00
Asger Feldthaus
a19f06ffc0 JS: Port checks to JS 2022-03-15 10:35:49 +01:00
Asger Feldthaus
7f8205684e Ruby: verify tokens in identifying access path 2022-03-15 10:25:59 +01:00
Asger Feldthaus
97ca1155c3 JS: Sync ApiGraphModels.qll and test 2022-03-15 09:29:34 +01:00
Asger Feldthaus
65249dabd3 Ruby: add warning for wrong number of columns in CSV row 2022-03-15 09:28:21 +01:00
Michael Nebel
ba67ea0445 C#: Fix performance issue with UselessNullCoalescingExpression query. 2022-03-15 09:09:45 +01:00
Asger Feldthaus
f28acbf3dc Ruby: autoformat 2022-03-15 08:15:18 +01:00
Geoffrey White
73710e9edb C++: Fix QLDoc. 2022-03-14 19:11:43 +00:00
Geoffrey White
7c93eb1eaf C++: Fix large newtype. 2022-03-14 19:06:41 +00:00
Geoffrey White
d1b04b4e07 C++: Use asDefiningArgument() where appropriate. 2022-03-14 17:53:47 +00:00
Asger Feldthaus
fee32d3480 Elaborate on qldoc for API::EntryPoint 2022-03-14 17:52:07 +01:00
Asger Feldthaus
be65b9bebc Ruby: remove spurious Instance token from getExtraSuccessorFromInvoke 2022-03-14 17:39:43 +01:00
Asger Feldthaus
072ad8f4a7 Ruby: add (from model) to remote flow description 2022-03-14 17:39:17 +01:00
Asger Feldthaus
37bbd46e43 Ruby: fix broken comment 2022-03-14 17:33:57 +01:00
Asger Feldthaus
c9d7651c59 Be explicit about re-exporting 2022-03-14 17:26:30 +01:00
Michael Nebel
432ac7a824 C#: Deprecate the StructuralComparisonConfig class. 2022-03-14 14:17:56 +01:00
Michael Nebel
5a4a97569f C#: Use Gvn comparison instead of StructuralComparisonConfiguration in Constants. 2022-03-14 14:17:56 +01:00
Michael Nebel
5b5ea140d2 C#: Delete the Internal StructuralComparisonConfiguration class as it is no longer needed. 2022-03-14 14:17:56 +01:00
Michael Nebel
bf4dc0034a C#: Use Gvn comparison instead of StructuralComparisonConfiguration in Guards. 2022-03-14 14:17:56 +01:00
Michael Nebel
90b4eb9e13 C#: Use Gvn comparison instead of StructuralComparisonConfiguration in UnsafeLazyInitialization. 2022-03-14 14:17:56 +01:00
Michael Nebel
74b8e73133 C#: Use Gvn comparison instead of StructuralComparisonConfiguration in MissedTernaryOpportunity. 2022-03-14 14:17:56 +01:00
Michael Nebel
94999d4df5 C#: Use Gvn comparison instead of StructuralComparisonConfiguration in UselessIsBeforeAs. 2022-03-14 14:17:56 +01:00
Michael Nebel
8e7c7d8259 C#: Use Gvn comparison instead of StructuralComparisonConfiguration in UselessNullCoalescingExpression. 2022-03-14 14:17:56 +01:00
Michael Nebel
4a1981edfd C#: Use Gvn comparison instead of StructuralComparisonConfiguration in NestedLoopsSameVariable. 2022-03-14 14:17:56 +01:00
Michael Nebel
b4f2fc60ec C#: Use Gvn comparison instead of StructuralComparisonConfiguration in SelfAssignment. 2022-03-14 14:17:56 +01:00
Michael Nebel
f241eef2ea C#: Use Gvn comparison instead of StructuralComparisonConfiguration in structuralComparison test. 2022-03-14 14:17:56 +01:00
Michael Nebel
6f5b2e8440 C#: Use Gvn comparison instead of StructuralComparisonConfiguration in UseTryGetValue. 2022-03-14 14:17:56 +01:00
Jonathan Leitschuh
50ff2c2c68 Code cleanup from code review 2022-03-11 11:44:15 -05:00
Arthur Baars
cf4b834536 Address comments 2022-03-11 14:25:34 +01:00
Jonathan Leitschuh
1c9864286d Remove SystemProperty from FlowSources 2022-03-10 18:29:29 -05:00
Alex Ford
0f0a51e2e0 Ruby: update test output 2022-03-10 18:27:06 +00:00
Alex Ford
2b25765156 Format QL 2022-03-10 17:55:42 +00:00
Alex Ford
43fb759dfa Ruby: add a few more rb/clear-text-storage-sensitive-data test cases 2022-03-10 17:52:50 +00:00
Alex Ford
37c0702cdd Ruby: update test output 2022-03-10 17:50:29 +00:00
Alex Ford
0b73088ed4 Ruby: link to sink in rb/clear-text-storage-sensitive-data message 2022-03-10 17:38:52 +00:00
Alex Ford
0f3cf47ca9 Ruby/JS/Py: Add "random" to the notSensitiveRegexp() heuristic 2022-03-10 17:38:52 +00:00
Alex Ford
532fc080a1 Ruby: Fix inconsistencies in checking for sensitive names in CleartextSources 2022-03-10 17:38:52 +00:00
Alex Ford
8be1be388e Ruby: update CleartextStorage test output for source locations 2022-03-10 17:38:52 +00:00
Alex Ford
fda2b56e20 Ruby: move rb/clear-text-storage-sensitive-data location from sink to source 2022-03-10 17:38:52 +00:00
Alex Ford
4618000567 Ruby: move an import into CleartextStorage.ql 2022-03-10 17:38:52 +00:00
Alex Ford
853fbe8911 Ruby: Fix CleartextStorageCustomizations to use PersistentWriteAccess 2022-03-10 17:38:52 +00:00
Alex Ford
a1a7c31661 Ruby: drop an outdated TODO 2022-03-10 17:38:52 +00:00
Alex Ford
9fe7d6e143 Ruby: fix typo
Co-authored-by: Harry Maclean <hmac@github.com>
2022-03-10 17:38:52 +00:00
Alex Ford
0e2709f809 Ruby: changenote for rb/clear-text-storage-sensitive-data 2022-03-10 17:38:52 +00:00
Alex Ford
ef29a372a4 Ruby: Cleartext storage tests 2022-03-10 17:38:52 +00:00
Alex Ford
0070e30377 Ruby: Add rb/clear-text-storage-sensitive-data query 2022-03-10 17:38:52 +00:00
Alex Ford
7084718b07 Ruby: factor out common parts of CleartextLoggingCustomizations into CleartextSources 2022-03-10 17:38:52 +00:00
Jonathan Leitschuh
ecb8911756 Apply suggestions from code review
Co-authored-by: Chris Smowton <smowton@github.com>
2022-03-10 11:48:16 -05:00
Jonathan Leitschuh
2a6c4e9350 Add localFlowPlusInitializers 2022-03-09 11:06:26 -05:00
Geoffrey White
9ebdb2ac1d C++: QLDoc. 2022-03-08 16:12:58 +00:00
Jonathan Leitschuh
a21992ade9 Minor refactoring to improve tests and documentation 2022-03-07 18:40:53 -05:00
Jonathan Leitschuh
5b651f29d8 Fix insufficient tests and add documentation 2022-03-07 16:39:40 -05:00
Jonathan Leitschuh
b282c7f1b9 Apply suggestions from code review
Co-authored-by: Marcono1234 <Marcono1234@users.noreply.github.com>
Co-authored-by: Chris Smowton <smowton@github.com>
2022-03-07 11:31:32 -05:00
Arthur Baars
ce50f35dda Python: switch to shared implementation of IncompleteHostnameRegExp.ql 2022-03-07 16:10:08 +01:00
Arthur Baars
bb348116ab JavaScript: update expected output 2022-03-07 16:10:08 +01:00
Arthur Baars
98f56f4d60 Js/Ruby: Share IncompleteHostnameRegExp.ql 2022-03-07 16:10:08 +01:00
Arthur Baars
097c661362 Ruby: drop results that cannot be found yet from IncompleteHostnameRegExp.expected 2022-03-07 16:10:08 +01:00
Arthur Baars
9e8930c192 Ruby: IncompleteHostnameRegExp.ql 2022-03-07 16:10:08 +01:00
Arthur Baars
832c9c4b0b Ruby: copy IncompleteHostnameRegExp files from JavaScript 2022-03-07 16:10:07 +01:00
Arthur Baars
602538d1c1 Ruby: add RegExpPatterns module 2022-03-07 16:09:12 +01:00
Geoffrey White
cb33ed4fc2 C++: Only look for sensitive strings in appropriate parameters. 2022-03-07 11:29:09 +00:00
Geoffrey White
f1d6234483 C++: Add more information about registry query parameters. 2022-03-07 09:45:31 +00:00
Jonathan Leitschuh
523ddb79f3 Cleanup after code review feedback 2022-03-04 15:35:01 -05:00
Jonathan Leitschuh
5243fe3dbf Apply suggestions from code review
Co-authored-by: Chris Smowton <smowton@github.com>
2022-03-04 15:30:52 -05:00
Geoffrey White
4316026720 C++: VariableAccess -> Expr. 2022-03-04 18:00:54 +00:00
Erik Krogh Kristensen
7691807713 delete the getLastParameter predicate from ApiGraphs 2022-03-04 16:24:54 +01:00
Erik Krogh Kristensen
934e06ca3b fix mistake in argumentPassing. The type-tracking was not required to be in an end state 2022-03-04 09:49:42 +01:00
Jonathan Leitschuh
7ab193dde2 Add System.getProperties().getProperty support 2022-03-03 20:08:38 -05:00
Jonathan Leitschuh
31527a67e5 Refactor OS Checks & SystemProperty logic from review feedback 2022-03-03 17:15:35 -05:00
Jonathan Leitschuh
103c770ce7 Apply suggestions from code review
Co-authored-by: Chris Smowton <smowton@github.com>
2022-03-03 16:39:45 -05:00
Geoffrey White
6848b6095b C++: Autoformat. 2022-03-03 12:51:54 +00:00
Geoffrey White
5c6923c099 C++: Improve and differentiate the qhelp. 2022-03-03 11:04:55 +00:00
Geoffrey White
88b7a085b0 C++: Make the bulk of test cases in tests.cpp more relevant. 2022-03-03 10:40:17 +00:00
Geoffrey White
07b4bf7023 C++: Use the same trick as in ExposedSystemData to catch a few more results. 2022-03-03 10:33:39 +00:00
Geoffrey White
6e5729c924 C++: Fix typo and adjust violation message wording. 2022-03-03 10:28:53 +00:00
Geoffrey White
9e193f624c C++: Change note. 2022-03-03 09:55:02 +00:00
Jonathan Leitschuh
fea50065f5 Fix duplicated comment 2022-03-02 19:54:04 -05:00
Jonathan Leitschuh
85de9f305e Fix naming of OSCheck method 2022-03-02 19:41:46 -05:00
Jonathan Leitschuh
a7adbb7291 Refactor more system property access logic 2022-03-02 19:33:05 -05:00
Jonathan Leitschuh
3c53a05e16 Add OS Checks based upon separator or path separator 2022-03-02 14:15:56 -05:00
Geoffrey White
2a14a4f14e C++: Fill in metadata. 2022-03-02 18:52:52 +00:00
Geoffrey White
66b9356eb9 C++: There is no overlap between OutputWrite and RemoteFlowSinkFunction. 2022-03-02 18:16:39 +00:00
Geoffrey White
a1ace7122d C++: Move SystemData class into a library. 2022-03-02 18:01:06 +00:00
Geoffrey White
70e4a409fd C++: Add the new query to tests. 2022-03-02 17:56:53 +00:00
Geoffrey White
d95b56fca0 C++: Create prototype query. 2022-03-02 17:56:49 +00:00
Jonathan Leitschuh
82d3cd8924 Improve system property lookup 2022-03-02 12:51:15 -05:00
Jonathan Leitschuh
dad9a02fbd Update TempDirInfoDisclosure with new OS Guards 2022-03-02 12:51:15 -05:00
Jonathan Leitschuh
5913c9acad Refactor OS Guard Checks 2022-03-02 12:51:14 -05:00
Jonathan Leitschuh
fd63107edf Update OS Check from Review Feedback 2022-03-02 12:51:12 -05:00
Jonathan Leitschuh
9f5022ee95 Review fixup and add test for apache SystemUtils 2022-03-02 12:50:38 -05:00
Jonathan Leitschuh
49513443f2 Update java/ql/lib/semmle/code/java/os/OSCheck.qll
Co-authored-by: Marcono1234 <Marcono1234@users.noreply.github.com>
2022-03-02 12:50:37 -05:00
Jonathan Leitschuh
3cdfc00542 Cleanup from review feedback 2022-03-02 12:50:37 -05:00
Jonathan Leitschuh
39828fd596 Apply OS guard checks to TempDirLocalInformationDisclosure 2022-03-02 12:50:37 -05:00
Jonathan Leitschuh
cd073a2173 Java: Add Guard Classes for checking OS 2022-03-02 12:50:35 -05:00
Geoffrey White
67aa1449ce C++: Add some more test cases (moved from the private repo). 2022-03-02 17:23:07 +00:00
Geoffrey White
19718fa280 C++: Add a couple of new test cases. 2022-03-02 15:18:04 +00:00
Geoffrey White
da740cfa05 C++: Test layout. 2022-03-02 15:18:04 +00:00
Rasmus Wriedt Larsen
27d5349a74 Python: ORM: Remove imports from test code
These are no longer needed, as data-flow now has this import by default
2022-03-01 15:39:52 +01:00
Rasmus Wriedt Larsen
a1c7ec8c6d Python: Accept .exepcted changes from importing frameworks from data-flow
Since `python.qll` has `private import
semmle.python.dataflow.new.DataFlow`, that means that all tests now
implicitly imports the frameworks modeling, and therefore any python
class is part of the DjangoViewClassHelper ql class.

de8ecb214f/python/ql/lib/python.qll (L44)
2022-03-01 15:37:16 +01:00
Asger Feldthaus
df379809df Ruby: support CSV rows of form ;any;Method[foo] 2022-03-01 14:08:21 +01:00
Asger Feldthaus
05ea33033b Ruby: add test for API::EntryPoint 2022-03-01 14:08:21 +01:00
Asger Feldthaus
bf83400bd2 Ruby: port API::EntryPoint from JS 2022-03-01 14:08:21 +01:00
Asger Feldthaus
e10e3b9466 Ruby: convert ActiveStorage::Filename model to MaD 2022-03-01 14:08:21 +01:00
Asger Feldthaus
e6a3747656 Ruby: add test for ActiveStorage.Filename.new 2022-03-01 14:08:21 +01:00
Asger Feldthaus
70c083fa64 Ruby: convert Regexp.escape model to MaD 2022-03-01 14:08:21 +01:00
Asger Feldthaus
cbd044a768 Ruby: add a code injection test for flwo through Regexp.escape 2022-03-01 14:08:21 +01:00
Asger Feldthaus
63e7c16d6b Ruby: add test with sinks and type-defs 2022-03-01 14:08:20 +01:00
Asger Feldthaus
388949f12e Ruby: support WithBlock and WithoutBlock 2022-03-01 14:08:20 +01:00
Asger Feldthaus
d6bc9c259e Ruby: add simple test case 2022-03-01 14:08:20 +01:00
Asger Feldthaus
d808bdc028 JS: Sync ApiGraphModels.qll 2022-03-01 14:08:20 +01:00
Asger Feldthaus
a33e89279d Ruby: instantiate ApiGraphModels library in Ruby 2022-03-01 14:08:20 +01:00
Rasmus Wriedt Larsen
cd58c12bbe Merge branch 'main' into orm 2022-03-01 12:01:54 +01:00
Rasmus Wriedt Larsen
98c60a706e Python: Autoformat
Oops
2022-03-01 11:54:09 +01:00
Rasmus Wriedt Larsen
e32f8d98b0 Python: Always import ORM steps for data-flow
For C#, see
fdd787b89c/csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowPrivate.qll (L16)

that import EntityFramework, which is ORM library.
2022-03-01 11:32:36 +01:00
Tamas Vajk
1538e89bd9 Use generate-report.py from base SHA 2022-02-28 20:36:23 +01:00
Tamas Vajk
bd30c63aa1 Fix expected file comparer to handle missing files better in MaD workflows 2022-02-28 20:16:20 +01:00
Tamas Vajk
714659c706 Change cp to mv in CSV coverage PR job 2022-02-28 20:07:23 +01:00
Rasmus Wriedt Larsen
8afd560c64 Python: ORM: Handle load of PolymorphicModels 2022-02-28 16:38:41 +01:00
Rasmus Wriedt Larsen
48fba87273 Python: ORM: add flow to base-class 2022-02-28 16:38:40 +01:00
Rasmus Wriedt Larsen
6b9dd49499 Python: ORM: Model polymorphic.models.PolymorphicModel as Django ORM class 2022-02-28 16:38:40 +01:00
Rasmus Wriedt Larsen
e1191cf63c Python: ORM: Add tests for inheritance 2022-02-28 16:38:40 +01:00
Rasmus Wriedt Larsen
092cfceb18 Python: Add dataflow consistency checks to ORM tests
Luckily they passed :phew:
2022-02-28 16:38:40 +01:00
Rasmus Wriedt Larsen
d7ff00e615 Python: Add change-note 2022-02-28 16:38:40 +01:00
Rasmus Wriedt Larsen
ed36ff1570 Python: ORM: Handle <Model>.objects.[<QuerySet>].update() 2022-02-28 16:38:40 +01:00
Rasmus Wriedt Larsen
fea46b642d Python: ORM: Handle <Model>.objects.create and friends 2022-02-28 16:38:40 +01:00
Rasmus Wriedt Larsen
9b458b54aa Python: ORM: Add flow to collection/dict queries 2022-02-28 16:38:40 +01:00
Rasmus Wriedt Larsen
9cff4cbd1c Python: ORM: Add a few more tests
There were a few methods I had overlooked
2022-02-28 16:38:40 +01:00
Rasmus Wriedt Larsen
ae057c74cc Python: ORM: Store step for constructor 2022-02-28 16:38:40 +01:00
Rasmus Wriedt Larsen
f8a51bb994 Python: ORM: Add data-flow steps for Django ORM
Added dummy-whitespace to `orm_security_tests.py` so it would be
possible to see what the reflected XSS results are in the diff
2022-02-28 16:38:40 +01:00
Rasmus Wriedt Larsen
ef39968a56 Python: ORM: Add data-flow plumbing for ORM modeling
The idea is that we will do `save ==> synthetic`
and `synthetic ==> load`, so we don't need to do CP between save/load.

This setup with synthetic node in the middle, also allows for a limited
amount of the field-flow we can do with real flow-summary support.
2022-02-28 16:38:40 +01:00
Rasmus Wriedt Larsen
d3f07cdc10 Python: ORM: Add qltests
Which shows that there is no flow yet, which is not really a surprise :D
2022-02-28 16:38:40 +01:00
Rasmus Wriedt Larsen
c78fed6594 Python: ORM: Add raw python test files
no ql test files yet though, will come in next commit.
2022-02-28 16:38:40 +01:00
Rasmus Wriedt Larsen
f89fb50eb5 Python: ORM: Add boilerplate django project
By doing

```
django-admin startproject testproj
django-admin startapp testapp
```
2022-02-28 16:38:40 +01:00
Erik Krogh Kristensen
5130929358 remove comment suggesting that the receiver is parameter -1 2022-02-28 15:25:34 +01:00
Erik Krogh Kristensen
843ed8fca5 rename pw to aw
Co-authored-by: yoff <lerchedahl@gmail.com>
2022-02-28 15:25:25 +01:00
Erik Krogh Kristensen
5e23da813f rename named-parameters to keyword-parameters 2022-02-03 23:10:39 +01:00
Erik Krogh Kristensen
e434f075fa introduce, and use, API::APICallNode 2022-02-03 23:10:39 +01:00
Erik Krogh Kristensen
3801a158a8 remove module exporst nodes from API graphs 2022-02-03 23:10:39 +01:00
Erik Krogh Kristensen
c3f4a851f0 remove some TODOs I won't do 2022-02-03 23:10:39 +01:00
Erik Krogh Kristensen
3be3da2eb6 add recursive API-graph test 2022-02-03 23:10:38 +01:00
Erik Krogh Kristensen
ef5818e243 support import * in ApiGraphs 2022-02-03 23:10:38 +01:00
Erik Krogh Kristensen
16774ba285 add support for named parameters in API graphs 2022-02-03 23:10:38 +01:00
Erik Krogh Kristensen
095c73f1fe redo the ApiGraph testing framework 2022-02-03 23:10:38 +01:00
Erik Krogh Kristensen
66fd43fc3b add def edge for function returns 2022-02-03 23:10:38 +01:00
Erik Krogh Kristensen
d8eea7ba4c property writes are def nodes 2022-02-03 23:10:38 +01:00
Erik Krogh Kristensen
a908b219e9 more backtracking of def nodes, and lots of tests 2022-02-03 23:10:38 +01:00
Erik Krogh Kristensen
038b032a43 get basic module exports to work in API-graphs 2022-02-03 23:10:38 +01:00
Erik Krogh Kristensen
df9efbe778 get mimimal def nodes to work in python 2022-02-03 23:10:38 +01:00
Erik Krogh Kristensen
52ca0d168b move API-graph tests out of the experimental test folder 2022-02-03 23:10:37 +01:00
Erik Krogh Kristensen
89786d9ce2 rename pr to ref in memberFromRef 2022-02-03 23:10:37 +01:00
483 changed files with 29413 additions and 5774 deletions

View File

@@ -16,9 +16,10 @@ jobs:
- uses: actions/checkout@v2
- name: Find codeql
id: find-codeql
uses: github/codeql-action/init@erik-krogh/ql
uses: github/codeql-action/init@aa93aea877e5fb8841bcb1193f672abf6e9f2980
with:
languages: javascript # does not matter
tools: latest
- name: Get CodeQL version
id: get-codeql-version
run: |
@@ -159,7 +160,7 @@ jobs:
PACK: ${{ runner.temp }}/pack
- name: Hack codeql-action options
run: |
JSON=$(jq -nc --arg pack "${PACK}" '.resolve.queries=["--search-path", $pack] | .resolve.extractor=["--search-path", $pack] | .database.init=["--search-path", $pack]')
JSON=$(jq -nc --arg pack "${PACK}" '.database."run-queries"=["--search-path", $pack] | .resolve.queries=["--search-path", $pack] | .resolve.extractor=["--search-path", $pack] | .database.init=["--search-path", $pack]')
echo "CODEQL_ACTION_EXTRA_OPTIONS=${JSON}" >> ${GITHUB_ENV}
env:
PACK: ${{ runner.temp }}/pack
@@ -171,22 +172,25 @@ jobs:
echo "paths:" > ${CONF}
echo " - ${FOLDER}" >> ${CONF}
echo "paths-ignore:" >> ${CONF}
echo " - ql/ql/test" >> ${CONF}
echo " - ql/ql/test" >> ${CONF}
echo "disable-default-queries: true" >> ${CONF}
echo "packs:" >> ${CONF}
echo " - codeql/ql" >> ${CONF}
echo "Config file: "
cat ${CONF}
env:
CONF: ./ql-for-ql-config.yml
FOLDER: ${{ matrix.folder }}
- name: Initialize CodeQL
uses: github/codeql-action/init@erik-krogh/ql
uses: github/codeql-action/init@aa93aea877e5fb8841bcb1193f672abf6e9f2980
with:
languages: ql
db-location: ${{ runner.temp }}/db
config-file: ./ql-for-ql-config.yml
tools: latest
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@erik-krogh/ql
uses: github/codeql-action/analyze@aa93aea877e5fb8841bcb1193f672abf6e9f2980
with:
category: "ql-for-ql-${{ matrix.folder }}"
- name: Copy sarif file to CWD

View File

@@ -26,7 +26,7 @@ jobs:
- name: Find codeql
id: find-codeql
uses: github/codeql-action/init@erik-krogh/ql
uses: github/codeql-action/init@aa93aea877e5fb8841bcb1193f672abf6e9f2980
with:
languages: javascript # does not matter
- uses: actions/cache@v2

View File

@@ -20,7 +20,7 @@ jobs:
- uses: actions/checkout@v2
- name: Find codeql
id: find-codeql
uses: github/codeql-action/init@erik-krogh/ql
uses: github/codeql-action/init@aa93aea877e5fb8841bcb1193f672abf6e9f2980
with:
languages: javascript # does not matter
- uses: actions/cache@v2

View File

@@ -36,7 +36,7 @@ If you have an idea for a query that you would like to share with other CodeQL u
For details, see the [guide on query metadata](docs/query-metadata-style-guide.md).
Make sure the `select` statement is compatible with the query `@kind`. See [About CodeQL queries](https://help.semmle.com/QL/learn-ql/writing-queries/introduction-to-queries.html#select-clause) on help.semmle.com.
Make sure the `select` statement is compatible with the query `@kind`. See [About CodeQL queries](https://codeql.github.com/docs/writing-codeql-queries/about-codeql-queries/#select-clause) on codeql.github.com.
3. **Formatting**

View File

@@ -27,7 +27,8 @@
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl3.qll",
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl4.qll",
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl.qll",
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl2.qll"
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImpl2.qll",
"ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowImplForLibraries.qll"
],
"DataFlow Java/C++/C#/Python Common": [
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplCommon.qll",
@@ -54,7 +55,8 @@
"python/ql/lib/semmle/python/dataflow/new/internal/tainttracking2/TaintTrackingImpl.qll",
"python/ql/lib/semmle/python/dataflow/new/internal/tainttracking3/TaintTrackingImpl.qll",
"python/ql/lib/semmle/python/dataflow/new/internal/tainttracking4/TaintTrackingImpl.qll",
"ruby/ql/lib/codeql/ruby/dataflow/internal/tainttracking1/TaintTrackingImpl.qll"
"ruby/ql/lib/codeql/ruby/dataflow/internal/tainttracking1/TaintTrackingImpl.qll",
"ruby/ql/lib/codeql/ruby/dataflow/internal/tainttrackingforlibraries/TaintTrackingImpl.qll"
],
"DataFlow Java/C++/C#/Python Consistency checks": [
"java/ql/lib/semmle/code/java/dataflow/internal/DataFlowImplConsistency.qll",
@@ -480,11 +482,12 @@
"python/ql/lib/semmle/python/security/performance/ReDoSUtil.qll",
"ruby/ql/lib/codeql/ruby/security/performance/ReDoSUtil.qll"
],
"ReDoS Exponential Python/JS": [
"ReDoS Exponential Python/JS/Ruby": [
"javascript/ql/lib/semmle/javascript/security/performance/ExponentialBackTracking.qll",
"python/ql/lib/semmle/python/security/performance/ExponentialBackTracking.qll"
"python/ql/lib/semmle/python/security/performance/ExponentialBackTracking.qll",
"ruby/ql/lib/codeql/ruby/security/performance/ExponentialBackTracking.qll"
],
"ReDoS Polynomial Python/JS": [
"ReDoS Polynomial Python/JS/Ruby": [
"javascript/ql/lib/semmle/javascript/security/performance/SuperlinearBackTracking.qll",
"python/ql/lib/semmle/python/security/performance/SuperlinearBackTracking.qll",
"ruby/ql/lib/codeql/ruby/security/performance/SuperlinearBackTracking.qll"
@@ -515,5 +518,35 @@
"java/ql/lib/semmle/code/java/dataflow/internal/AccessPathSyntax.qll",
"javascript/ql/lib/semmle/javascript/frameworks/data/internal/AccessPathSyntax.qll",
"ruby/ql/lib/codeql/ruby/dataflow/internal/AccessPathSyntax.qll"
],
"Concepts Python/Ruby/JS": [
"python/ql/lib/semmle/python/internal/ConceptsShared.qll",
"ruby/ql/lib/codeql/ruby/internal/ConceptsShared.qll",
"javascript/ql/lib/semmle/javascript/internal/ConceptsShared.qll"
],
"Hostname Regexp queries": [
"javascript/ql/src/Security/CWE-020/HostnameRegexpShared.qll",
"python/ql/src/Security/CWE-020/HostnameRegexpShared.qll",
"ruby/ql/src/queries/security/cwe-020/HostnameRegexpShared.qll"
],
"ApiGraphModels": [
"javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll",
"ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll"
],
"TaintedFormatStringQuery Ruby/JS": [
"javascript/ql/lib/semmle/javascript/security/dataflow/TaintedFormatStringQuery.qll",
"ruby/ql/lib/codeql/ruby/security/TaintedFormatStringQuery.qll"
],
"TaintedFormatStringCustomizations Ruby/JS": [
"javascript/ql/lib/semmle/javascript/security/dataflow/TaintedFormatStringCustomizations.qll",
"ruby/ql/lib/codeql/ruby/security/TaintedFormatStringCustomizations.qll"
],
"HttpToFileAccessQuery JS/Ruby": [
"javascript/ql/lib/semmle/javascript/security/dataflow/HttpToFileAccessQuery.qll",
"ruby/ql/lib/codeql/ruby/security/HttpToFileAccessQuery.qll"
],
"HttpToFileAccessCustomizations JS/Ruby": [
"javascript/ql/lib/semmle/javascript/security/dataflow/HttpToFileAccessCustomizations.qll",
"ruby/ql/lib/codeql/ruby/security/HttpToFileAccessCustomizations.qll"
]
}
}

View File

@@ -0,0 +1,4 @@
---
category: feature
---
* The data flow and taint tracking libraries have been extended with versions of `isBarrierIn`, `isBarrierOut`, and `isBarrierGuard`, respectively `isSanitizerIn`, `isSanitizerOut`, and `isSanitizerGuard`, that support flow states.

View File

@@ -73,8 +73,24 @@ class Location extends @location {
/** Holds if `this` comes on a line strictly before `l`. */
pragma[inline]
predicate isBefore(Location l) {
this.getFile() = l.getFile() and this.getEndLine() < l.getStartLine()
predicate isBefore(Location l) { this.isBefore(l, false) }
/**
* Holds if `this` comes strictly before `l`. The boolean `sameLine` is
* true if `l` is on the same line as `this`, but starts at a later column.
* Otherwise, `sameLine` is false.
*/
pragma[inline]
predicate isBefore(Location l, boolean sameLine) {
this.getFile() = l.getFile() and
(
sameLine = false and
this.getEndLine() < l.getStartLine()
or
sameLine = true and
this.getEndLine() = l.getStartLine() and
this.getEndColumn() < l.getStartColumn()
)
}
/** Holds if location `l` is completely contained within this one. */

View File

@@ -94,6 +94,7 @@ class Type extends Locatable, @type {
* The result of this predicate will be the type itself, except in the case of a TypedefType or a Decltype,
* in which case the result will be type which results from (possibly recursively) resolving typedefs.
*/
pragma[nomagic]
Type getUnderlyingType() { result = this }
/**

View File

@@ -87,12 +87,30 @@ abstract class Configuration extends string {
/** Holds if data flow into `node` is prohibited. */
predicate isBarrierIn(Node node) { none() }
/**
* Holds if data flow into `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierIn(Node node, FlowState state) { none() }
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/**
* Holds if data flow out of `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierOut(Node node, FlowState state) { none() }
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if the additional flow step from `node1` to `node2` must be taken
* into account in the analysis.
@@ -305,7 +323,7 @@ private class RetNodeEx extends NodeEx {
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
}
private predicate inBarrier(NodeEx node, Configuration config) {
private predicate fullInBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n)
@@ -314,7 +332,16 @@ private predicate inBarrier(NodeEx node, Configuration config) {
)
}
private predicate outBarrier(NodeEx node, Configuration config) {
private predicate stateInBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n, state)
|
config.isSource(n, state)
)
}
private predicate fullOutBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n)
@@ -323,6 +350,15 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
private predicate stateOutBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n, state)
|
config.isSink(n, state)
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -345,9 +381,19 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
pragma[nomagic]
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
exists(Node n | node.asNode() = n |
config.isBarrier(n, state)
or
config.isBarrierIn(n, state) and
not config.isSource(n, state)
or
config.isBarrierOut(n, state) and
not config.isSink(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
)
}
@@ -376,8 +422,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
/** Provides the relevant barriers for a step from `node1` to `node2`. */
pragma[inline]
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullOutBarrier(node1, config) and
not fullInBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
@@ -430,6 +476,8 @@ private predicate additionalLocalStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config)
)
@@ -471,6 +519,8 @@ private predicate additionalJumpStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
@@ -870,8 +920,8 @@ private module Stage1 {
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
revFlow(node, true, config) and
fwdFlow(node, true, config) and
not inBarrier(node, config) and
not outBarrier(node, config)
not fullInBarrier(node, config) and
not fullOutBarrier(node, config)
}
/** Holds if flow may return from `callable`. */
@@ -966,8 +1016,8 @@ private predicate flowOutOfCallNodeCand1(
) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and
not inBarrier(out, config)
not fullOutBarrier(ret, config) and
not fullInBarrier(out, config)
}
pragma[nomagic]
@@ -988,8 +1038,8 @@ private predicate flowIntoCallNodeCand1(
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
not outBarrier(arg, config) and
not inBarrier(p, config)
not fullOutBarrier(arg, config) and
not fullInBarrier(p, config)
}
/**
@@ -1706,18 +1756,31 @@ private module LocalFlowBigStep {
* Holds if `node` can be the first node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
private predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
Stage2::revFlow(node, state, config) and
(
sourceNode(node, state, config) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
additionalJumpStateStep(_, _, node, state, config) or
node instanceof ParamNodeEx or
node.asNode() instanceof OutNodeExt or
store(_, _, node, _, config) or
read(_, _, node, config) or
sourceNode(node, state, config)
or
jumpStep(_, node, config)
or
additionalJumpStep(_, node, config)
or
additionalJumpStateStep(_, _, node, state, config)
or
node instanceof ParamNodeEx
or
node.asNode() instanceof OutNodeExt
or
store(_, _, node, _, config)
or
read(_, _, node, config)
or
node instanceof FlowCheckNode
or
exists(FlowState s |
additionalLocalStateStep(_, s, node, state, config) and
s != state
)
)
}
@@ -1737,6 +1800,9 @@ private module LocalFlowBigStep {
or
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
additionalJumpStateStep(node, state, next, s, config)
or
additionalLocalStateStep(node, state, next, s, config) and
s != state
)
or
Stage2::revFlow(node, state, config) and
@@ -1770,42 +1836,40 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
DataFlowType t, Configuration config, LocalCallContext cc
NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t,
Configuration config, LocalCallContext cc
) {
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](state1), pragma[only_bind_into](config)) and
localFlowEntry(node1, pragma[only_bind_into](state), pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
state1 = state2 and
preservesValue = true and
t = node1.getDataFlowType() // irrelevant dummy value
t = node1.getDataFlowType() and // irrelevant dummy value
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
additionalLocalFlowStepNodeCand2(node1, state, node2, state, config) and
preservesValue = false and
t = node2.getDataFlowType()
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall())
or
exists(NodeEx mid |
localFlowStepPlus(node1, state1, mid, pragma[only_bind_into](state2), preservesValue, t,
localFlowStepPlus(node1, pragma[only_bind_into](state), mid, preservesValue, t,
pragma[only_bind_into](config), cc) and
localFlowStepNodeCand1(mid, node2, config) and
not mid instanceof FlowCheckNode and
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
)
or
exists(NodeEx mid, FlowState st |
localFlowStepPlus(node1, state1, mid, st, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, st, node2, state2, config) and
exists(NodeEx mid |
localFlowStepPlus(node1, state, mid, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, state, node2, state, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
t = node2.getDataFlowType() and
Stage2::revFlow(node2, state2, pragma[only_bind_into](config))
t = node2.getDataFlowType()
)
)
}
@@ -1819,9 +1883,19 @@ private module LocalFlowBigStep {
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
) {
localFlowStepPlus(node1, state1, node2, state2, preservesValue, apf.getType(), config,
callContext) and
localFlowExit(node2, state2, config)
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
localFlowExit(node2, state1, config) and
state1 = state2
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and
preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and
callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or
isUnreachableInCallCached(node2.asNode(), call)
)
}
}
@@ -2695,10 +2769,10 @@ private module Stage4 {
bindingset[node, cc, config]
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
localFlowEntry(node, _, config) and
result =
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
node.getEnclosingCallable())
node.getEnclosingCallable()) and
exists(config)
}
private predicate localStep(

View File

@@ -87,12 +87,30 @@ abstract class Configuration extends string {
/** Holds if data flow into `node` is prohibited. */
predicate isBarrierIn(Node node) { none() }
/**
* Holds if data flow into `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierIn(Node node, FlowState state) { none() }
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/**
* Holds if data flow out of `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierOut(Node node, FlowState state) { none() }
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if the additional flow step from `node1` to `node2` must be taken
* into account in the analysis.
@@ -305,7 +323,7 @@ private class RetNodeEx extends NodeEx {
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
}
private predicate inBarrier(NodeEx node, Configuration config) {
private predicate fullInBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n)
@@ -314,7 +332,16 @@ private predicate inBarrier(NodeEx node, Configuration config) {
)
}
private predicate outBarrier(NodeEx node, Configuration config) {
private predicate stateInBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n, state)
|
config.isSource(n, state)
)
}
private predicate fullOutBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n)
@@ -323,6 +350,15 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
private predicate stateOutBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n, state)
|
config.isSink(n, state)
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -345,9 +381,19 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
pragma[nomagic]
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
exists(Node n | node.asNode() = n |
config.isBarrier(n, state)
or
config.isBarrierIn(n, state) and
not config.isSource(n, state)
or
config.isBarrierOut(n, state) and
not config.isSink(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
)
}
@@ -376,8 +422,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
/** Provides the relevant barriers for a step from `node1` to `node2`. */
pragma[inline]
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullOutBarrier(node1, config) and
not fullInBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
@@ -430,6 +476,8 @@ private predicate additionalLocalStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config)
)
@@ -471,6 +519,8 @@ private predicate additionalJumpStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
@@ -870,8 +920,8 @@ private module Stage1 {
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
revFlow(node, true, config) and
fwdFlow(node, true, config) and
not inBarrier(node, config) and
not outBarrier(node, config)
not fullInBarrier(node, config) and
not fullOutBarrier(node, config)
}
/** Holds if flow may return from `callable`. */
@@ -966,8 +1016,8 @@ private predicate flowOutOfCallNodeCand1(
) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and
not inBarrier(out, config)
not fullOutBarrier(ret, config) and
not fullInBarrier(out, config)
}
pragma[nomagic]
@@ -988,8 +1038,8 @@ private predicate flowIntoCallNodeCand1(
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
not outBarrier(arg, config) and
not inBarrier(p, config)
not fullOutBarrier(arg, config) and
not fullInBarrier(p, config)
}
/**
@@ -1706,18 +1756,31 @@ private module LocalFlowBigStep {
* Holds if `node` can be the first node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
private predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
Stage2::revFlow(node, state, config) and
(
sourceNode(node, state, config) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
additionalJumpStateStep(_, _, node, state, config) or
node instanceof ParamNodeEx or
node.asNode() instanceof OutNodeExt or
store(_, _, node, _, config) or
read(_, _, node, config) or
sourceNode(node, state, config)
or
jumpStep(_, node, config)
or
additionalJumpStep(_, node, config)
or
additionalJumpStateStep(_, _, node, state, config)
or
node instanceof ParamNodeEx
or
node.asNode() instanceof OutNodeExt
or
store(_, _, node, _, config)
or
read(_, _, node, config)
or
node instanceof FlowCheckNode
or
exists(FlowState s |
additionalLocalStateStep(_, s, node, state, config) and
s != state
)
)
}
@@ -1737,6 +1800,9 @@ private module LocalFlowBigStep {
or
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
additionalJumpStateStep(node, state, next, s, config)
or
additionalLocalStateStep(node, state, next, s, config) and
s != state
)
or
Stage2::revFlow(node, state, config) and
@@ -1770,42 +1836,40 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
DataFlowType t, Configuration config, LocalCallContext cc
NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t,
Configuration config, LocalCallContext cc
) {
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](state1), pragma[only_bind_into](config)) and
localFlowEntry(node1, pragma[only_bind_into](state), pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
state1 = state2 and
preservesValue = true and
t = node1.getDataFlowType() // irrelevant dummy value
t = node1.getDataFlowType() and // irrelevant dummy value
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
additionalLocalFlowStepNodeCand2(node1, state, node2, state, config) and
preservesValue = false and
t = node2.getDataFlowType()
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall())
or
exists(NodeEx mid |
localFlowStepPlus(node1, state1, mid, pragma[only_bind_into](state2), preservesValue, t,
localFlowStepPlus(node1, pragma[only_bind_into](state), mid, preservesValue, t,
pragma[only_bind_into](config), cc) and
localFlowStepNodeCand1(mid, node2, config) and
not mid instanceof FlowCheckNode and
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
)
or
exists(NodeEx mid, FlowState st |
localFlowStepPlus(node1, state1, mid, st, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, st, node2, state2, config) and
exists(NodeEx mid |
localFlowStepPlus(node1, state, mid, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, state, node2, state, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
t = node2.getDataFlowType() and
Stage2::revFlow(node2, state2, pragma[only_bind_into](config))
t = node2.getDataFlowType()
)
)
}
@@ -1819,9 +1883,19 @@ private module LocalFlowBigStep {
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
) {
localFlowStepPlus(node1, state1, node2, state2, preservesValue, apf.getType(), config,
callContext) and
localFlowExit(node2, state2, config)
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
localFlowExit(node2, state1, config) and
state1 = state2
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and
preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and
callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or
isUnreachableInCallCached(node2.asNode(), call)
)
}
}
@@ -2695,10 +2769,10 @@ private module Stage4 {
bindingset[node, cc, config]
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
localFlowEntry(node, _, config) and
result =
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
node.getEnclosingCallable())
node.getEnclosingCallable()) and
exists(config)
}
private predicate localStep(

View File

@@ -87,12 +87,30 @@ abstract class Configuration extends string {
/** Holds if data flow into `node` is prohibited. */
predicate isBarrierIn(Node node) { none() }
/**
* Holds if data flow into `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierIn(Node node, FlowState state) { none() }
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/**
* Holds if data flow out of `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierOut(Node node, FlowState state) { none() }
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if the additional flow step from `node1` to `node2` must be taken
* into account in the analysis.
@@ -305,7 +323,7 @@ private class RetNodeEx extends NodeEx {
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
}
private predicate inBarrier(NodeEx node, Configuration config) {
private predicate fullInBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n)
@@ -314,7 +332,16 @@ private predicate inBarrier(NodeEx node, Configuration config) {
)
}
private predicate outBarrier(NodeEx node, Configuration config) {
private predicate stateInBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n, state)
|
config.isSource(n, state)
)
}
private predicate fullOutBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n)
@@ -323,6 +350,15 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
private predicate stateOutBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n, state)
|
config.isSink(n, state)
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -345,9 +381,19 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
pragma[nomagic]
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
exists(Node n | node.asNode() = n |
config.isBarrier(n, state)
or
config.isBarrierIn(n, state) and
not config.isSource(n, state)
or
config.isBarrierOut(n, state) and
not config.isSink(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
)
}
@@ -376,8 +422,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
/** Provides the relevant barriers for a step from `node1` to `node2`. */
pragma[inline]
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullOutBarrier(node1, config) and
not fullInBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
@@ -430,6 +476,8 @@ private predicate additionalLocalStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config)
)
@@ -471,6 +519,8 @@ private predicate additionalJumpStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
@@ -870,8 +920,8 @@ private module Stage1 {
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
revFlow(node, true, config) and
fwdFlow(node, true, config) and
not inBarrier(node, config) and
not outBarrier(node, config)
not fullInBarrier(node, config) and
not fullOutBarrier(node, config)
}
/** Holds if flow may return from `callable`. */
@@ -966,8 +1016,8 @@ private predicate flowOutOfCallNodeCand1(
) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and
not inBarrier(out, config)
not fullOutBarrier(ret, config) and
not fullInBarrier(out, config)
}
pragma[nomagic]
@@ -988,8 +1038,8 @@ private predicate flowIntoCallNodeCand1(
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
not outBarrier(arg, config) and
not inBarrier(p, config)
not fullOutBarrier(arg, config) and
not fullInBarrier(p, config)
}
/**
@@ -1706,18 +1756,31 @@ private module LocalFlowBigStep {
* Holds if `node` can be the first node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
private predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
Stage2::revFlow(node, state, config) and
(
sourceNode(node, state, config) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
additionalJumpStateStep(_, _, node, state, config) or
node instanceof ParamNodeEx or
node.asNode() instanceof OutNodeExt or
store(_, _, node, _, config) or
read(_, _, node, config) or
sourceNode(node, state, config)
or
jumpStep(_, node, config)
or
additionalJumpStep(_, node, config)
or
additionalJumpStateStep(_, _, node, state, config)
or
node instanceof ParamNodeEx
or
node.asNode() instanceof OutNodeExt
or
store(_, _, node, _, config)
or
read(_, _, node, config)
or
node instanceof FlowCheckNode
or
exists(FlowState s |
additionalLocalStateStep(_, s, node, state, config) and
s != state
)
)
}
@@ -1737,6 +1800,9 @@ private module LocalFlowBigStep {
or
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
additionalJumpStateStep(node, state, next, s, config)
or
additionalLocalStateStep(node, state, next, s, config) and
s != state
)
or
Stage2::revFlow(node, state, config) and
@@ -1770,42 +1836,40 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
DataFlowType t, Configuration config, LocalCallContext cc
NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t,
Configuration config, LocalCallContext cc
) {
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](state1), pragma[only_bind_into](config)) and
localFlowEntry(node1, pragma[only_bind_into](state), pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
state1 = state2 and
preservesValue = true and
t = node1.getDataFlowType() // irrelevant dummy value
t = node1.getDataFlowType() and // irrelevant dummy value
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
additionalLocalFlowStepNodeCand2(node1, state, node2, state, config) and
preservesValue = false and
t = node2.getDataFlowType()
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall())
or
exists(NodeEx mid |
localFlowStepPlus(node1, state1, mid, pragma[only_bind_into](state2), preservesValue, t,
localFlowStepPlus(node1, pragma[only_bind_into](state), mid, preservesValue, t,
pragma[only_bind_into](config), cc) and
localFlowStepNodeCand1(mid, node2, config) and
not mid instanceof FlowCheckNode and
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
)
or
exists(NodeEx mid, FlowState st |
localFlowStepPlus(node1, state1, mid, st, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, st, node2, state2, config) and
exists(NodeEx mid |
localFlowStepPlus(node1, state, mid, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, state, node2, state, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
t = node2.getDataFlowType() and
Stage2::revFlow(node2, state2, pragma[only_bind_into](config))
t = node2.getDataFlowType()
)
)
}
@@ -1819,9 +1883,19 @@ private module LocalFlowBigStep {
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
) {
localFlowStepPlus(node1, state1, node2, state2, preservesValue, apf.getType(), config,
callContext) and
localFlowExit(node2, state2, config)
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
localFlowExit(node2, state1, config) and
state1 = state2
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and
preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and
callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or
isUnreachableInCallCached(node2.asNode(), call)
)
}
}
@@ -2695,10 +2769,10 @@ private module Stage4 {
bindingset[node, cc, config]
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
localFlowEntry(node, _, config) and
result =
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
node.getEnclosingCallable())
node.getEnclosingCallable()) and
exists(config)
}
private predicate localStep(

View File

@@ -87,12 +87,30 @@ abstract class Configuration extends string {
/** Holds if data flow into `node` is prohibited. */
predicate isBarrierIn(Node node) { none() }
/**
* Holds if data flow into `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierIn(Node node, FlowState state) { none() }
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/**
* Holds if data flow out of `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierOut(Node node, FlowState state) { none() }
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if the additional flow step from `node1` to `node2` must be taken
* into account in the analysis.
@@ -305,7 +323,7 @@ private class RetNodeEx extends NodeEx {
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
}
private predicate inBarrier(NodeEx node, Configuration config) {
private predicate fullInBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n)
@@ -314,7 +332,16 @@ private predicate inBarrier(NodeEx node, Configuration config) {
)
}
private predicate outBarrier(NodeEx node, Configuration config) {
private predicate stateInBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n, state)
|
config.isSource(n, state)
)
}
private predicate fullOutBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n)
@@ -323,6 +350,15 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
private predicate stateOutBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n, state)
|
config.isSink(n, state)
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -345,9 +381,19 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
pragma[nomagic]
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
exists(Node n | node.asNode() = n |
config.isBarrier(n, state)
or
config.isBarrierIn(n, state) and
not config.isSource(n, state)
or
config.isBarrierOut(n, state) and
not config.isSink(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
)
}
@@ -376,8 +422,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
/** Provides the relevant barriers for a step from `node1` to `node2`. */
pragma[inline]
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullOutBarrier(node1, config) and
not fullInBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
@@ -430,6 +476,8 @@ private predicate additionalLocalStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config)
)
@@ -471,6 +519,8 @@ private predicate additionalJumpStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
@@ -870,8 +920,8 @@ private module Stage1 {
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
revFlow(node, true, config) and
fwdFlow(node, true, config) and
not inBarrier(node, config) and
not outBarrier(node, config)
not fullInBarrier(node, config) and
not fullOutBarrier(node, config)
}
/** Holds if flow may return from `callable`. */
@@ -966,8 +1016,8 @@ private predicate flowOutOfCallNodeCand1(
) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and
not inBarrier(out, config)
not fullOutBarrier(ret, config) and
not fullInBarrier(out, config)
}
pragma[nomagic]
@@ -988,8 +1038,8 @@ private predicate flowIntoCallNodeCand1(
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
not outBarrier(arg, config) and
not inBarrier(p, config)
not fullOutBarrier(arg, config) and
not fullInBarrier(p, config)
}
/**
@@ -1706,18 +1756,31 @@ private module LocalFlowBigStep {
* Holds if `node` can be the first node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
private predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
Stage2::revFlow(node, state, config) and
(
sourceNode(node, state, config) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
additionalJumpStateStep(_, _, node, state, config) or
node instanceof ParamNodeEx or
node.asNode() instanceof OutNodeExt or
store(_, _, node, _, config) or
read(_, _, node, config) or
sourceNode(node, state, config)
or
jumpStep(_, node, config)
or
additionalJumpStep(_, node, config)
or
additionalJumpStateStep(_, _, node, state, config)
or
node instanceof ParamNodeEx
or
node.asNode() instanceof OutNodeExt
or
store(_, _, node, _, config)
or
read(_, _, node, config)
or
node instanceof FlowCheckNode
or
exists(FlowState s |
additionalLocalStateStep(_, s, node, state, config) and
s != state
)
)
}
@@ -1737,6 +1800,9 @@ private module LocalFlowBigStep {
or
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
additionalJumpStateStep(node, state, next, s, config)
or
additionalLocalStateStep(node, state, next, s, config) and
s != state
)
or
Stage2::revFlow(node, state, config) and
@@ -1770,42 +1836,40 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
DataFlowType t, Configuration config, LocalCallContext cc
NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t,
Configuration config, LocalCallContext cc
) {
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](state1), pragma[only_bind_into](config)) and
localFlowEntry(node1, pragma[only_bind_into](state), pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
state1 = state2 and
preservesValue = true and
t = node1.getDataFlowType() // irrelevant dummy value
t = node1.getDataFlowType() and // irrelevant dummy value
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
additionalLocalFlowStepNodeCand2(node1, state, node2, state, config) and
preservesValue = false and
t = node2.getDataFlowType()
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall())
or
exists(NodeEx mid |
localFlowStepPlus(node1, state1, mid, pragma[only_bind_into](state2), preservesValue, t,
localFlowStepPlus(node1, pragma[only_bind_into](state), mid, preservesValue, t,
pragma[only_bind_into](config), cc) and
localFlowStepNodeCand1(mid, node2, config) and
not mid instanceof FlowCheckNode and
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
)
or
exists(NodeEx mid, FlowState st |
localFlowStepPlus(node1, state1, mid, st, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, st, node2, state2, config) and
exists(NodeEx mid |
localFlowStepPlus(node1, state, mid, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, state, node2, state, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
t = node2.getDataFlowType() and
Stage2::revFlow(node2, state2, pragma[only_bind_into](config))
t = node2.getDataFlowType()
)
)
}
@@ -1819,9 +1883,19 @@ private module LocalFlowBigStep {
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
) {
localFlowStepPlus(node1, state1, node2, state2, preservesValue, apf.getType(), config,
callContext) and
localFlowExit(node2, state2, config)
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
localFlowExit(node2, state1, config) and
state1 = state2
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and
preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and
callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or
isUnreachableInCallCached(node2.asNode(), call)
)
}
}
@@ -2695,10 +2769,10 @@ private module Stage4 {
bindingset[node, cc, config]
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
localFlowEntry(node, _, config) and
result =
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
node.getEnclosingCallable())
node.getEnclosingCallable()) and
exists(config)
}
private predicate localStep(

View File

@@ -87,12 +87,30 @@ abstract class Configuration extends string {
/** Holds if data flow into `node` is prohibited. */
predicate isBarrierIn(Node node) { none() }
/**
* Holds if data flow into `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierIn(Node node, FlowState state) { none() }
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/**
* Holds if data flow out of `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierOut(Node node, FlowState state) { none() }
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if the additional flow step from `node1` to `node2` must be taken
* into account in the analysis.
@@ -305,7 +323,7 @@ private class RetNodeEx extends NodeEx {
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
}
private predicate inBarrier(NodeEx node, Configuration config) {
private predicate fullInBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n)
@@ -314,7 +332,16 @@ private predicate inBarrier(NodeEx node, Configuration config) {
)
}
private predicate outBarrier(NodeEx node, Configuration config) {
private predicate stateInBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n, state)
|
config.isSource(n, state)
)
}
private predicate fullOutBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n)
@@ -323,6 +350,15 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
private predicate stateOutBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n, state)
|
config.isSink(n, state)
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -345,9 +381,19 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
pragma[nomagic]
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
exists(Node n | node.asNode() = n |
config.isBarrier(n, state)
or
config.isBarrierIn(n, state) and
not config.isSource(n, state)
or
config.isBarrierOut(n, state) and
not config.isSink(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
)
}
@@ -376,8 +422,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
/** Provides the relevant barriers for a step from `node1` to `node2`. */
pragma[inline]
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullOutBarrier(node1, config) and
not fullInBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
@@ -430,6 +476,8 @@ private predicate additionalLocalStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config)
)
@@ -471,6 +519,8 @@ private predicate additionalJumpStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
@@ -870,8 +920,8 @@ private module Stage1 {
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
revFlow(node, true, config) and
fwdFlow(node, true, config) and
not inBarrier(node, config) and
not outBarrier(node, config)
not fullInBarrier(node, config) and
not fullOutBarrier(node, config)
}
/** Holds if flow may return from `callable`. */
@@ -966,8 +1016,8 @@ private predicate flowOutOfCallNodeCand1(
) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and
not inBarrier(out, config)
not fullOutBarrier(ret, config) and
not fullInBarrier(out, config)
}
pragma[nomagic]
@@ -988,8 +1038,8 @@ private predicate flowIntoCallNodeCand1(
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
not outBarrier(arg, config) and
not inBarrier(p, config)
not fullOutBarrier(arg, config) and
not fullInBarrier(p, config)
}
/**
@@ -1706,18 +1756,31 @@ private module LocalFlowBigStep {
* Holds if `node` can be the first node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
private predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
Stage2::revFlow(node, state, config) and
(
sourceNode(node, state, config) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
additionalJumpStateStep(_, _, node, state, config) or
node instanceof ParamNodeEx or
node.asNode() instanceof OutNodeExt or
store(_, _, node, _, config) or
read(_, _, node, config) or
sourceNode(node, state, config)
or
jumpStep(_, node, config)
or
additionalJumpStep(_, node, config)
or
additionalJumpStateStep(_, _, node, state, config)
or
node instanceof ParamNodeEx
or
node.asNode() instanceof OutNodeExt
or
store(_, _, node, _, config)
or
read(_, _, node, config)
or
node instanceof FlowCheckNode
or
exists(FlowState s |
additionalLocalStateStep(_, s, node, state, config) and
s != state
)
)
}
@@ -1737,6 +1800,9 @@ private module LocalFlowBigStep {
or
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
additionalJumpStateStep(node, state, next, s, config)
or
additionalLocalStateStep(node, state, next, s, config) and
s != state
)
or
Stage2::revFlow(node, state, config) and
@@ -1770,42 +1836,40 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
DataFlowType t, Configuration config, LocalCallContext cc
NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t,
Configuration config, LocalCallContext cc
) {
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](state1), pragma[only_bind_into](config)) and
localFlowEntry(node1, pragma[only_bind_into](state), pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
state1 = state2 and
preservesValue = true and
t = node1.getDataFlowType() // irrelevant dummy value
t = node1.getDataFlowType() and // irrelevant dummy value
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
additionalLocalFlowStepNodeCand2(node1, state, node2, state, config) and
preservesValue = false and
t = node2.getDataFlowType()
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall())
or
exists(NodeEx mid |
localFlowStepPlus(node1, state1, mid, pragma[only_bind_into](state2), preservesValue, t,
localFlowStepPlus(node1, pragma[only_bind_into](state), mid, preservesValue, t,
pragma[only_bind_into](config), cc) and
localFlowStepNodeCand1(mid, node2, config) and
not mid instanceof FlowCheckNode and
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
)
or
exists(NodeEx mid, FlowState st |
localFlowStepPlus(node1, state1, mid, st, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, st, node2, state2, config) and
exists(NodeEx mid |
localFlowStepPlus(node1, state, mid, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, state, node2, state, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
t = node2.getDataFlowType() and
Stage2::revFlow(node2, state2, pragma[only_bind_into](config))
t = node2.getDataFlowType()
)
)
}
@@ -1819,9 +1883,19 @@ private module LocalFlowBigStep {
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
) {
localFlowStepPlus(node1, state1, node2, state2, preservesValue, apf.getType(), config,
callContext) and
localFlowExit(node2, state2, config)
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
localFlowExit(node2, state1, config) and
state1 = state2
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and
preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and
callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or
isUnreachableInCallCached(node2.asNode(), call)
)
}
}
@@ -2695,10 +2769,10 @@ private module Stage4 {
bindingset[node, cc, config]
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
localFlowEntry(node, _, config) and
result =
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
node.getEnclosingCallable())
node.getEnclosingCallable()) and
exists(config)
}
private predicate localStep(

View File

@@ -109,6 +109,16 @@ abstract class Configuration extends DataFlow::Configuration {
/** Holds if taint propagation into `node` is prohibited. */
predicate isSanitizerIn(DataFlow::Node node) { none() }
/**
* Holds if taint propagation into `node` is prohibited when the flow state is
* `state`.
*/
predicate isSanitizerIn(DataFlow::Node node, DataFlow::FlowState state) { none() }
final override predicate isBarrierIn(DataFlow::Node node, DataFlow::FlowState state) {
this.isSanitizerIn(node, state)
}
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
/** Holds if taint propagation out of `node` is prohibited. */
@@ -116,6 +126,16 @@ abstract class Configuration extends DataFlow::Configuration {
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
/**
* Holds if taint propagation out of `node` is prohibited when the flow state is
* `state`.
*/
predicate isSanitizerOut(DataFlow::Node node, DataFlow::FlowState state) { none() }
final override predicate isBarrierOut(DataFlow::Node node, DataFlow::FlowState state) {
this.isSanitizerOut(node, state)
}
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
@@ -123,6 +143,16 @@ abstract class Configuration extends DataFlow::Configuration {
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
}
/**
* Holds if taint propagation through nodes guarded by `guard` is prohibited
* when the flow state is `state`.
*/
predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) { none() }
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
this.isSanitizerGuard(guard, state)
}
/**
* Holds if the additional taint propagation step from `node1` to `node2`
* must be taken into account in the analysis.

View File

@@ -109,6 +109,16 @@ abstract class Configuration extends DataFlow::Configuration {
/** Holds if taint propagation into `node` is prohibited. */
predicate isSanitizerIn(DataFlow::Node node) { none() }
/**
* Holds if taint propagation into `node` is prohibited when the flow state is
* `state`.
*/
predicate isSanitizerIn(DataFlow::Node node, DataFlow::FlowState state) { none() }
final override predicate isBarrierIn(DataFlow::Node node, DataFlow::FlowState state) {
this.isSanitizerIn(node, state)
}
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
/** Holds if taint propagation out of `node` is prohibited. */
@@ -116,6 +126,16 @@ abstract class Configuration extends DataFlow::Configuration {
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
/**
* Holds if taint propagation out of `node` is prohibited when the flow state is
* `state`.
*/
predicate isSanitizerOut(DataFlow::Node node, DataFlow::FlowState state) { none() }
final override predicate isBarrierOut(DataFlow::Node node, DataFlow::FlowState state) {
this.isSanitizerOut(node, state)
}
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
@@ -123,6 +143,16 @@ abstract class Configuration extends DataFlow::Configuration {
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
}
/**
* Holds if taint propagation through nodes guarded by `guard` is prohibited
* when the flow state is `state`.
*/
predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) { none() }
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
this.isSanitizerGuard(guard, state)
}
/**
* Holds if the additional taint propagation step from `node1` to `node2`
* must be taken into account in the analysis.

View File

@@ -87,12 +87,30 @@ abstract class Configuration extends string {
/** Holds if data flow into `node` is prohibited. */
predicate isBarrierIn(Node node) { none() }
/**
* Holds if data flow into `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierIn(Node node, FlowState state) { none() }
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/**
* Holds if data flow out of `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierOut(Node node, FlowState state) { none() }
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if the additional flow step from `node1` to `node2` must be taken
* into account in the analysis.
@@ -305,7 +323,7 @@ private class RetNodeEx extends NodeEx {
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
}
private predicate inBarrier(NodeEx node, Configuration config) {
private predicate fullInBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n)
@@ -314,7 +332,16 @@ private predicate inBarrier(NodeEx node, Configuration config) {
)
}
private predicate outBarrier(NodeEx node, Configuration config) {
private predicate stateInBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n, state)
|
config.isSource(n, state)
)
}
private predicate fullOutBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n)
@@ -323,6 +350,15 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
private predicate stateOutBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n, state)
|
config.isSink(n, state)
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -345,9 +381,19 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
pragma[nomagic]
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
exists(Node n | node.asNode() = n |
config.isBarrier(n, state)
or
config.isBarrierIn(n, state) and
not config.isSource(n, state)
or
config.isBarrierOut(n, state) and
not config.isSink(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
)
}
@@ -376,8 +422,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
/** Provides the relevant barriers for a step from `node1` to `node2`. */
pragma[inline]
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullOutBarrier(node1, config) and
not fullInBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
@@ -430,6 +476,8 @@ private predicate additionalLocalStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config)
)
@@ -471,6 +519,8 @@ private predicate additionalJumpStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
@@ -870,8 +920,8 @@ private module Stage1 {
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
revFlow(node, true, config) and
fwdFlow(node, true, config) and
not inBarrier(node, config) and
not outBarrier(node, config)
not fullInBarrier(node, config) and
not fullOutBarrier(node, config)
}
/** Holds if flow may return from `callable`. */
@@ -966,8 +1016,8 @@ private predicate flowOutOfCallNodeCand1(
) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and
not inBarrier(out, config)
not fullOutBarrier(ret, config) and
not fullInBarrier(out, config)
}
pragma[nomagic]
@@ -988,8 +1038,8 @@ private predicate flowIntoCallNodeCand1(
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
not outBarrier(arg, config) and
not inBarrier(p, config)
not fullOutBarrier(arg, config) and
not fullInBarrier(p, config)
}
/**
@@ -1706,18 +1756,31 @@ private module LocalFlowBigStep {
* Holds if `node` can be the first node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
private predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
Stage2::revFlow(node, state, config) and
(
sourceNode(node, state, config) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
additionalJumpStateStep(_, _, node, state, config) or
node instanceof ParamNodeEx or
node.asNode() instanceof OutNodeExt or
store(_, _, node, _, config) or
read(_, _, node, config) or
sourceNode(node, state, config)
or
jumpStep(_, node, config)
or
additionalJumpStep(_, node, config)
or
additionalJumpStateStep(_, _, node, state, config)
or
node instanceof ParamNodeEx
or
node.asNode() instanceof OutNodeExt
or
store(_, _, node, _, config)
or
read(_, _, node, config)
or
node instanceof FlowCheckNode
or
exists(FlowState s |
additionalLocalStateStep(_, s, node, state, config) and
s != state
)
)
}
@@ -1737,6 +1800,9 @@ private module LocalFlowBigStep {
or
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
additionalJumpStateStep(node, state, next, s, config)
or
additionalLocalStateStep(node, state, next, s, config) and
s != state
)
or
Stage2::revFlow(node, state, config) and
@@ -1770,42 +1836,40 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
DataFlowType t, Configuration config, LocalCallContext cc
NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t,
Configuration config, LocalCallContext cc
) {
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](state1), pragma[only_bind_into](config)) and
localFlowEntry(node1, pragma[only_bind_into](state), pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
state1 = state2 and
preservesValue = true and
t = node1.getDataFlowType() // irrelevant dummy value
t = node1.getDataFlowType() and // irrelevant dummy value
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
additionalLocalFlowStepNodeCand2(node1, state, node2, state, config) and
preservesValue = false and
t = node2.getDataFlowType()
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall())
or
exists(NodeEx mid |
localFlowStepPlus(node1, state1, mid, pragma[only_bind_into](state2), preservesValue, t,
localFlowStepPlus(node1, pragma[only_bind_into](state), mid, preservesValue, t,
pragma[only_bind_into](config), cc) and
localFlowStepNodeCand1(mid, node2, config) and
not mid instanceof FlowCheckNode and
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
)
or
exists(NodeEx mid, FlowState st |
localFlowStepPlus(node1, state1, mid, st, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, st, node2, state2, config) and
exists(NodeEx mid |
localFlowStepPlus(node1, state, mid, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, state, node2, state, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
t = node2.getDataFlowType() and
Stage2::revFlow(node2, state2, pragma[only_bind_into](config))
t = node2.getDataFlowType()
)
)
}
@@ -1819,9 +1883,19 @@ private module LocalFlowBigStep {
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
) {
localFlowStepPlus(node1, state1, node2, state2, preservesValue, apf.getType(), config,
callContext) and
localFlowExit(node2, state2, config)
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
localFlowExit(node2, state1, config) and
state1 = state2
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and
preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and
callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or
isUnreachableInCallCached(node2.asNode(), call)
)
}
}
@@ -2695,10 +2769,10 @@ private module Stage4 {
bindingset[node, cc, config]
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
localFlowEntry(node, _, config) and
result =
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
node.getEnclosingCallable())
node.getEnclosingCallable()) and
exists(config)
}
private predicate localStep(

View File

@@ -87,12 +87,30 @@ abstract class Configuration extends string {
/** Holds if data flow into `node` is prohibited. */
predicate isBarrierIn(Node node) { none() }
/**
* Holds if data flow into `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierIn(Node node, FlowState state) { none() }
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/**
* Holds if data flow out of `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierOut(Node node, FlowState state) { none() }
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if the additional flow step from `node1` to `node2` must be taken
* into account in the analysis.
@@ -305,7 +323,7 @@ private class RetNodeEx extends NodeEx {
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
}
private predicate inBarrier(NodeEx node, Configuration config) {
private predicate fullInBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n)
@@ -314,7 +332,16 @@ private predicate inBarrier(NodeEx node, Configuration config) {
)
}
private predicate outBarrier(NodeEx node, Configuration config) {
private predicate stateInBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n, state)
|
config.isSource(n, state)
)
}
private predicate fullOutBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n)
@@ -323,6 +350,15 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
private predicate stateOutBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n, state)
|
config.isSink(n, state)
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -345,9 +381,19 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
pragma[nomagic]
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
exists(Node n | node.asNode() = n |
config.isBarrier(n, state)
or
config.isBarrierIn(n, state) and
not config.isSource(n, state)
or
config.isBarrierOut(n, state) and
not config.isSink(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
)
}
@@ -376,8 +422,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
/** Provides the relevant barriers for a step from `node1` to `node2`. */
pragma[inline]
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullOutBarrier(node1, config) and
not fullInBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
@@ -430,6 +476,8 @@ private predicate additionalLocalStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config)
)
@@ -471,6 +519,8 @@ private predicate additionalJumpStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
@@ -870,8 +920,8 @@ private module Stage1 {
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
revFlow(node, true, config) and
fwdFlow(node, true, config) and
not inBarrier(node, config) and
not outBarrier(node, config)
not fullInBarrier(node, config) and
not fullOutBarrier(node, config)
}
/** Holds if flow may return from `callable`. */
@@ -966,8 +1016,8 @@ private predicate flowOutOfCallNodeCand1(
) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and
not inBarrier(out, config)
not fullOutBarrier(ret, config) and
not fullInBarrier(out, config)
}
pragma[nomagic]
@@ -988,8 +1038,8 @@ private predicate flowIntoCallNodeCand1(
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
not outBarrier(arg, config) and
not inBarrier(p, config)
not fullOutBarrier(arg, config) and
not fullInBarrier(p, config)
}
/**
@@ -1706,18 +1756,31 @@ private module LocalFlowBigStep {
* Holds if `node` can be the first node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
private predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
Stage2::revFlow(node, state, config) and
(
sourceNode(node, state, config) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
additionalJumpStateStep(_, _, node, state, config) or
node instanceof ParamNodeEx or
node.asNode() instanceof OutNodeExt or
store(_, _, node, _, config) or
read(_, _, node, config) or
sourceNode(node, state, config)
or
jumpStep(_, node, config)
or
additionalJumpStep(_, node, config)
or
additionalJumpStateStep(_, _, node, state, config)
or
node instanceof ParamNodeEx
or
node.asNode() instanceof OutNodeExt
or
store(_, _, node, _, config)
or
read(_, _, node, config)
or
node instanceof FlowCheckNode
or
exists(FlowState s |
additionalLocalStateStep(_, s, node, state, config) and
s != state
)
)
}
@@ -1737,6 +1800,9 @@ private module LocalFlowBigStep {
or
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
additionalJumpStateStep(node, state, next, s, config)
or
additionalLocalStateStep(node, state, next, s, config) and
s != state
)
or
Stage2::revFlow(node, state, config) and
@@ -1770,42 +1836,40 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
DataFlowType t, Configuration config, LocalCallContext cc
NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t,
Configuration config, LocalCallContext cc
) {
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](state1), pragma[only_bind_into](config)) and
localFlowEntry(node1, pragma[only_bind_into](state), pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
state1 = state2 and
preservesValue = true and
t = node1.getDataFlowType() // irrelevant dummy value
t = node1.getDataFlowType() and // irrelevant dummy value
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
additionalLocalFlowStepNodeCand2(node1, state, node2, state, config) and
preservesValue = false and
t = node2.getDataFlowType()
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall())
or
exists(NodeEx mid |
localFlowStepPlus(node1, state1, mid, pragma[only_bind_into](state2), preservesValue, t,
localFlowStepPlus(node1, pragma[only_bind_into](state), mid, preservesValue, t,
pragma[only_bind_into](config), cc) and
localFlowStepNodeCand1(mid, node2, config) and
not mid instanceof FlowCheckNode and
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
)
or
exists(NodeEx mid, FlowState st |
localFlowStepPlus(node1, state1, mid, st, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, st, node2, state2, config) and
exists(NodeEx mid |
localFlowStepPlus(node1, state, mid, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, state, node2, state, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
t = node2.getDataFlowType() and
Stage2::revFlow(node2, state2, pragma[only_bind_into](config))
t = node2.getDataFlowType()
)
)
}
@@ -1819,9 +1883,19 @@ private module LocalFlowBigStep {
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
) {
localFlowStepPlus(node1, state1, node2, state2, preservesValue, apf.getType(), config,
callContext) and
localFlowExit(node2, state2, config)
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
localFlowExit(node2, state1, config) and
state1 = state2
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and
preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and
callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or
isUnreachableInCallCached(node2.asNode(), call)
)
}
}
@@ -2695,10 +2769,10 @@ private module Stage4 {
bindingset[node, cc, config]
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
localFlowEntry(node, _, config) and
result =
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
node.getEnclosingCallable())
node.getEnclosingCallable()) and
exists(config)
}
private predicate localStep(

View File

@@ -87,12 +87,30 @@ abstract class Configuration extends string {
/** Holds if data flow into `node` is prohibited. */
predicate isBarrierIn(Node node) { none() }
/**
* Holds if data flow into `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierIn(Node node, FlowState state) { none() }
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/**
* Holds if data flow out of `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierOut(Node node, FlowState state) { none() }
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if the additional flow step from `node1` to `node2` must be taken
* into account in the analysis.
@@ -305,7 +323,7 @@ private class RetNodeEx extends NodeEx {
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
}
private predicate inBarrier(NodeEx node, Configuration config) {
private predicate fullInBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n)
@@ -314,7 +332,16 @@ private predicate inBarrier(NodeEx node, Configuration config) {
)
}
private predicate outBarrier(NodeEx node, Configuration config) {
private predicate stateInBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n, state)
|
config.isSource(n, state)
)
}
private predicate fullOutBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n)
@@ -323,6 +350,15 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
private predicate stateOutBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n, state)
|
config.isSink(n, state)
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -345,9 +381,19 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
pragma[nomagic]
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
exists(Node n | node.asNode() = n |
config.isBarrier(n, state)
or
config.isBarrierIn(n, state) and
not config.isSource(n, state)
or
config.isBarrierOut(n, state) and
not config.isSink(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
)
}
@@ -376,8 +422,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
/** Provides the relevant barriers for a step from `node1` to `node2`. */
pragma[inline]
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullOutBarrier(node1, config) and
not fullInBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
@@ -430,6 +476,8 @@ private predicate additionalLocalStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config)
)
@@ -471,6 +519,8 @@ private predicate additionalJumpStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
@@ -870,8 +920,8 @@ private module Stage1 {
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
revFlow(node, true, config) and
fwdFlow(node, true, config) and
not inBarrier(node, config) and
not outBarrier(node, config)
not fullInBarrier(node, config) and
not fullOutBarrier(node, config)
}
/** Holds if flow may return from `callable`. */
@@ -966,8 +1016,8 @@ private predicate flowOutOfCallNodeCand1(
) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and
not inBarrier(out, config)
not fullOutBarrier(ret, config) and
not fullInBarrier(out, config)
}
pragma[nomagic]
@@ -988,8 +1038,8 @@ private predicate flowIntoCallNodeCand1(
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
not outBarrier(arg, config) and
not inBarrier(p, config)
not fullOutBarrier(arg, config) and
not fullInBarrier(p, config)
}
/**
@@ -1706,18 +1756,31 @@ private module LocalFlowBigStep {
* Holds if `node` can be the first node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
private predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
Stage2::revFlow(node, state, config) and
(
sourceNode(node, state, config) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
additionalJumpStateStep(_, _, node, state, config) or
node instanceof ParamNodeEx or
node.asNode() instanceof OutNodeExt or
store(_, _, node, _, config) or
read(_, _, node, config) or
sourceNode(node, state, config)
or
jumpStep(_, node, config)
or
additionalJumpStep(_, node, config)
or
additionalJumpStateStep(_, _, node, state, config)
or
node instanceof ParamNodeEx
or
node.asNode() instanceof OutNodeExt
or
store(_, _, node, _, config)
or
read(_, _, node, config)
or
node instanceof FlowCheckNode
or
exists(FlowState s |
additionalLocalStateStep(_, s, node, state, config) and
s != state
)
)
}
@@ -1737,6 +1800,9 @@ private module LocalFlowBigStep {
or
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
additionalJumpStateStep(node, state, next, s, config)
or
additionalLocalStateStep(node, state, next, s, config) and
s != state
)
or
Stage2::revFlow(node, state, config) and
@@ -1770,42 +1836,40 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
DataFlowType t, Configuration config, LocalCallContext cc
NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t,
Configuration config, LocalCallContext cc
) {
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](state1), pragma[only_bind_into](config)) and
localFlowEntry(node1, pragma[only_bind_into](state), pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
state1 = state2 and
preservesValue = true and
t = node1.getDataFlowType() // irrelevant dummy value
t = node1.getDataFlowType() and // irrelevant dummy value
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
additionalLocalFlowStepNodeCand2(node1, state, node2, state, config) and
preservesValue = false and
t = node2.getDataFlowType()
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall())
or
exists(NodeEx mid |
localFlowStepPlus(node1, state1, mid, pragma[only_bind_into](state2), preservesValue, t,
localFlowStepPlus(node1, pragma[only_bind_into](state), mid, preservesValue, t,
pragma[only_bind_into](config), cc) and
localFlowStepNodeCand1(mid, node2, config) and
not mid instanceof FlowCheckNode and
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
)
or
exists(NodeEx mid, FlowState st |
localFlowStepPlus(node1, state1, mid, st, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, st, node2, state2, config) and
exists(NodeEx mid |
localFlowStepPlus(node1, state, mid, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, state, node2, state, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
t = node2.getDataFlowType() and
Stage2::revFlow(node2, state2, pragma[only_bind_into](config))
t = node2.getDataFlowType()
)
)
}
@@ -1819,9 +1883,19 @@ private module LocalFlowBigStep {
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
) {
localFlowStepPlus(node1, state1, node2, state2, preservesValue, apf.getType(), config,
callContext) and
localFlowExit(node2, state2, config)
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
localFlowExit(node2, state1, config) and
state1 = state2
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and
preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and
callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or
isUnreachableInCallCached(node2.asNode(), call)
)
}
}
@@ -2695,10 +2769,10 @@ private module Stage4 {
bindingset[node, cc, config]
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
localFlowEntry(node, _, config) and
result =
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
node.getEnclosingCallable())
node.getEnclosingCallable()) and
exists(config)
}
private predicate localStep(

View File

@@ -87,12 +87,30 @@ abstract class Configuration extends string {
/** Holds if data flow into `node` is prohibited. */
predicate isBarrierIn(Node node) { none() }
/**
* Holds if data flow into `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierIn(Node node, FlowState state) { none() }
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/**
* Holds if data flow out of `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierOut(Node node, FlowState state) { none() }
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if the additional flow step from `node1` to `node2` must be taken
* into account in the analysis.
@@ -305,7 +323,7 @@ private class RetNodeEx extends NodeEx {
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
}
private predicate inBarrier(NodeEx node, Configuration config) {
private predicate fullInBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n)
@@ -314,7 +332,16 @@ private predicate inBarrier(NodeEx node, Configuration config) {
)
}
private predicate outBarrier(NodeEx node, Configuration config) {
private predicate stateInBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n, state)
|
config.isSource(n, state)
)
}
private predicate fullOutBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n)
@@ -323,6 +350,15 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
private predicate stateOutBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n, state)
|
config.isSink(n, state)
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -345,9 +381,19 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
pragma[nomagic]
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
exists(Node n | node.asNode() = n |
config.isBarrier(n, state)
or
config.isBarrierIn(n, state) and
not config.isSource(n, state)
or
config.isBarrierOut(n, state) and
not config.isSink(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
)
}
@@ -376,8 +422,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
/** Provides the relevant barriers for a step from `node1` to `node2`. */
pragma[inline]
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullOutBarrier(node1, config) and
not fullInBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
@@ -430,6 +476,8 @@ private predicate additionalLocalStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config)
)
@@ -471,6 +519,8 @@ private predicate additionalJumpStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
@@ -870,8 +920,8 @@ private module Stage1 {
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
revFlow(node, true, config) and
fwdFlow(node, true, config) and
not inBarrier(node, config) and
not outBarrier(node, config)
not fullInBarrier(node, config) and
not fullOutBarrier(node, config)
}
/** Holds if flow may return from `callable`. */
@@ -966,8 +1016,8 @@ private predicate flowOutOfCallNodeCand1(
) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and
not inBarrier(out, config)
not fullOutBarrier(ret, config) and
not fullInBarrier(out, config)
}
pragma[nomagic]
@@ -988,8 +1038,8 @@ private predicate flowIntoCallNodeCand1(
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
not outBarrier(arg, config) and
not inBarrier(p, config)
not fullOutBarrier(arg, config) and
not fullInBarrier(p, config)
}
/**
@@ -1706,18 +1756,31 @@ private module LocalFlowBigStep {
* Holds if `node` can be the first node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
private predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
Stage2::revFlow(node, state, config) and
(
sourceNode(node, state, config) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
additionalJumpStateStep(_, _, node, state, config) or
node instanceof ParamNodeEx or
node.asNode() instanceof OutNodeExt or
store(_, _, node, _, config) or
read(_, _, node, config) or
sourceNode(node, state, config)
or
jumpStep(_, node, config)
or
additionalJumpStep(_, node, config)
or
additionalJumpStateStep(_, _, node, state, config)
or
node instanceof ParamNodeEx
or
node.asNode() instanceof OutNodeExt
or
store(_, _, node, _, config)
or
read(_, _, node, config)
or
node instanceof FlowCheckNode
or
exists(FlowState s |
additionalLocalStateStep(_, s, node, state, config) and
s != state
)
)
}
@@ -1737,6 +1800,9 @@ private module LocalFlowBigStep {
or
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
additionalJumpStateStep(node, state, next, s, config)
or
additionalLocalStateStep(node, state, next, s, config) and
s != state
)
or
Stage2::revFlow(node, state, config) and
@@ -1770,42 +1836,40 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
DataFlowType t, Configuration config, LocalCallContext cc
NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t,
Configuration config, LocalCallContext cc
) {
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](state1), pragma[only_bind_into](config)) and
localFlowEntry(node1, pragma[only_bind_into](state), pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
state1 = state2 and
preservesValue = true and
t = node1.getDataFlowType() // irrelevant dummy value
t = node1.getDataFlowType() and // irrelevant dummy value
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
additionalLocalFlowStepNodeCand2(node1, state, node2, state, config) and
preservesValue = false and
t = node2.getDataFlowType()
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall())
or
exists(NodeEx mid |
localFlowStepPlus(node1, state1, mid, pragma[only_bind_into](state2), preservesValue, t,
localFlowStepPlus(node1, pragma[only_bind_into](state), mid, preservesValue, t,
pragma[only_bind_into](config), cc) and
localFlowStepNodeCand1(mid, node2, config) and
not mid instanceof FlowCheckNode and
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
)
or
exists(NodeEx mid, FlowState st |
localFlowStepPlus(node1, state1, mid, st, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, st, node2, state2, config) and
exists(NodeEx mid |
localFlowStepPlus(node1, state, mid, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, state, node2, state, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
t = node2.getDataFlowType() and
Stage2::revFlow(node2, state2, pragma[only_bind_into](config))
t = node2.getDataFlowType()
)
)
}
@@ -1819,9 +1883,19 @@ private module LocalFlowBigStep {
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
) {
localFlowStepPlus(node1, state1, node2, state2, preservesValue, apf.getType(), config,
callContext) and
localFlowExit(node2, state2, config)
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
localFlowExit(node2, state1, config) and
state1 = state2
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and
preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and
callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or
isUnreachableInCallCached(node2.asNode(), call)
)
}
}
@@ -2695,10 +2769,10 @@ private module Stage4 {
bindingset[node, cc, config]
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
localFlowEntry(node, _, config) and
result =
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
node.getEnclosingCallable())
node.getEnclosingCallable()) and
exists(config)
}
private predicate localStep(

View File

@@ -109,6 +109,16 @@ abstract class Configuration extends DataFlow::Configuration {
/** Holds if taint propagation into `node` is prohibited. */
predicate isSanitizerIn(DataFlow::Node node) { none() }
/**
* Holds if taint propagation into `node` is prohibited when the flow state is
* `state`.
*/
predicate isSanitizerIn(DataFlow::Node node, DataFlow::FlowState state) { none() }
final override predicate isBarrierIn(DataFlow::Node node, DataFlow::FlowState state) {
this.isSanitizerIn(node, state)
}
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
/** Holds if taint propagation out of `node` is prohibited. */
@@ -116,6 +126,16 @@ abstract class Configuration extends DataFlow::Configuration {
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
/**
* Holds if taint propagation out of `node` is prohibited when the flow state is
* `state`.
*/
predicate isSanitizerOut(DataFlow::Node node, DataFlow::FlowState state) { none() }
final override predicate isBarrierOut(DataFlow::Node node, DataFlow::FlowState state) {
this.isSanitizerOut(node, state)
}
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
@@ -123,6 +143,16 @@ abstract class Configuration extends DataFlow::Configuration {
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
}
/**
* Holds if taint propagation through nodes guarded by `guard` is prohibited
* when the flow state is `state`.
*/
predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) { none() }
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
this.isSanitizerGuard(guard, state)
}
/**
* Holds if the additional taint propagation step from `node1` to `node2`
* must be taken into account in the analysis.

View File

@@ -109,6 +109,16 @@ abstract class Configuration extends DataFlow::Configuration {
/** Holds if taint propagation into `node` is prohibited. */
predicate isSanitizerIn(DataFlow::Node node) { none() }
/**
* Holds if taint propagation into `node` is prohibited when the flow state is
* `state`.
*/
predicate isSanitizerIn(DataFlow::Node node, DataFlow::FlowState state) { none() }
final override predicate isBarrierIn(DataFlow::Node node, DataFlow::FlowState state) {
this.isSanitizerIn(node, state)
}
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
/** Holds if taint propagation out of `node` is prohibited. */
@@ -116,6 +126,16 @@ abstract class Configuration extends DataFlow::Configuration {
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
/**
* Holds if taint propagation out of `node` is prohibited when the flow state is
* `state`.
*/
predicate isSanitizerOut(DataFlow::Node node, DataFlow::FlowState state) { none() }
final override predicate isBarrierOut(DataFlow::Node node, DataFlow::FlowState state) {
this.isSanitizerOut(node, state)
}
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
@@ -123,6 +143,16 @@ abstract class Configuration extends DataFlow::Configuration {
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
}
/**
* Holds if taint propagation through nodes guarded by `guard` is prohibited
* when the flow state is `state`.
*/
predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) { none() }
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
this.isSanitizerGuard(guard, state)
}
/**
* Holds if the additional taint propagation step from `node1` to `node2`
* must be taken into account in the analysis.

View File

@@ -109,6 +109,16 @@ abstract class Configuration extends DataFlow::Configuration {
/** Holds if taint propagation into `node` is prohibited. */
predicate isSanitizerIn(DataFlow::Node node) { none() }
/**
* Holds if taint propagation into `node` is prohibited when the flow state is
* `state`.
*/
predicate isSanitizerIn(DataFlow::Node node, DataFlow::FlowState state) { none() }
final override predicate isBarrierIn(DataFlow::Node node, DataFlow::FlowState state) {
this.isSanitizerIn(node, state)
}
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
/** Holds if taint propagation out of `node` is prohibited. */
@@ -116,6 +126,16 @@ abstract class Configuration extends DataFlow::Configuration {
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
/**
* Holds if taint propagation out of `node` is prohibited when the flow state is
* `state`.
*/
predicate isSanitizerOut(DataFlow::Node node, DataFlow::FlowState state) { none() }
final override predicate isBarrierOut(DataFlow::Node node, DataFlow::FlowState state) {
this.isSanitizerOut(node, state)
}
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
@@ -123,6 +143,16 @@ abstract class Configuration extends DataFlow::Configuration {
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
}
/**
* Holds if taint propagation through nodes guarded by `guard` is prohibited
* when the flow state is `state`.
*/
predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) { none() }
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
this.isSanitizerGuard(guard, state)
}
/**
* Holds if the additional taint propagation step from `node1` to `node2`
* must be taken into account in the analysis.

View File

@@ -161,8 +161,13 @@ class IRBlock extends IRBlockBase {
*/
pragma[noinline]
final IRBlock dominanceFrontier() {
this.dominates(result.getAPredecessor()) and
not this.strictlyDominates(result)
this.getASuccessor() = result and
not this.immediatelyDominates(result)
or
exists(IRBlock prev | result = prev.dominanceFrontier() |
this.immediatelyDominates(prev) and
not this.immediatelyDominates(result)
)
}
/**
@@ -201,8 +206,13 @@ class IRBlock extends IRBlockBase {
*/
pragma[noinline]
final IRBlock postDominanceFrontier() {
this.postDominates(result.getASuccessor()) and
not this.strictlyPostDominates(result)
this.getAPredecessor() = result and
not this.immediatelyPostDominates(result)
or
exists(IRBlock prev | result = prev.postDominanceFrontier() |
this.immediatelyPostDominates(prev) and
not this.immediatelyPostDominates(result)
)
}
/**

View File

@@ -161,8 +161,13 @@ class IRBlock extends IRBlockBase {
*/
pragma[noinline]
final IRBlock dominanceFrontier() {
this.dominates(result.getAPredecessor()) and
not this.strictlyDominates(result)
this.getASuccessor() = result and
not this.immediatelyDominates(result)
or
exists(IRBlock prev | result = prev.dominanceFrontier() |
this.immediatelyDominates(prev) and
not this.immediatelyDominates(result)
)
}
/**
@@ -201,8 +206,13 @@ class IRBlock extends IRBlockBase {
*/
pragma[noinline]
final IRBlock postDominanceFrontier() {
this.postDominates(result.getASuccessor()) and
not this.strictlyPostDominates(result)
this.getAPredecessor() = result and
not this.immediatelyPostDominates(result)
or
exists(IRBlock prev | result = prev.postDominanceFrontier() |
this.immediatelyPostDominates(prev) and
not this.immediatelyPostDominates(result)
)
}
/**

View File

@@ -349,7 +349,7 @@ Instruction getInstructionBackEdgeSuccessor(Instruction instruction, EdgeKind ki
/** Holds if `goto` jumps strictly forward in the program text. */
private predicate isStrictlyForwardGoto(GotoStmt goto) {
goto.getLocation().isBefore(goto.getTarget().getLocation())
goto.getLocation().isBefore(goto.getTarget().getLocation(), _)
}
Locatable getInstructionAst(TStageInstruction instr) {

View File

@@ -154,13 +154,6 @@ private predicate ignoreSideEffects(Expr expr) {
* around extractor bugs. Once the relevant extractor bugs are fixed, this predicate can be removed.
*/
private predicate isInvalidFunction(Function func) {
exists(Literal literal |
// Constructor field inits within a compiler-generated copy constructor have a source expression
// that is a `Literal` with no value.
literal = func.(Constructor).getAnInitializer().(ConstructorFieldInit).getExpr() and
not exists(literal.getValue())
)
or
exists(ThisExpr thisExpr |
// An instantiation of a member function template is not treated as a `MemberFunction` if it has
// only non-type template arguments.

View File

@@ -161,8 +161,13 @@ class IRBlock extends IRBlockBase {
*/
pragma[noinline]
final IRBlock dominanceFrontier() {
this.dominates(result.getAPredecessor()) and
not this.strictlyDominates(result)
this.getASuccessor() = result and
not this.immediatelyDominates(result)
or
exists(IRBlock prev | result = prev.dominanceFrontier() |
this.immediatelyDominates(prev) and
not this.immediatelyDominates(result)
)
}
/**
@@ -201,8 +206,13 @@ class IRBlock extends IRBlockBase {
*/
pragma[noinline]
final IRBlock postDominanceFrontier() {
this.postDominates(result.getASuccessor()) and
not this.strictlyPostDominates(result)
this.getAPredecessor() = result and
not this.immediatelyPostDominates(result)
or
exists(IRBlock prev | result = prev.postDominanceFrontier() |
this.immediatelyPostDominates(prev) and
not this.immediatelyPostDominates(result)
)
}
/**

View File

@@ -92,6 +92,7 @@ abstract class FormattingFunction extends ArrayFunction, TaintFunction {
* snapshots there may be multiple results where we can't tell which is correct for a
* particular function.
*/
pragma[nomagic]
Type getWideCharType() {
result = getFormatCharType() and
result.getSize() > 1

View File

@@ -0,0 +1,21 @@
/**
* @name Extraction errors
* @description List all extraction errors for files in the source code directory.
* @kind diagnostic
* @id cpp/diagnostics/extraction-errors
*/
import cpp
import ExtractionErrors
// NOTE:
// This file looks like the other `diagnostics/extraction-errors` queries in other CodeQL supported
// languages. However, since this diagnostic query is located in the `Internal` subdirectory it will not
// appear in the Code Scanning suite. The related query `cpp/diagnostics/extraction-warnings` is,
// however, included as a public diagnostics query.
from ExtractionError error
where
error instanceof ExtractionUnknownError or
exists(error.getFile().getRelativePath())
select error, "Extraction failed in " + error.getFile() + " with error " + error.getErrorMessage(),
error.getSeverity()

View File

@@ -0,0 +1,137 @@
/**
* Provides a common hierarchy of all types of errors that can occur during extraction.
*/
import cpp
/*
* A note about how the C/C++ extractor emits diagnostics:
* When the extractor frontend encounters an error, it emits a diagnostic message,
* that includes a message, location and severity.
* However, that process is best-effort and may fail (e.g. due to lack of memory).
* Thus, if the extractor emitted at least one diagnostic of severity discretionary
* error (or higher), it *also* emits a simple "There was an error during this compilation"
* error diagnostic, without location information.
* In the common case, this means that a compilation during which one or more errors happened also gets
* the catch-all diagnostic.
* This diagnostic has the empty string as file path.
* We filter out these useless diagnostics if there is at least one error-level diagnostic
* for the affected compilation in the database.
* Otherwise, we show it to indicate that something went wrong and that we
* don't know what exactly happened.
*/
/**
* An error that, if present, leads to a file being marked as non-successfully extracted.
*/
class ReportableError extends Diagnostic {
ReportableError() {
(
this instanceof CompilerDiscretionaryError or
this instanceof CompilerError or
this instanceof CompilerCatastrophe
) and
// Filter for the catch-all diagnostic, see note above.
not this.getFile().getAbsolutePath() = ""
}
}
private newtype TExtractionError =
TReportableError(ReportableError err) or
TCompilationFailed(Compilation c, File f) {
f = c.getAFileCompiled() and not c.normalTermination()
} or
// Show the catch-all diagnostic (see note above) only if we haven't seen any other error-level diagnostic
// for that compilation
TUnknownError(CompilerError err) {
not exists(ReportableError e | e.getCompilation() = err.getCompilation())
}
/**
* Superclass for the extraction error hierarchy.
*/
class ExtractionError extends TExtractionError {
/** Gets the string representation of the error. */
string toString() { none() }
/** Gets the error message for this error. */
string getErrorMessage() { none() }
/** Gets the file this error occured in. */
File getFile() { none() }
/** Gets the location this error occured in. */
Location getLocation() { none() }
/** Gets the SARIF severity of this error. */
int getSeverity() {
// Unfortunately, we can't distinguish between errors and fatal errors in SARIF,
// so all errors have severity 2.
result = 2
}
}
/**
* An unrecoverable extraction error, where extraction was unable to finish.
* This can be caused by a multitude of reasons, for example:
* - hitting a frontend assertion
* - crashing due to dereferencing an invalid pointer
* - stack overflow
* - out of memory
*/
class ExtractionUnrecoverableError extends ExtractionError, TCompilationFailed {
Compilation c;
File f;
ExtractionUnrecoverableError() { this = TCompilationFailed(c, f) }
override string toString() {
result = "Unrecoverable extraction error while compiling " + f.toString()
}
override string getErrorMessage() { result = "unrecoverable compilation failure." }
override File getFile() { result = f }
override Location getLocation() { result = f.getLocation() }
}
/**
* A recoverable extraction error.
* These are compiler errors from the frontend.
* Upon encountering one of these, we still continue extraction, but the
* database will be incomplete for that file.
*/
class ExtractionRecoverableError extends ExtractionError, TReportableError {
ReportableError err;
ExtractionRecoverableError() { this = TReportableError(err) }
override string toString() { result = "Recoverable extraction error: " + err }
override string getErrorMessage() { result = err.getFullMessage() }
override File getFile() { result = err.getFile() }
override Location getLocation() { result = err.getLocation() }
}
/**
* An unknown error happened during extraction.
* These are only displayed if we know that we encountered an error during extraction,
* but, for some reason, failed to emit a proper diagnostic with location information
* and error message.
*/
class ExtractionUnknownError extends ExtractionError, TUnknownError {
CompilerError err;
ExtractionUnknownError() { this = TUnknownError(err) }
override string toString() { result = "Unknown extraction error: " + err }
override string getErrorMessage() { result = err.getFullMessage() }
override File getFile() { result = err.getFile() }
override Location getLocation() { result = err.getLocation() }
}

View File

@@ -19,9 +19,9 @@ import semmle.code.cpp.security.Security
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
import semmle.code.cpp.ir.IR
import semmle.code.cpp.ir.dataflow.TaintTracking
import semmle.code.cpp.ir.dataflow.TaintTracking2
import semmle.code.cpp.security.FlowSources
import semmle.code.cpp.models.implementations.Strcat
import DataFlow::PathGraph
Expr sinkAsArgumentIndirection(DataFlow::Node sink) {
result =
@@ -66,154 +66,70 @@ predicate interestingConcatenation(DataFlow::Node fst, DataFlow::Node snd) {
)
}
class TaintToConcatenationConfiguration extends TaintTracking::Configuration {
TaintToConcatenationConfiguration() { this = "TaintToConcatenationConfiguration" }
override predicate isSource(DataFlow::Node source) { source instanceof FlowSource }
override predicate isSink(DataFlow::Node sink) { interestingConcatenation(sink, _) }
override predicate isSanitizer(DataFlow::Node node) {
node.asInstruction().getResultType() instanceof IntegralType
or
node.asInstruction().getResultType() instanceof FloatingPointType
}
class ConcatState extends DataFlow::FlowState {
ConcatState() { this = "ConcatState" }
}
class ExecTaintConfiguration extends TaintTracking2::Configuration {
class ExecState extends DataFlow::FlowState {
DataFlow::Node fst;
DataFlow::Node snd;
ExecState() {
this =
"ExecState (" + fst.getLocation() + " | " + fst + ", " + snd.getLocation() + " | " + snd + ")" and
interestingConcatenation(fst, snd)
}
DataFlow::Node getFstNode() { result = fst }
DataFlow::Node getSndNode() { result = snd }
}
class ExecTaintConfiguration extends TaintTracking::Configuration {
ExecTaintConfiguration() { this = "ExecTaintConfiguration" }
override predicate isSource(DataFlow::Node source) {
exists(DataFlow::Node prevSink, TaintToConcatenationConfiguration conf |
conf.hasFlow(_, prevSink) and
interestingConcatenation(prevSink, source)
)
override predicate isSource(DataFlow::Node source, DataFlow::FlowState state) {
source instanceof FlowSource and
state instanceof ConcatState
}
override predicate isSink(DataFlow::Node sink) {
shellCommand(sinkAsArgumentIndirection(sink), _)
override predicate isSink(DataFlow::Node sink, DataFlow::FlowState state) {
shellCommand(sinkAsArgumentIndirection(sink), _) and
state instanceof ExecState
}
override predicate isSanitizerOut(DataFlow::Node node) {
isSink(node) // Prevent duplicates along a call chain, since `shellCommand` will include wrappers
}
}
module StitchedPathGraph {
// There's a different PathNode class for each DataFlowImplN.qll, so we can't simply combine the
// PathGraph predicates directly. Instead, we use a newtype so there's a single type that
// contains both sets of PathNodes.
newtype TMergedPathNode =
TPathNode1(DataFlow::PathNode node) or
TPathNode2(DataFlow2::PathNode node)
// this wraps the toString and location predicates so we can use the merged node type in a
// selection
class MergedPathNode extends TMergedPathNode {
string toString() {
exists(DataFlow::PathNode n |
this = TPathNode1(n) and
result = n.toString()
)
or
exists(DataFlow2::PathNode n |
this = TPathNode2(n) and
result = n.toString()
)
}
DataFlow::Node getNode() {
exists(DataFlow::PathNode n |
this = TPathNode1(n) and
result = n.getNode()
)
or
exists(DataFlow2::PathNode n |
this = TPathNode2(n) and
result = n.getNode()
)
}
DataFlow::PathNode getPathNode1() { this = TPathNode1(result) }
DataFlow2::PathNode getPathNode2() { this = TPathNode2(result) }
predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
) {
exists(DataFlow::PathNode n |
this = TPathNode1(n) and
n.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
)
or
exists(DataFlow2::PathNode n |
this = TPathNode2(n) and
n.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
)
}
}
query predicate edges(MergedPathNode a, MergedPathNode b) {
exists(DataFlow::PathNode an, DataFlow::PathNode bn |
a = TPathNode1(an) and
b = TPathNode1(bn) and
DataFlow::PathGraph::edges(an, bn)
)
or
exists(DataFlow2::PathNode an, DataFlow2::PathNode bn |
a = TPathNode2(an) and
b = TPathNode2(bn) and
DataFlow2::PathGraph::edges(an, bn)
)
or
// This is where paths from the two configurations are connected. `interestingConcatenation`
// is the only thing in this module that's actually specific to the query - everything else is
// just using types and predicates from the DataFlow library.
interestingConcatenation(a.getNode(), b.getNode()) and
a instanceof TPathNode1 and
b instanceof TPathNode2
}
query predicate nodes(MergedPathNode mpn, string key, string val) {
// here we just need the union of the underlying `nodes` predicates
exists(DataFlow::PathNode n |
mpn = TPathNode1(n) and
DataFlow::PathGraph::nodes(n, key, val)
)
or
exists(DataFlow2::PathNode n |
mpn = TPathNode2(n) and
DataFlow2::PathGraph::nodes(n, key, val)
)
}
query predicate subpaths(
MergedPathNode arg, MergedPathNode par, MergedPathNode ret, MergedPathNode out
override predicate isAdditionalTaintStep(
DataFlow::Node node1, DataFlow::FlowState state1, DataFlow::Node node2,
DataFlow::FlowState state2
) {
// just forward subpaths from the underlying libraries. This might be slightly awkward when
// the concatenation is deep in a call chain.
DataFlow::PathGraph::subpaths(arg.getPathNode1(), par.getPathNode1(), ret.getPathNode1(),
out.getPathNode1())
or
DataFlow2::PathGraph::subpaths(arg.getPathNode2(), par.getPathNode2(), ret.getPathNode2(),
out.getPathNode2())
state1 instanceof ConcatState and
state2.(ExecState).getFstNode() = node1 and
state2.(ExecState).getSndNode() = node2
}
override predicate isSanitizer(DataFlow::Node node, DataFlow::FlowState state) {
(
node.asInstruction().getResultType() instanceof IntegralType
or
node.asInstruction().getResultType() instanceof FloatingPointType
) and
state instanceof ConcatState
}
override predicate isSanitizerOut(DataFlow::Node node, DataFlow::FlowState state) {
isSink(node, state) // Prevent duplicates along a call chain, since `shellCommand` will include wrappers
}
}
import StitchedPathGraph
from
DataFlow::PathNode sourceNode, DataFlow::PathNode concatSink, DataFlow2::PathNode concatSource,
DataFlow2::PathNode sinkNode, string taintCause, string callChain,
TaintToConcatenationConfiguration conf1, ExecTaintConfiguration conf2
ExecTaintConfiguration conf, DataFlow::PathNode sourceNode, DataFlow::PathNode sinkNode,
string taintCause, string callChain, DataFlow::Node concatResult
where
conf.hasFlowPath(sourceNode, sinkNode) and
taintCause = sourceNode.getNode().(FlowSource).getSourceType() and
conf1.hasFlowPath(sourceNode, concatSink) and
interestingConcatenation(concatSink.getNode(), concatSource.getNode()) and // this loses call context
conf2.hasFlowPath(concatSource, sinkNode) and
shellCommand(sinkAsArgumentIndirection(sinkNode.getNode()), callChain)
select sinkAsArgumentIndirection(sinkNode.getNode()), TPathNode1(sourceNode).(MergedPathNode),
TPathNode2(sinkNode).(MergedPathNode),
shellCommand(sinkAsArgumentIndirection(sinkNode.getNode()), callChain) and
concatResult = sinkNode.getState().(ExecState).getSndNode()
select sinkAsArgumentIndirection(sinkNode.getNode()), sourceNode, sinkNode,
"This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to "
+ callChain, sourceNode, "user input (" + taintCause + ")", concatSource,
concatSource.toString()
+ callChain, sourceNode, "user input (" + taintCause + ")", concatResult,
concatResult.toString()

View File

@@ -3,17 +3,17 @@
"qhelp.dtd">
<qhelp>
<overview>
<p>Exposing system data or debugging information may help an adversary to learn about the system and form an attack plan. An attacker can use error messages that reveal technologies, operating systems, and product versions to tune their attack against known vulnerabilities in these technologies.</p>
<p>Exposing system data or debugging information may help a malicious user learn about the system and form an attack plan. An attacker can use error messages that reveal technologies, operating systems, and product versions to tune their attack against known vulnerabilities in the software.</p>
<p>This query finds locations where system configuration information might be revealed to a user.</p>
<p>This query finds locations where system configuration information might be revealed to a remote user.</p>
</overview>
<recommendation>
<p>Do not expose system configuration information to users. Be wary of the difference between information that could be helpful to users, and unnecessary details that could be useful to an adversary.</p>
<p>Do not expose system configuration information to remote users. Be wary of the difference between information that could be helpful to users, and unnecessary details that could be useful to a malicious user.</p>
</recommendation>
<example>
<p>In this example the value of the <code>PATH</code> environment variable is revealed in full to the user when a particular error occurs. This might reveal information such as the software installed on your system to an adversary who does not have legitimate access to that information.</p>
<p>In this example the value of the <code>PATH</code> environment variable is revealed in full to the user when a particular error occurs. This might reveal information such as the software installed on your system to a malicious user who does not have legitimate access to that information.</p>
<sample src="ExposedSystemDataIncorrect.cpp" />

View File

@@ -1,7 +1,7 @@
/**
* @name Exposure of system data to an unauthorized control sphere
* @description Exposing system data or debugging information helps
* an adversary learn about the system and form an
* a malicious user learn about the system and form an
* attack plan.
* @kind path-problem
* @problem.severity warning
@@ -13,284 +13,15 @@
*/
import cpp
import semmle.code.cpp.commons.Environment
import semmle.code.cpp.ir.dataflow.TaintTracking
import semmle.code.cpp.models.interfaces.FlowSource
import DataFlow::PathGraph
/**
* An element that should not be exposed to an adversary.
*/
abstract class SystemData extends Element {
/**
* Gets an expression that is part of this `SystemData`.
*/
abstract Expr getAnExpr();
}
/**
* Data originating from the environment.
*/
class EnvData extends SystemData {
EnvData() {
// identify risky looking environment variables only
this.(EnvironmentRead)
.getEnvironmentVariable()
.toLowerCase()
.regexpMatch(".*(user|host|admin|root|home|path|http|ssl|snmp|sock|port|proxy|pass|token|crypt|key).*")
}
override Expr getAnExpr() { result = this }
}
/**
* Data originating from a call to `mysql_get_client_info()`.
*/
class SqlClientInfo extends SystemData {
SqlClientInfo() { this.(FunctionCall).getTarget().hasName("mysql_get_client_info") }
override Expr getAnExpr() { result = this }
}
private predicate sqlConnectInfo(FunctionCall source, VariableAccess use) {
(
source.getTarget().hasName("mysql_connect") or
source.getTarget().hasName("mysql_real_connect")
) and
use = source.getAnArgument()
}
/**
* Data passed into an SQL connect function.
*/
class SqlConnectInfo extends SystemData {
SqlConnectInfo() { sqlConnectInfo(this, _) }
override Expr getAnExpr() { sqlConnectInfo(this, result) }
}
private predicate posixSystemInfo(FunctionCall source, Element use) {
// size_t confstr(int name, char *buf, size_t len)
// - various OS / system strings, such as the libc version
// int statvfs(const char *__path, struct statvfs *__buf)
// int fstatvfs(int __fd, struct statvfs *__buf)
// - various filesystem parameters
// int uname(struct utsname *buf)
// - OS name and version
source.getTarget().hasName(["confstr", "statvfs", "fstatvfs", "uname"]) and
use = source.getArgument(1)
}
/**
* Data obtained from a POSIX system information call.
*/
class PosixSystemInfo extends SystemData {
PosixSystemInfo() { posixSystemInfo(this, _) }
override Expr getAnExpr() { posixSystemInfo(this, result) }
}
private predicate posixPWInfo(FunctionCall source, Element use) {
// struct passwd *getpwnam(const char *name);
// struct passwd *getpwuid(uid_t uid);
// struct passwd *getpwent(void);
// struct group *getgrnam(const char *name);
// struct group *getgrgid(gid_t);
// struct group *getgrent(void);
source
.getTarget()
.hasName(["getpwnam", "getpwuid", "getpwent", "getgrnam", "getgrgid", "getgrent"]) and
use = source
or
// int getpwnam_r(const char *name, struct passwd *pwd,
// char *buf, size_t buflen, struct passwd **result);
// int getpwuid_r(uid_t uid, struct passwd *pwd,
// char *buf, size_t buflen, struct passwd **result);
// int getgrgid_r(gid_t gid, struct group *grp,
// char *buf, size_t buflen, struct group **result);
// int getgrnam_r(const char *name, struct group *grp,
// char *buf, size_t buflen, struct group **result);
source.getTarget().hasName(["getpwnam_r", "getpwuid_r", "getgrgid_r", "getgrnam_r"]) and
use = source.getArgument([1, 2, 4])
or
// int getpwent_r(struct passwd *pwd, char *buffer, size_t bufsize,
// struct passwd **result);
// int getgrent_r(struct group *gbuf, char *buf,
// size_t buflen, struct group **gbufp);
source.getTarget().hasName(["getpwent_r", "getgrent_r"]) and
use = source.getArgument([0, 1, 3])
}
/**
* Data obtained from a POSIX user/password/group database information call.
*/
class PosixPWInfo extends SystemData {
PosixPWInfo() { posixPWInfo(this, _) }
override Expr getAnExpr() { posixPWInfo(this, result) }
}
private predicate windowsSystemInfo(FunctionCall source, Element use) {
// DWORD WINAPI GetVersion(void);
source.getTarget().hasGlobalName("GetVersion") and
use = source
or
// BOOL WINAPI GetVersionEx(_Inout_ LPOSVERSIONINFO lpVersionInfo);
// void WINAPI GetSystemInfo(_Out_ LPSYSTEM_INFO lpSystemInfo);
// void WINAPI GetNativeSystemInfo(_Out_ LPSYSTEM_INFO lpSystemInfo);
source
.getTarget()
.hasGlobalName([
"GetVersionEx", "GetVersionExA", "GetVersionExW", "GetSystemInfo", "GetNativeSystemInfo"
]) and
use = source.getArgument(0)
}
/**
* Data obtained from a Windows system information call.
*/
class WindowsSystemInfo extends SystemData {
WindowsSystemInfo() { windowsSystemInfo(this, _) }
override Expr getAnExpr() { windowsSystemInfo(this, result) }
}
private predicate windowsFolderPath(FunctionCall source, Element use) {
// BOOL SHGetSpecialFolderPath(
// HWND hwndOwner,
// _Out_ LPTSTR lpszPath,
// _In_ int csidl,
// _In_ BOOL fCreate
// );
source
.getTarget()
.hasGlobalName([
"SHGetSpecialFolderPath", "SHGetSpecialFolderPathA", "SHGetSpecialFolderPathW"
]) and
use = source.getArgument(1)
or
// HRESULT SHGetKnownFolderPath(
// _In_ REFKNOWNFOLDERID rfid,
// _In_ DWORD dwFlags,
// _In_opt_ HANDLE hToken,
// _Out_ PWSTR *ppszPath
// );
source.getTarget().hasGlobalName("SHGetKnownFolderPath") and
use = source.getArgument(3)
or
// HRESULT SHGetFolderPath(
// _In_ HWND hwndOwner,
// _In_ int nFolder,
// _In_ HANDLE hToken,
// _In_ DWORD dwFlags,
// _Out_ LPTSTR pszPath
// );
source.getTarget().hasGlobalName(["SHGetFolderPath", "SHGetFolderPathA", "SHGetFolderPathW"]) and
use = source.getArgument(4)
or
// HRESULT SHGetFolderPathAndSubDir(
// _In_ HWND hwnd,
// _In_ int csidl,
// _In_ HANDLE hToken,
// _In_ DWORD dwFlags,
// _In_ LPCTSTR pszSubDir,
// _Out_ LPTSTR pszPath
// );
source
.getTarget()
.hasGlobalName([
"SHGetFolderPathAndSubDir", "SHGetFolderPathAndSubDirA", "SHGetFolderPathAndSubDirW"
]) and
use = source.getArgument(5)
}
/**
* Data obtained about Windows special paths (for example, the
* location of `System32`).
*/
class WindowsFolderPath extends SystemData {
WindowsFolderPath() { windowsFolderPath(this, _) }
override Expr getAnExpr() { windowsFolderPath(this, result) }
}
private predicate logonUser(FunctionCall source, VariableAccess use) {
source.getTarget().hasGlobalName(["LogonUser", "LogonUserW", "LogonUserA"]) and
use = source.getAnArgument()
}
/**
* Data passed into a `LogonUser` (Windows) function.
*/
class LogonUser extends SystemData {
LogonUser() { logonUser(this, _) }
override Expr getAnExpr() { logonUser(this, result) }
}
private predicate regQuery(FunctionCall source, VariableAccess use) {
// LONG WINAPI RegQueryValue(
// _In_ HKEY hKey,
// _In_opt_ LPCTSTR lpSubKey,
// _Out_opt_ LPTSTR lpValue,
// _Inout_opt_ PLONG lpcbValue
// );
source.getTarget().hasGlobalName(["RegQueryValue", "RegQueryValueA", "RegQueryValueW"]) and
use = source.getArgument(2)
or
// LONG WINAPI RegQueryMultipleValues(
// _In_ HKEY hKey,
// _Out_ PVALENT val_list,
// _In_ DWORD num_vals,
// _Out_opt_ LPTSTR lpValueBuf,
// _Inout_opt_ LPDWORD ldwTotsize
// );
source
.getTarget()
.hasGlobalName([
"RegQueryMultipleValues", "RegQueryMultipleValuesA", "RegQueryMultipleValuesW"
]) and
use = source.getArgument(3)
or
// LONG WINAPI RegQueryValueEx(
// _In_ HKEY hKey,
// _In_opt_ LPCTSTR lpValueName,
// _Reserved_ LPDWORD lpReserved,
// _Out_opt_ LPDWORD lpType,
// _Out_opt_ LPBYTE lpData,
// _Inout_opt_ LPDWORD lpcbData
// );
source.getTarget().hasGlobalName(["RegQueryValueEx", "RegQueryValueExA", "RegQueryValueExW"]) and
use = source.getArgument(4)
or
// LONG WINAPI RegGetValue(
// _In_ HKEY hkey,
// _In_opt_ LPCTSTR lpSubKey,
// _In_opt_ LPCTSTR lpValue,
// _In_opt_ DWORD dwFlags,
// _Out_opt_ LPDWORD pdwType,
// _Out_opt_ PVOID pvData,
// _Inout_opt_ LPDWORD pcbData
// );
source.getTarget().hasGlobalName(["RegGetValue", "RegGetValueA", "RegGetValueW"]) and
use = source.getArgument(5)
}
/**
* Data read from the Windows registry.
*/
class RegQuery extends SystemData {
RegQuery() { regQuery(this, _) }
override Expr getAnExpr() { regQuery(this, result) }
}
import SystemData
class ExposedSystemDataConfiguration extends TaintTracking::Configuration {
ExposedSystemDataConfiguration() { this = "ExposedSystemDataConfiguration" }
override predicate isSource(DataFlow::Node source) {
source.asConvertedExpr() = any(SystemData sd).getAnExpr()
}
override predicate isSource(DataFlow::Node source) { source = any(SystemData sd).getAnExpr() }
override predicate isSink(DataFlow::Node sink) {
exists(FunctionCall fc, FunctionInput input, int arg |

View File

@@ -2,6 +2,5 @@ char* path = getenv("PATH");
//...
fprintf(stderr, "A required executable file could not be found. " \
"Please ensure that the software has been installed " \
"correctly or contact a system administrator.\n");
message = "An internal error has occurred. Please try again or contact a system administrator.\n";
send(socket, message, strlen(message), 0);

View File

@@ -2,4 +2,5 @@ char* path = getenv("PATH");
//...
fprintf(stderr, "cannot find exe on path %s\n", path);
sprintf(buffer, "Cannot find exe on path: %s", path);
send(socket, buffer, strlen(buffer), 0);

View File

@@ -0,0 +1,28 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>Exposing system data or debugging information may help a malicious user learn about the system and form an attack plan. An attacker can use error messages that reveal technologies, operating systems, and product versions to tune their attack against known vulnerabilities in the software.</p>
<p>This query finds locations where system configuration information that is particularly sensitive might be revealed to a user.</p>
</overview>
<recommendation>
<p>Do not expose system configuration information to users. Be wary of the difference between information that could be helpful to users, and unnecessary details that could be useful to a malicious user.</p>
</recommendation>
<example>
<p>In this example the value of the <code>PATH</code> environment variable is revealed in full to the user when a particular error occurs. This might reveal information such as the software installed on your system to a malicious user who does not have legitimate access to that information.</p>
<sample src="PotentiallyExposedSystemDataIncorrect.cpp" />
<p>The message should be rephrased without this information, for example:</p>
<sample src="PotentiallyExposedSystemDataCorrect.cpp" />
</example>
<references>
</references>
</qhelp>

View File

@@ -0,0 +1,51 @@
/**
* @name Potential exposure of sensitive system data to an unauthorized control sphere
* @description Exposing sensitive system data helps
* a malicious user learn about the system and form an
* attack plan.
* @kind path-problem
* @problem.severity warning
* @security-severity 6.5
* @precision medium
* @id cpp/potential-system-data-exposure
* @tags security
* external/cwe/cwe-497
*/
/*
* These queries are closely related:
* - `cpp/system-data-exposure`, which flags exposure of system information
* to a remote sink (i.e. focusses on quality of the sink).
* - `cpp/potential-system-data-exposure`, which flags on exposure of the most
* sensitive information to a local sink (i.e. focusses on quality of the
* sensitive information).
*
* This used to be a single query with neither focus, which was too noisy and
* gave the user less control.
*/
import cpp
import semmle.code.cpp.ir.dataflow.TaintTracking
import semmle.code.cpp.models.interfaces.FlowSource
import semmle.code.cpp.security.OutputWrite
import DataFlow::PathGraph
import SystemData
class PotentiallyExposedSystemDataConfiguration extends TaintTracking::Configuration {
PotentiallyExposedSystemDataConfiguration() { this = "PotentiallyExposedSystemDataConfiguration" }
override predicate isSource(DataFlow::Node source) {
source = any(SystemData sd | sd.isSensitive()).getAnExpr()
}
override predicate isSink(DataFlow::Node sink) {
exists(OutputWrite ow | ow.getASource().getAChild*() = sink.asExpr())
}
}
from
PotentiallyExposedSystemDataConfiguration config, DataFlow::PathNode source,
DataFlow::PathNode sink
where config.hasFlowPath(source, sink)
select sink, source, sink, "This operation potentially exposes sensitive system data from $@.",
source, source.getNode().toString()

View File

@@ -0,0 +1,5 @@
char* key = getenv("APP_KEY");
//...
fprintf(stderr, "Application key not recognized. Please ensure the key is correct or contact a system administrator.\n", key);

View File

@@ -0,0 +1,5 @@
char* key = getenv("APP_KEY");
//...
fprintf(stderr, "Key not recognized: %s\n", key);

View File

@@ -0,0 +1,342 @@
/**
* Classes for recognizing system data, used by the exposed system data queries.
*/
import cpp
import semmle.code.cpp.commons.Environment
import semmle.code.cpp.ir.dataflow.TaintTracking
/**
* An element that should not be exposed to a malicious user.
*/
abstract class SystemData extends Element {
/**
* Gets an expression that is part of this `SystemData`.
*/
abstract DataFlow::Node getAnExpr();
/**
* Holds if this system data is considered especially sensitive (for example
* a password or token).
*/
predicate isSensitive() { none() }
}
/**
* Data originating from the environment.
*/
class EnvData extends SystemData {
EnvData() {
// identify risky looking environment variables only
this.(EnvironmentRead)
.getEnvironmentVariable()
.toLowerCase()
.regexpMatch(".*(user|host|admin|root|home|path|http|ssl|snmp|sock|port|proxy|pass|token|crypt|key).*")
}
override DataFlow::Node getAnExpr() { result.asConvertedExpr() = this }
override predicate isSensitive() {
this.(EnvironmentRead)
.getEnvironmentVariable()
.toLowerCase()
.regexpMatch(".*(pass|token|key).*")
}
}
/**
* Data originating from a call to `mysql_get_client_info()`.
*/
class SQLClientInfo extends SystemData {
SQLClientInfo() { this.(FunctionCall).getTarget().hasName("mysql_get_client_info") }
override DataFlow::Node getAnExpr() { result.asConvertedExpr() = this }
override predicate isSensitive() { any() }
}
private predicate sqlConnectInfo(FunctionCall source, Expr use) {
(
source.getTarget().hasName("mysql_connect") or
source.getTarget().hasName("mysql_real_connect")
) and
use = source.getAnArgument()
}
/**
* Data passed into an SQL connect function.
*/
class SQLConnectInfo extends SystemData {
SQLConnectInfo() { sqlConnectInfo(this, _) }
override DataFlow::Node getAnExpr() { sqlConnectInfo(this, result.asConvertedExpr()) }
override predicate isSensitive() { any() }
}
private predicate posixSystemInfo(FunctionCall source, DataFlow::Node use) {
// size_t confstr(int name, char *buf, size_t len)
// - various OS / system strings, such as the libc version
// int statvfs(const char *__path, struct statvfs *__buf)
// int fstatvfs(int __fd, struct statvfs *__buf)
source.getTarget().hasName(["confstr", "statvfs", "fstatvfs"]) and
use.asDefiningArgument() = source.getArgument(1)
or
// - various filesystem parameters
// int uname(struct utsname *buf)
// - OS name and version
source.getTarget().hasName("uname") and
use.asDefiningArgument() = source.getArgument(0)
}
/**
* Data obtained from a POSIX system information call.
*/
class PosixSystemInfo extends SystemData {
PosixSystemInfo() { posixSystemInfo(this, _) }
override DataFlow::Node getAnExpr() { posixSystemInfo(this, result) }
}
private predicate posixPWInfo(FunctionCall source, DataFlow::Node use) {
// struct passwd *getpwnam(const char *name);
// struct passwd *getpwuid(uid_t uid);
// struct passwd *getpwent(void);
// struct group *getgrnam(const char *name);
// struct group *getgrgid(gid_t);
// struct group *getgrent(void);
source
.getTarget()
.hasName(["getpwnam", "getpwuid", "getpwent", "getgrnam", "getgrgid", "getgrent"]) and
use.asConvertedExpr() = source
or
// int getpwnam_r(const char *name, struct passwd *pwd,
// char *buf, size_t buflen, struct passwd **result);
// int getpwuid_r(uid_t uid, struct passwd *pwd,
// char *buf, size_t buflen, struct passwd **result);
// int getgrgid_r(gid_t gid, struct group *grp,
// char *buf, size_t buflen, struct group **result);
// int getgrnam_r(const char *name, struct group *grp,
// char *buf, size_t buflen, struct group **result);
source.getTarget().hasName(["getpwnam_r", "getpwuid_r", "getgrgid_r", "getgrnam_r"]) and
(
use.asConvertedExpr() = source.getArgument([1, 2]) or
use.asDefiningArgument() = source.getArgument(4)
)
or
// int getpwent_r(struct passwd *pwd, char *buffer, size_t bufsize,
// struct passwd **result);
// int getgrent_r(struct group *gbuf, char *buf,
// size_t buflen, struct group **gbufp);
source.getTarget().hasName(["getpwent_r", "getgrent_r"]) and
(
use.asConvertedExpr() = source.getArgument([0, 1]) or
use.asDefiningArgument() = source.getArgument(3)
)
}
/**
* Data obtained from a POSIX user/password/group database information call.
*/
class PosixPWInfo extends SystemData {
PosixPWInfo() { posixPWInfo(this, _) }
override DataFlow::Node getAnExpr() { posixPWInfo(this, result) }
override predicate isSensitive() { any() }
}
private predicate windowsSystemInfo(FunctionCall source, DataFlow::Node use) {
// DWORD WINAPI GetVersion(void);
source.getTarget().hasGlobalName("GetVersion") and
use.asConvertedExpr() = source
or
// BOOL WINAPI GetVersionEx(_Inout_ LPOSVERSIONINFO lpVersionInfo);
// void WINAPI GetSystemInfo(_Out_ LPSYSTEM_INFO lpSystemInfo);
// void WINAPI GetNativeSystemInfo(_Out_ LPSYSTEM_INFO lpSystemInfo);
source
.getTarget()
.hasGlobalName([
"GetVersionEx", "GetVersionExA", "GetVersionExW", "GetSystemInfo", "GetNativeSystemInfo"
]) and
use.asDefiningArgument() = source.getArgument(0)
}
/**
* Data obtained from a Windows system information call.
*/
class WindowsSystemInfo extends SystemData {
WindowsSystemInfo() { windowsSystemInfo(this, _) }
override DataFlow::Node getAnExpr() { windowsSystemInfo(this, result) }
}
private predicate windowsFolderPath(FunctionCall source, Element use) {
// BOOL SHGetSpecialFolderPath(
// HWND hwndOwner,
// _Out_ LPTSTR lpszPath,
// _In_ int csidl,
// _In_ BOOL fCreate
// );
source
.getTarget()
.hasGlobalName([
"SHGetSpecialFolderPath", "SHGetSpecialFolderPathA", "SHGetSpecialFolderPathW"
]) and
use = source.getArgument(1)
or
// HRESULT SHGetKnownFolderPath(
// _In_ REFKNOWNFOLDERID rfid,
// _In_ DWORD dwFlags,
// _In_opt_ HANDLE hToken,
// _Out_ PWSTR *ppszPath
// );
source.getTarget().hasGlobalName("SHGetKnownFolderPath") and
use = source.getArgument(3)
or
// HRESULT SHGetFolderPath(
// _In_ HWND hwndOwner,
// _In_ int nFolder,
// _In_ HANDLE hToken,
// _In_ DWORD dwFlags,
// _Out_ LPTSTR pszPath
// );
source.getTarget().hasGlobalName(["SHGetFolderPath", "SHGetFolderPathA", "SHGetFolderPathW"]) and
use = source.getArgument(4)
or
// HRESULT SHGetFolderPathAndSubDir(
// _In_ HWND hwnd,
// _In_ int csidl,
// _In_ HANDLE hToken,
// _In_ DWORD dwFlags,
// _In_ LPCTSTR pszSubDir,
// _Out_ LPTSTR pszPath
// );
source
.getTarget()
.hasGlobalName([
"SHGetFolderPathAndSubDir", "SHGetFolderPathAndSubDirA", "SHGetFolderPathAndSubDirW"
]) and
use = source.getArgument(5)
}
/**
* Data obtained about Windows special paths (for example, the
* location of `System32`).
*/
class WindowsFolderPath extends SystemData {
WindowsFolderPath() { windowsFolderPath(this, _) }
override DataFlow::Node getAnExpr() { windowsFolderPath(this, result.asDefiningArgument()) }
}
private predicate logonUser(FunctionCall source, VariableAccess use) {
source.getTarget().hasGlobalName(["LogonUser", "LogonUserW", "LogonUserA"]) and
use = source.getAnArgument()
}
/**
* Data passed into a `LogonUser` (Windows) function.
*/
class LogonUser extends SystemData {
LogonUser() { logonUser(this, _) }
override DataFlow::Node getAnExpr() { logonUser(this, result.asConvertedExpr()) }
override predicate isSensitive() { any() }
}
/**
* The type of a registry query parameter, if it is of interest to us. This
* is used to express information about registry query parameters in the
* `regQuery` predicate concisely.
*/
private newtype TRegQueryParameter =
TSubKeyName() or
TValueName() or
TReturnData()
/**
* Registry query call (`source`) with information about parameters (`param`).
*/
private predicate regQuery(FunctionCall source, TRegQueryParameter paramType, Expr param) {
// LONG WINAPI RegQueryValue(
// _In_ HKEY hKey,
// _In_opt_ LPCTSTR lpSubKey,
// _Out_opt_ LPTSTR lpValue,
// _Inout_opt_ PLONG lpcbValue
// );
source.getTarget().hasGlobalName(["RegQueryValue", "RegQueryValueA", "RegQueryValueW"]) and
(
paramType = TSubKeyName() and param = source.getArgument(1)
or
paramType = TReturnData() and param = source.getArgument(2)
)
or
// LONG WINAPI RegQueryMultipleValues(
// _In_ HKEY hKey,
// _Out_ PVALENT val_list,
// _In_ DWORD num_vals,
// _Out_opt_ LPTSTR lpValueBuf,
// _Inout_opt_ LPDWORD ldwTotsize
// );
source
.getTarget()
.hasGlobalName([
"RegQueryMultipleValues", "RegQueryMultipleValuesA", "RegQueryMultipleValuesW"
]) and
paramType = TReturnData() and
param = source.getArgument(3)
or
// LONG WINAPI RegQueryValueEx(
// _In_ HKEY hKey,
// _In_opt_ LPCTSTR lpValueName,
// _Reserved_ LPDWORD lpReserved,
// _Out_opt_ LPDWORD lpType,
// _Out_opt_ LPBYTE lpData,
// _Inout_opt_ LPDWORD lpcbData
// );
source.getTarget().hasGlobalName(["RegQueryValueEx", "RegQueryValueExA", "RegQueryValueExW"]) and
(
paramType = TValueName() and param = source.getArgument(1)
or
paramType = TReturnData() and param = source.getArgument(4)
)
or
// LONG WINAPI RegGetValue(
// _In_ HKEY hkey,
// _In_opt_ LPCTSTR lpSubKey,
// _In_opt_ LPCTSTR lpValue,
// _In_opt_ DWORD dwFlags,
// _Out_opt_ LPDWORD pdwType,
// _Out_opt_ PVOID pvData,
// _Inout_opt_ LPDWORD pcbData
// );
source.getTarget().hasGlobalName(["RegGetValue", "RegGetValueA", "RegGetValueW"]) and
(
paramType = TSubKeyName() and param = source.getArgument(1)
or
paramType = TValueName() and param = source.getArgument(2)
or
paramType = TReturnData() and param = source.getArgument(5)
)
}
/**
* Data read from the Windows registry.
*/
class RegQuery extends SystemData {
RegQuery() { regQuery(this, _, _) }
override DataFlow::Node getAnExpr() { regQuery(this, TReturnData(), result.asDefiningArgument()) }
override predicate isSensitive() {
exists(Expr e |
(
regQuery(this, TSubKeyName(), e) or
regQuery(this, TValueName(), e)
) and
e.getValue().toLowerCase().regexpMatch(".*(pass|token|key).*")
)
}
}

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* A new query, "Potential exposure of sensitive system data to an unauthorized control sphere" (`cpp/potential-system-data-exposure`) has been added. This query is focused on exposure of information that is highly likely to be sensitive, whereas the similar query "Exposure of system data to an unauthorized control sphere" (`cpp/system-data-exposure`) is focused on exposure of information on a channel that is more likely to be intercepted by an attacker.

View File

@@ -0,0 +1,4 @@
---
category: minorAnalysis
---
* The `cpp/command-line-injection` query now takes into account calling contexts across string concatenations. This removes false positives due to mismatched calling contexts before and after string concatenations.

View File

@@ -3,4 +3,3 @@
- apply: code-scanning-selectors.yml
from: codeql/suite-helpers
- apply: codeql-suites/exclude-slow-queries.yml
from: codeql/cpp-queries

View File

@@ -3,7 +3,6 @@
- apply: lgtm-selectors.yml
from: codeql/suite-helpers
- apply: codeql-suites/exclude-slow-queries.yml
from: codeql/cpp-queries
# These are only for IDE use.
- exclude:
tags contain:

View File

@@ -3,4 +3,3 @@
- apply: security-and-quality-selectors.yml
from: codeql/suite-helpers
- apply: codeql-suites/exclude-slow-queries.yml
from: codeql/cpp-queries

View File

@@ -3,4 +3,3 @@
- apply: security-extended-selectors.yml
from: codeql/suite-helpers
- apply: codeql-suites/exclude-slow-queries.yml
from: codeql/cpp-queries

View File

@@ -0,0 +1,46 @@
/**
* @name Linux kernel double-fetch vulnerability detection
* @description Double-fetch is a very common vulnerability pattern
* in linux kernel, attacker can exploit double-fetch
* issues to obatain root privilege.
* Double-fetch is caused by fetching data from user
* mode by calling copy_from_user twice, CVE-2016-6480
* is quite a good example for your information.
* @kind problem
* @id cpp/linux-kernel-double-fetch-vulnerability
* @problem.severity warning
* @security-severity 7.5
* @tags security
* external/cwe/cwe-362
*/
import cpp
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
class CopyFromUserFunctionCall extends FunctionCall {
CopyFromUserFunctionCall() {
this.getTarget().getName() = "copy_from_user" and
not this.getArgument(1) instanceof AddressOfExpr
}
//root cause of double-fetech issue is read from
//the same user mode memory twice, so it makes
//sense that only check user mode pointer
predicate readFromSameUserModePointer(CopyFromUserFunctionCall another) {
globalValueNumber(this.getArgument(1)) = globalValueNumber(another.getArgument(1))
}
}
from CopyFromUserFunctionCall p1, CopyFromUserFunctionCall p2
where
not p1 = p2 and
p1.readFromSameUserModePointer(p2) and
exists(IfStmt ifStmt |
p1.getBasicBlock().getAFalseSuccessor*() = ifStmt.getBasicBlock() and
ifStmt.getBasicBlock().getAFalseSuccessor*() = p2.getBasicBlock()
) and
not exists(AssignPointerAddExpr assignPtrAdd |
globalValueNumber(p1.getArgument(1)) = globalValueNumber(assignPtrAdd.getLValue()) and
p1.getBasicBlock().getAFalseSuccessor*() = assignPtrAdd.getBasicBlock()
)
select p2, "Double fetch vulnerability. First fetch was $@.", p1, p1.toString()

View File

@@ -208,11 +208,16 @@ postWithInFlow
| lambdas.cpp:13:7:13:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:13:10:17:2 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:13:10:17:2 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:13:11:13:11 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:13:11:13:11 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:16:3:16:11 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:20:7:20:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:20:10:24:2 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:20:10:24:2 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:20:10:24:2 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:20:11:20:11 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:20:11:20:11 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:20:11:20:11 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:23:3:23:3 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:23:3:23:14 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:23:3:23:14 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
@@ -220,6 +225,8 @@ postWithInFlow
| lambdas.cpp:28:7:28:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:28:10:31:2 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:28:10:31:2 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:28:11:28:11 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:28:11:28:11 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:34:7:34:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:34:13:34:13 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:40:7:40:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |

View File

@@ -27,7 +27,8 @@
| arrayassignment.cpp:29:8:29:13 | call to source | arrayassignment.cpp:29:2:29:15 | ... = ... | |
| arrayassignment.cpp:29:8:29:13 | call to source | arrayassignment.cpp:33:7:33:9 | r_x | |
| arrayassignment.cpp:32:8:32:10 | p_x | arrayassignment.cpp:32:7:32:10 | * ... | TAINT |
| arrayassignment.cpp:37:7:37:7 | Unknown literal | arrayassignment.cpp:37:7:37:7 | constructor init of field i | TAINT |
| arrayassignment.cpp:37:7:37:7 | i | arrayassignment.cpp:37:7:37:7 | constructor init of field i | TAINT |
| arrayassignment.cpp:37:7:37:7 | i | arrayassignment.cpp:37:7:37:7 | i | |
| arrayassignment.cpp:37:7:37:7 | this | arrayassignment.cpp:37:7:37:7 | constructor init of field i [pre-this] | |
| arrayassignment.cpp:40:2:40:6 | this | arrayassignment.cpp:40:12:40:15 | constructor init of field i [pre-this] | |
| arrayassignment.cpp:40:12:40:15 | 0 | arrayassignment.cpp:40:12:40:15 | constructor init of field i | TAINT |
@@ -284,6 +285,7 @@
| copyableclass_declonly.cpp:67:13:67:18 | call to source | copyableclass_declonly.cpp:67:13:67:20 | call to MyCopyableClassDeclOnly | TAINT |
| copyableclass_declonly.cpp:67:13:67:20 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:67:8:67:9 | ref arg s3 | TAINT |
| copyableclass_declonly.cpp:67:13:67:20 | call to MyCopyableClassDeclOnly | copyableclass_declonly.cpp:67:11:67:11 | call to operator= | TAINT |
| file://:0:0:0:0 | (unnamed parameter 0) | arrayassignment.cpp:37:7:37:7 | (unnamed parameter 0) | |
| file://:0:0:0:0 | (unnamed parameter 0) | file://:0:0:0:0 | (unnamed parameter 0) | |
| file://:0:0:0:0 | (unnamed parameter 0) | file://:0:0:0:0 | (unnamed parameter 0) | |
| file://:0:0:0:0 | (unnamed parameter 0) | file://:0:0:0:0 | (unnamed parameter 0) | |
@@ -299,6 +301,27 @@
| file://:0:0:0:0 | (unnamed parameter 0) | file://:0:0:0:0 | (unnamed parameter 0) | |
| file://:0:0:0:0 | (unnamed parameter 0) | file://:0:0:0:0 | (unnamed parameter 0) | |
| file://:0:0:0:0 | (unnamed parameter 0) | file://:0:0:0:0 | (unnamed parameter 0) | |
| file://:0:0:0:0 | (unnamed parameter 0) | stl.h:75:8:75:8 | (unnamed parameter 0) | |
| file://:0:0:0:0 | (unnamed parameter 0) | stl.h:75:8:75:8 | (unnamed parameter 0) | |
| file://:0:0:0:0 | (unnamed parameter 0) | stl.h:389:9:389:9 | (unnamed parameter 0) | |
| file://:0:0:0:0 | (unnamed parameter 0) | stl.h:389:9:389:9 | (unnamed parameter 0) | |
| file://:0:0:0:0 | (unnamed parameter 0) | stl.h:389:9:389:9 | (unnamed parameter 0) | |
| file://:0:0:0:0 | (unnamed parameter 0) | stl.h:389:9:389:9 | (unnamed parameter 0) | |
| file://:0:0:0:0 | (unnamed parameter 0) | stl.h:389:9:389:9 | (unnamed parameter 0) | |
| file://:0:0:0:0 | (unnamed parameter 0) | stl.h:389:9:389:9 | (unnamed parameter 0) | |
| file://:0:0:0:0 | (unnamed parameter 0) | stl.h:389:9:389:9 | (unnamed parameter 0) | |
| file://:0:0:0:0 | (unnamed parameter 0) | stl.h:389:9:389:9 | (unnamed parameter 0) | |
| file://:0:0:0:0 | (unnamed parameter 0) | stl.h:389:9:389:9 | (unnamed parameter 0) | |
| file://:0:0:0:0 | (unnamed parameter 0) | stl.h:389:9:389:9 | (unnamed parameter 0) | |
| file://:0:0:0:0 | (unnamed parameter 0) | structlikeclass.cpp:5:7:5:7 | (unnamed parameter 0) | |
| file://:0:0:0:0 | (unnamed parameter 0) | structlikeclass.cpp:5:7:5:7 | (unnamed parameter 0) | |
| file://:0:0:0:0 | (unnamed parameter 0) | taint.cpp:228:11:228:11 | (unnamed parameter 0) | |
| file://:0:0:0:0 | (unnamed parameter 0) | taint.cpp:228:11:228:11 | (unnamed parameter 0) | |
| file://:0:0:0:0 | (unnamed parameter 0) | taint.cpp:235:11:235:11 | (unnamed parameter 0) | |
| file://:0:0:0:0 | (unnamed parameter 0) | taint.cpp:235:11:235:11 | (unnamed parameter 0) | |
| file://:0:0:0:0 | (unnamed parameter 0) | taint.cpp:235:11:235:11 | (unnamed parameter 0) | |
| file://:0:0:0:0 | (unnamed parameter 0) | taint.cpp:243:11:243:11 | (unnamed parameter 0) | |
| file://:0:0:0:0 | (unnamed parameter 0) | taint.cpp:243:11:243:11 | (unnamed parameter 0) | |
| format.cpp:16:21:16:21 | s | format.cpp:16:21:16:21 | s | |
| format.cpp:16:21:16:21 | s | format.cpp:22:22:22:22 | s | |
| format.cpp:16:31:16:31 | n | format.cpp:22:25:22:25 | n | |
@@ -3554,8 +3577,10 @@
| standalone_iterators.cpp:120:2:120:3 | it | standalone_iterators.cpp:120:5:120:5 | call to operator+= | TAINT |
| standalone_iterators.cpp:120:2:120:3 | ref arg it | standalone_iterators.cpp:121:7:121:8 | it | |
| standalone_iterators.cpp:120:8:120:13 | call to source | standalone_iterators.cpp:120:2:120:3 | ref arg it | TAINT |
| stl.h:75:8:75:8 | Unknown literal | stl.h:75:8:75:8 | constructor init of field container | TAINT |
| stl.h:75:8:75:8 | Unknown literal | stl.h:75:8:75:8 | constructor init of field container | TAINT |
| stl.h:75:8:75:8 | container | stl.h:75:8:75:8 | constructor init of field container | TAINT |
| stl.h:75:8:75:8 | container | stl.h:75:8:75:8 | constructor init of field container | TAINT |
| stl.h:75:8:75:8 | container | stl.h:75:8:75:8 | container | |
| stl.h:75:8:75:8 | container | stl.h:75:8:75:8 | container | |
| stl.h:75:8:75:8 | this | stl.h:75:8:75:8 | constructor init of field container [pre-this] | |
| stl.h:75:8:75:8 | this | stl.h:75:8:75:8 | constructor init of field container [pre-this] | |
| stl.h:95:69:95:69 | x | stl.h:95:69:95:69 | x | |
@@ -3573,16 +3598,6 @@
| stl.h:292:30:292:40 | call to allocator | stl.h:292:21:292:41 | noexcept(...) | TAINT |
| stl.h:292:30:292:40 | call to allocator | stl.h:292:21:292:41 | noexcept(...) | TAINT |
| stl.h:292:53:292:63 | 0 | stl.h:292:46:292:64 | (no string representation) | TAINT |
| stl.h:389:9:389:9 | Unknown literal | stl.h:389:9:389:9 | constructor init of field first | TAINT |
| stl.h:389:9:389:9 | Unknown literal | stl.h:389:9:389:9 | constructor init of field first | TAINT |
| stl.h:389:9:389:9 | Unknown literal | stl.h:389:9:389:9 | constructor init of field first | TAINT |
| stl.h:389:9:389:9 | Unknown literal | stl.h:389:9:389:9 | constructor init of field first | TAINT |
| stl.h:389:9:389:9 | Unknown literal | stl.h:389:9:389:9 | constructor init of field first | TAINT |
| stl.h:389:9:389:9 | Unknown literal | stl.h:389:9:389:9 | constructor init of field second | TAINT |
| stl.h:389:9:389:9 | Unknown literal | stl.h:389:9:389:9 | constructor init of field second | TAINT |
| stl.h:389:9:389:9 | Unknown literal | stl.h:389:9:389:9 | constructor init of field second | TAINT |
| stl.h:389:9:389:9 | Unknown literal | stl.h:389:9:389:9 | constructor init of field second | TAINT |
| stl.h:389:9:389:9 | Unknown literal | stl.h:389:9:389:9 | constructor init of field second | TAINT |
| stl.h:389:9:389:9 | constructor init of field first [post-this] | stl.h:389:9:389:9 | constructor init of field second [pre-this] | |
| stl.h:389:9:389:9 | constructor init of field first [post-this] | stl.h:389:9:389:9 | constructor init of field second [pre-this] | |
| stl.h:389:9:389:9 | constructor init of field first [post-this] | stl.h:389:9:389:9 | constructor init of field second [pre-this] | |
@@ -3593,6 +3608,26 @@
| stl.h:389:9:389:9 | constructor init of field first [pre-this] | stl.h:389:9:389:9 | constructor init of field second [pre-this] | |
| stl.h:389:9:389:9 | constructor init of field first [pre-this] | stl.h:389:9:389:9 | constructor init of field second [pre-this] | |
| stl.h:389:9:389:9 | constructor init of field first [pre-this] | stl.h:389:9:389:9 | constructor init of field second [pre-this] | |
| stl.h:389:9:389:9 | first | stl.h:389:9:389:9 | constructor init of field first | TAINT |
| stl.h:389:9:389:9 | first | stl.h:389:9:389:9 | constructor init of field first | TAINT |
| stl.h:389:9:389:9 | first | stl.h:389:9:389:9 | constructor init of field first | TAINT |
| stl.h:389:9:389:9 | first | stl.h:389:9:389:9 | constructor init of field first | TAINT |
| stl.h:389:9:389:9 | first | stl.h:389:9:389:9 | constructor init of field first | TAINT |
| stl.h:389:9:389:9 | first | stl.h:389:9:389:9 | first | |
| stl.h:389:9:389:9 | first | stl.h:389:9:389:9 | first | |
| stl.h:389:9:389:9 | first | stl.h:389:9:389:9 | first | |
| stl.h:389:9:389:9 | first | stl.h:389:9:389:9 | first | |
| stl.h:389:9:389:9 | first | stl.h:389:9:389:9 | first | |
| stl.h:389:9:389:9 | second | stl.h:389:9:389:9 | constructor init of field second | TAINT |
| stl.h:389:9:389:9 | second | stl.h:389:9:389:9 | constructor init of field second | TAINT |
| stl.h:389:9:389:9 | second | stl.h:389:9:389:9 | constructor init of field second | TAINT |
| stl.h:389:9:389:9 | second | stl.h:389:9:389:9 | constructor init of field second | TAINT |
| stl.h:389:9:389:9 | second | stl.h:389:9:389:9 | constructor init of field second | TAINT |
| stl.h:389:9:389:9 | second | stl.h:389:9:389:9 | second | |
| stl.h:389:9:389:9 | second | stl.h:389:9:389:9 | second | |
| stl.h:389:9:389:9 | second | stl.h:389:9:389:9 | second | |
| stl.h:389:9:389:9 | second | stl.h:389:9:389:9 | second | |
| stl.h:389:9:389:9 | second | stl.h:389:9:389:9 | second | |
| stl.h:389:9:389:9 | this | stl.h:389:9:389:9 | constructor init of field first [pre-this] | |
| stl.h:389:9:389:9 | this | stl.h:389:9:389:9 | constructor init of field first [pre-this] | |
| stl.h:389:9:389:9 | this | stl.h:389:9:389:9 | constructor init of field first [pre-this] | |
@@ -5354,10 +5389,12 @@
| stringstream.cpp:266:54:266:58 | ref arg call to flush | stringstream.cpp:266:35:266:39 | ref arg call to write | TAINT |
| stringstream.cpp:266:68:266:72 | xyz | stringstream.cpp:266:54:266:58 | ref arg call to flush | TAINT |
| stringstream.cpp:266:68:266:72 | xyz | stringstream.cpp:266:62:266:66 | call to write | TAINT |
| structlikeclass.cpp:5:7:5:7 | Unknown literal | structlikeclass.cpp:5:7:5:7 | constructor init of field v | TAINT |
| structlikeclass.cpp:5:7:5:7 | Unknown literal | structlikeclass.cpp:5:7:5:7 | constructor init of field v | TAINT |
| structlikeclass.cpp:5:7:5:7 | this | structlikeclass.cpp:5:7:5:7 | constructor init of field v [pre-this] | |
| structlikeclass.cpp:5:7:5:7 | this | structlikeclass.cpp:5:7:5:7 | constructor init of field v [pre-this] | |
| structlikeclass.cpp:5:7:5:7 | v | structlikeclass.cpp:5:7:5:7 | constructor init of field v | TAINT |
| structlikeclass.cpp:5:7:5:7 | v | structlikeclass.cpp:5:7:5:7 | constructor init of field v | TAINT |
| structlikeclass.cpp:5:7:5:7 | v | structlikeclass.cpp:5:7:5:7 | v | |
| structlikeclass.cpp:5:7:5:7 | v | structlikeclass.cpp:5:7:5:7 | v | |
| structlikeclass.cpp:8:2:8:16 | this | structlikeclass.cpp:8:28:8:32 | constructor init of field v [pre-this] | |
| structlikeclass.cpp:8:22:8:23 | _v | structlikeclass.cpp:8:30:8:31 | _v | |
| structlikeclass.cpp:8:30:8:31 | _v | structlikeclass.cpp:8:28:8:32 | constructor init of field v | TAINT |
@@ -5973,24 +6010,29 @@
| taint.cpp:226:9:226:10 | 0 | taint.cpp:261:7:261:7 | w | |
| taint.cpp:228:10:232:2 | [...](...){...} | taint.cpp:233:7:233:7 | a | |
| taint.cpp:228:10:232:2 | {...} | taint.cpp:228:10:232:2 | [...](...){...} | |
| taint.cpp:228:11:228:11 | Unknown literal | taint.cpp:228:11:228:11 | constructor init of field t | TAINT |
| taint.cpp:228:11:228:11 | Unknown literal | taint.cpp:228:11:228:11 | constructor init of field u | TAINT |
| taint.cpp:228:11:228:11 | constructor init of field t [post-this] | taint.cpp:228:11:228:11 | constructor init of field u [pre-this] | |
| taint.cpp:228:11:228:11 | constructor init of field t [pre-this] | taint.cpp:228:11:228:11 | constructor init of field u [pre-this] | |
| taint.cpp:228:11:228:11 | t | taint.cpp:228:11:228:11 | constructor init of field t | TAINT |
| taint.cpp:228:11:228:11 | t | taint.cpp:228:11:228:11 | t | |
| taint.cpp:228:11:228:11 | this | taint.cpp:228:11:228:11 | constructor init of field t [pre-this] | |
| taint.cpp:228:11:228:11 | u | taint.cpp:228:11:228:11 | constructor init of field u | TAINT |
| taint.cpp:228:11:228:11 | u | taint.cpp:228:11:228:11 | u | |
| taint.cpp:228:17:228:17 | this | taint.cpp:229:3:229:6 | this | |
| taint.cpp:229:3:229:6 | this | taint.cpp:230:3:230:6 | this | |
| taint.cpp:230:3:230:6 | this | file://:0:0:0:0 | this | |
| taint.cpp:235:10:239:2 | [...](...){...} | taint.cpp:240:2:240:2 | b | |
| taint.cpp:235:10:239:2 | {...} | taint.cpp:235:10:239:2 | [...](...){...} | |
| taint.cpp:235:11:235:11 | Unknown literal | taint.cpp:235:11:235:11 | constructor init of field t | TAINT |
| taint.cpp:235:11:235:11 | Unknown literal | taint.cpp:235:11:235:11 | constructor init of field u | TAINT |
| taint.cpp:235:11:235:11 | Unknown literal | taint.cpp:235:11:235:11 | constructor init of field v | TAINT |
| taint.cpp:235:11:235:11 | constructor init of field t [post-this] | taint.cpp:235:11:235:11 | constructor init of field u [pre-this] | |
| taint.cpp:235:11:235:11 | constructor init of field t [pre-this] | taint.cpp:235:11:235:11 | constructor init of field u [pre-this] | |
| taint.cpp:235:11:235:11 | constructor init of field u [post-this] | taint.cpp:235:11:235:11 | constructor init of field v [pre-this] | |
| taint.cpp:235:11:235:11 | constructor init of field u [pre-this] | taint.cpp:235:11:235:11 | constructor init of field v [pre-this] | |
| taint.cpp:235:11:235:11 | t | taint.cpp:235:11:235:11 | constructor init of field t | TAINT |
| taint.cpp:235:11:235:11 | t | taint.cpp:235:11:235:11 | t | |
| taint.cpp:235:11:235:11 | this | taint.cpp:235:11:235:11 | constructor init of field t [pre-this] | |
| taint.cpp:235:11:235:11 | u | taint.cpp:235:11:235:11 | constructor init of field u | TAINT |
| taint.cpp:235:11:235:11 | u | taint.cpp:235:11:235:11 | u | |
| taint.cpp:235:11:235:11 | v | taint.cpp:235:11:235:11 | constructor init of field v | TAINT |
| taint.cpp:235:11:235:11 | v | taint.cpp:235:11:235:11 | v | |
| taint.cpp:235:15:235:15 | this | taint.cpp:236:3:236:6 | this | |
| taint.cpp:236:3:236:6 | this | taint.cpp:237:3:237:6 | this | |
| taint.cpp:237:3:237:6 | this | taint.cpp:238:3:238:14 | this | |
@@ -5998,11 +6040,13 @@
| taint.cpp:238:7:238:12 | call to source | taint.cpp:238:3:238:14 | ... = ... | |
| taint.cpp:243:10:246:2 | [...](...){...} | taint.cpp:247:2:247:2 | c | |
| taint.cpp:243:10:246:2 | {...} | taint.cpp:243:10:246:2 | [...](...){...} | |
| taint.cpp:243:11:243:11 | Unknown literal | taint.cpp:243:11:243:11 | constructor init of field t | TAINT |
| taint.cpp:243:11:243:11 | Unknown literal | taint.cpp:243:11:243:11 | constructor init of field u | TAINT |
| taint.cpp:243:11:243:11 | constructor init of field t [post-this] | taint.cpp:243:11:243:11 | constructor init of field u [pre-this] | |
| taint.cpp:243:11:243:11 | constructor init of field t [pre-this] | taint.cpp:243:11:243:11 | constructor init of field u [pre-this] | |
| taint.cpp:243:11:243:11 | t | taint.cpp:243:11:243:11 | constructor init of field t | TAINT |
| taint.cpp:243:11:243:11 | t | taint.cpp:243:11:243:11 | t | |
| taint.cpp:243:11:243:11 | this | taint.cpp:243:11:243:11 | constructor init of field t [pre-this] | |
| taint.cpp:243:11:243:11 | u | taint.cpp:243:11:243:11 | constructor init of field u | TAINT |
| taint.cpp:243:11:243:11 | u | taint.cpp:243:11:243:11 | u | |
| taint.cpp:243:15:243:15 | this | taint.cpp:244:3:244:6 | this | |
| taint.cpp:244:3:244:6 | this | taint.cpp:245:3:245:6 | this | |
| taint.cpp:249:11:252:2 | [...](...){...} | taint.cpp:253:2:253:2 | d | |

View File

@@ -12,8 +12,12 @@
| addressOf.cpp:40:15:40:15 | i | non-const address |
| addressOf.cpp:42:19:42:22 | iref | non-const address |
| addressOf.cpp:47:12:47:31 | captured | non-const address |
| addressOf.cpp:47:13:47:13 | (unnamed parameter 0) | |
| addressOf.cpp:47:13:47:13 | captured | |
| addressOf.cpp:47:19:47:28 | captured | |
| addressOf.cpp:48:3:48:4 | f1 | const address |
| addressOf.cpp:49:13:49:13 | (unnamed parameter 0) | |
| addressOf.cpp:49:13:49:13 | captured | |
| addressOf.cpp:49:15:49:22 | captured | non-const address |
| addressOf.cpp:49:27:49:36 | captured | |
| addressOf.cpp:50:3:50:4 | f2 | const address |
@@ -245,6 +249,10 @@
| test.cpp:173:19:173:19 | x | const address |
| test.cpp:174:20:174:20 | x | const address |
| test.cpp:175:7:175:7 | x | |
| test.cpp:178:8:178:8 | (unnamed parameter 0) | |
| test.cpp:178:8:178:8 | (unnamed parameter 0) | |
| test.cpp:178:8:178:8 | nested | |
| test.cpp:178:8:178:8 | x_ | |
| test.cpp:183:38:183:41 | yptr | |
| test.cpp:183:48:183:48 | z | |
| test.cpp:184:28:184:35 | static_y | non-const address |

View File

@@ -8,6 +8,10 @@
| addressOf.cpp:61:33:61:35 | ref | addressOf.cpp:63:24:63:26 | ref |
| addressOf.cpp:70:29:70:31 | obj | addressOf.cpp:71:32:71:34 | obj |
| addressOf.cpp:70:29:70:31 | obj | addressOf.cpp:71:32:71:34 | obj |
| file://:0:0:0:0 | (unnamed parameter 0) | addressOf.cpp:47:13:47:13 | (unnamed parameter 0) |
| file://:0:0:0:0 | (unnamed parameter 0) | addressOf.cpp:49:13:49:13 | (unnamed parameter 0) |
| file://:0:0:0:0 | (unnamed parameter 0) | test.cpp:178:8:178:8 | (unnamed parameter 0) |
| file://:0:0:0:0 | (unnamed parameter 0) | test.cpp:178:8:178:8 | (unnamed parameter 0) |
| indirect_use.cpp:19:31:19:32 | ip | indirect_use.cpp:20:14:20:15 | ip |
| indirect_use.cpp:24:31:24:32 | ip | indirect_use.cpp:25:14:25:15 | ip |
| indirect_use.cpp:30:28:30:30 | ppp | indirect_use.cpp:31:19:31:21 | ppp |

View File

@@ -26,6 +26,10 @@
| addressOf.cpp:70:29:70:31 | obj | addressOf.cpp:71:32:71:34 | obj |
| addressOf.cpp:76:7:76:7 | x | addressOf.cpp:77:27:77:27 | x |
| addressOf.cpp:76:7:76:7 | x | addressOf.cpp:77:48:77:48 | x |
| file://:0:0:0:0 | (unnamed parameter 0) | addressOf.cpp:47:13:47:13 | (unnamed parameter 0) |
| file://:0:0:0:0 | (unnamed parameter 0) | addressOf.cpp:49:13:49:13 | (unnamed parameter 0) |
| file://:0:0:0:0 | (unnamed parameter 0) | test.cpp:178:8:178:8 | (unnamed parameter 0) |
| file://:0:0:0:0 | (unnamed parameter 0) | test.cpp:178:8:178:8 | (unnamed parameter 0) |
| indirect_use.cpp:19:31:19:32 | ip | indirect_use.cpp:20:14:20:15 | ip |
| indirect_use.cpp:20:10:20:10 | p | indirect_use.cpp:21:17:21:17 | p |
| indirect_use.cpp:24:31:24:32 | ip | indirect_use.cpp:25:14:25:15 | ip |

View File

@@ -12,6 +12,10 @@
| addressOf.cpp:61:23:61:25 | ptr | addressOf.cpp:63:19:63:21 | ptr |
| addressOf.cpp:70:29:70:31 | obj | addressOf.cpp:71:32:71:34 | obj |
| addressOf.cpp:76:7:76:7 | x | addressOf.cpp:77:48:77:48 | x |
| file://:0:0:0:0 | (unnamed parameter 0) | addressOf.cpp:47:13:47:13 | (unnamed parameter 0) |
| file://:0:0:0:0 | (unnamed parameter 0) | addressOf.cpp:49:13:49:13 | (unnamed parameter 0) |
| file://:0:0:0:0 | (unnamed parameter 0) | test.cpp:178:8:178:8 | (unnamed parameter 0) |
| file://:0:0:0:0 | (unnamed parameter 0) | test.cpp:178:8:178:8 | (unnamed parameter 0) |
| indirect_use.cpp:19:31:19:32 | ip | indirect_use.cpp:20:14:20:15 | ip |
| indirect_use.cpp:20:10:20:10 | p | indirect_use.cpp:21:17:21:17 | p |
| indirect_use.cpp:24:31:24:32 | ip | indirect_use.cpp:25:14:25:15 | ip |

View File

@@ -155,15 +155,21 @@ bad_asts.cpp:
# 19| getInitializer(0): [ConstructorFieldInit] constructor init of field x
# 19| Type = [IntType] int
# 19| ValueCategory = prvalue
# 19| getExpr(): [Literal] Unknown literal
# 19| getExpr(): [FieldAccess] x
# 19| Type = [IntType] int
# 19| ValueCategory = prvalue
# 19| ValueCategory = prvalue(load)
# 19| getQualifier(): [VariableAccess] (unnamed parameter 0)
# 19| Type = [LValueReferenceType] const Point &
# 19| ValueCategory = prvalue(load)
# 19| getInitializer(1): [ConstructorFieldInit] constructor init of field y
# 19| Type = [IntType] int
# 19| ValueCategory = prvalue
# 19| getExpr(): [Literal] Unknown literal
# 19| getExpr(): [FieldAccess] y
# 19| Type = [IntType] int
# 19| ValueCategory = prvalue
# 19| ValueCategory = prvalue(load)
# 19| getQualifier(): [VariableAccess] (unnamed parameter 0)
# 19| Type = [LValueReferenceType] const Point &
# 19| ValueCategory = prvalue(load)
# 19| getEntryPoint(): [BlockStmt] { ... }
# 19| getStmt(0): [ReturnStmt] return ...
# 19| [MoveConstructor] void Bad::Point::Point(Bad::Point&&)
@@ -11645,51 +11651,75 @@ ir.cpp:
# 1486| getInitializer(0): [ConstructorFieldInit] constructor init of field i
# 1486| Type = [IntType] int
# 1486| ValueCategory = prvalue
# 1486| getExpr(): [Literal] Unknown literal
# 1486| getExpr(): [FieldAccess] i
# 1486| Type = [IntType] int
# 1486| ValueCategory = prvalue
# 1486| ValueCategory = prvalue(load)
# 1486| getQualifier(): [VariableAccess] (unnamed parameter 0)
# 1486| Type = [LValueReferenceType] const StructuredBindingDataMemberStruct &
# 1486| ValueCategory = prvalue(load)
# 1486| getInitializer(1): [ConstructorFieldInit] constructor init of field d
# 1486| Type = [DoubleType] double
# 1486| ValueCategory = prvalue
# 1486| getExpr(): [Literal] Unknown literal
# 1486| getExpr(): [FieldAccess] d
# 1486| Type = [DoubleType] double
# 1486| ValueCategory = prvalue
# 1486| ValueCategory = prvalue(load)
# 1486| getQualifier(): [VariableAccess] (unnamed parameter 0)
# 1486| Type = [LValueReferenceType] const StructuredBindingDataMemberStruct &
# 1486| ValueCategory = prvalue(load)
# 1486| getInitializer(2): [ConstructorFieldInit] constructor init of field b
# 1486| Type = [IntType] unsigned int
# 1486| ValueCategory = prvalue
# 1486| getExpr(): [Literal] Unknown literal
# 1486| getExpr(): [FieldAccess] b
# 1486| Type = [IntType] unsigned int
# 1486| ValueCategory = prvalue
# 1486| ValueCategory = prvalue(load)
# 1486| getQualifier(): [VariableAccess] (unnamed parameter 0)
# 1486| Type = [LValueReferenceType] const StructuredBindingDataMemberStruct &
# 1486| ValueCategory = prvalue(load)
# 1486| getInitializer(3): [ConstructorFieldInit] constructor init of field r
# 1486| Type = [LValueReferenceType] int &
# 1486| ValueCategory = prvalue
# 1486| getExpr(): [Literal] Unknown literal
# 1486| getExpr(): [FieldAccess] r
# 1486| Type = [LValueReferenceType] int &
# 1486| ValueCategory = prvalue
# 1486| ValueCategory = prvalue(load)
# 1486| getQualifier(): [VariableAccess] (unnamed parameter 0)
# 1486| Type = [LValueReferenceType] const StructuredBindingDataMemberStruct &
# 1486| ValueCategory = prvalue(load)
# 1486| getInitializer(4): [ConstructorFieldInit] constructor init of field p
# 1486| Type = [IntPointerType] int *
# 1486| ValueCategory = prvalue
# 1486| getExpr(): [Literal] Unknown literal
# 1486| getExpr(): [FieldAccess] p
# 1486| Type = [IntPointerType] int *
# 1486| ValueCategory = prvalue
# 1486| ValueCategory = prvalue(load)
# 1486| getQualifier(): [VariableAccess] (unnamed parameter 0)
# 1486| Type = [LValueReferenceType] const StructuredBindingDataMemberStruct &
# 1486| ValueCategory = prvalue(load)
# 1486| getInitializer(5): [ConstructorFieldInit] constructor init of field xs
# 1486| Type = [CTypedefType,NestedTypedefType] ArrayType
# 1486| ValueCategory = prvalue
# 1486| getExpr(): [Literal] Unknown literal
# 1486| getExpr(): [FieldAccess] xs
# 1486| Type = [CTypedefType,NestedTypedefType] ArrayType
# 1486| ValueCategory = prvalue
# 1486| ValueCategory = prvalue(load)
# 1486| getQualifier(): [VariableAccess] (unnamed parameter 0)
# 1486| Type = [LValueReferenceType] const StructuredBindingDataMemberStruct &
# 1486| ValueCategory = prvalue(load)
# 1486| getInitializer(6): [ConstructorFieldInit] constructor init of field r_alt
# 1486| Type = [CTypedefType,NestedTypedefType] RefType
# 1486| ValueCategory = prvalue
# 1486| getExpr(): [Literal] Unknown literal
# 1486| getExpr(): [FieldAccess] r_alt
# 1486| Type = [CTypedefType,NestedTypedefType] RefType
# 1486| ValueCategory = prvalue
# 1486| ValueCategory = prvalue(load)
# 1486| getQualifier(): [VariableAccess] (unnamed parameter 0)
# 1486| Type = [LValueReferenceType] const StructuredBindingDataMemberStruct &
# 1486| ValueCategory = prvalue(load)
# 1486| getInitializer(7): [ConstructorFieldInit] constructor init of field m
# 1486| Type = [Struct] StructuredBindingDataMemberMemberStruct
# 1486| ValueCategory = prvalue
# 1486| getExpr(): [Literal] Unknown literal
# 1486| getExpr(): [FieldAccess] m
# 1486| Type = [Struct] StructuredBindingDataMemberMemberStruct
# 1486| ValueCategory = prvalue
# 1486| ValueCategory = prvalue(load)
# 1486| getQualifier(): [VariableAccess] (unnamed parameter 0)
# 1486| Type = [LValueReferenceType] const StructuredBindingDataMemberStruct &
# 1486| ValueCategory = prvalue(load)
# 1486| getEntryPoint(): [BlockStmt] { ... }
# 1486| getStmt(0): [ReturnStmt] return ...
# 1486| [MoveConstructor] void StructuredBindingDataMemberStruct::StructuredBindingDataMemberStruct(StructuredBindingDataMemberStruct&&)
@@ -12066,21 +12096,30 @@ ir.cpp:
# 1539| getInitializer(0): [ConstructorFieldInit] constructor init of field i
# 1539| Type = [IntType] int
# 1539| ValueCategory = prvalue
# 1539| getExpr(): [Literal] Unknown literal
# 1539| getExpr(): [FieldAccess] i
# 1539| Type = [IntType] int
# 1539| ValueCategory = prvalue
# 1539| ValueCategory = prvalue(load)
# 1539| getQualifier(): [VariableAccess] (unnamed parameter 0)
# 1539| Type = [LValueReferenceType] const StructuredBindingTupleRefGet &
# 1539| ValueCategory = prvalue(load)
# 1539| getInitializer(1): [ConstructorFieldInit] constructor init of field d
# 1539| Type = [DoubleType] double
# 1539| ValueCategory = prvalue
# 1539| getExpr(): [Literal] Unknown literal
# 1539| getExpr(): [FieldAccess] d
# 1539| Type = [DoubleType] double
# 1539| ValueCategory = prvalue
# 1539| ValueCategory = prvalue(load)
# 1539| getQualifier(): [VariableAccess] (unnamed parameter 0)
# 1539| Type = [LValueReferenceType] const StructuredBindingTupleRefGet &
# 1539| ValueCategory = prvalue(load)
# 1539| getInitializer(2): [ConstructorFieldInit] constructor init of field r
# 1539| Type = [LValueReferenceType] int &
# 1539| ValueCategory = prvalue
# 1539| getExpr(): [Literal] Unknown literal
# 1539| getExpr(): [FieldAccess] r
# 1539| Type = [LValueReferenceType] int &
# 1539| ValueCategory = prvalue
# 1539| ValueCategory = prvalue(load)
# 1539| getQualifier(): [VariableAccess] (unnamed parameter 0)
# 1539| Type = [LValueReferenceType] const StructuredBindingTupleRefGet &
# 1539| ValueCategory = prvalue(load)
# 1539| getEntryPoint(): [BlockStmt] { ... }
# 1539| getStmt(0): [ReturnStmt] return ...
# 1539| [MoveConstructor] void StructuredBindingTupleRefGet::StructuredBindingTupleRefGet(StructuredBindingTupleRefGet&&)
@@ -12820,6 +12859,238 @@ ir.cpp:
# 1668| Type = [IntType] int
# 1668| ValueCategory = prvalue(load)
# 1670| getStmt(3): [ReturnStmt] return ...
# 1672| [TopLevelFunction] void array_structured_binding_non_ref_init()
# 1672| <params>:
# 1672| getEntryPoint(): [BlockStmt] { ... }
# 1673| getStmt(0): [DeclStmt] declaration
# 1673| getDeclarationEntry(0): [VariableDeclarationEntry] definition of xs
# 1673| Type = [ArrayType] int[2]
# 1673| getVariable().getInitializer(): [Initializer] initializer for xs
# 1673| getExpr(): [ArrayAggregateLiteral] {...}
# 1673| Type = [ArrayType] int[2]
# 1673| ValueCategory = prvalue
# 1673| getElementExpr(0): [Literal] 1
# 1673| Type = [IntType] int
# 1673| Value = [Literal] 1
# 1673| ValueCategory = prvalue
# 1673| getElementExpr(1): [Literal] 2
# 1673| Type = [IntType] int
# 1673| Value = [Literal] 2
# 1673| ValueCategory = prvalue
# 1674| getStmt(1): [DeclStmt] declaration
# 1674| getDeclarationEntry(0): (no string representation)
# 1674| Type = [ArrayType] int[2]
# 1674| getVariable().getInitializer(): [Initializer] initializer for (unnamed local variable)
# 1674| getExpr(): [VariableAccess] xs
# 1674| Type = [ArrayType] int[2]
# 1674| ValueCategory = prvalue(load)
# 1674| getDeclarationEntry(1): [VariableDeclarationEntry] definition of x0
# 1674| Type = [IntType] int
#-----| getVariable().getInitializer(): [Initializer] initializer for x0
#-----| getExpr(): [ArrayExpr] access to array
#-----| Type = [IntType] int
#-----| ValueCategory = lvalue
#-----| getArrayBase(): [VariableAccess] (unnamed local variable)
#-----| Type = [ArrayType] int[2]
#-----| ValueCategory = lvalue
#-----| getArrayOffset(): [Literal] 0
#-----| Type = [LongType] unsigned long
#-----| Value = [Literal] 0
#-----| ValueCategory = prvalue
#-----| getArrayBase().getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion
#-----| Type = [IntPointerType] int *
#-----| ValueCategory = prvalue
# 1674| getDeclarationEntry(2): [VariableDeclarationEntry] definition of x1
# 1674| Type = [IntType] int
#-----| getVariable().getInitializer(): [Initializer] initializer for x1
#-----| getExpr(): [ArrayExpr] access to array
#-----| Type = [IntType] int
#-----| ValueCategory = lvalue
#-----| getArrayBase(): [VariableAccess] (unnamed local variable)
#-----| Type = [ArrayType] int[2]
#-----| ValueCategory = lvalue
#-----| getArrayOffset(): [Literal] 1
#-----| Type = [LongType] unsigned long
#-----| Value = [Literal] 1
#-----| ValueCategory = prvalue
#-----| getArrayBase().getFullyConverted(): [ArrayToPointerConversion] array to pointer conversion
#-----| Type = [IntPointerType] int *
#-----| ValueCategory = prvalue
# 1675| getStmt(2): [ReturnStmt] return ...
# 1677| [CopyAssignmentOperator] CapturedLambdaMyObj& CapturedLambdaMyObj::operator=(CapturedLambdaMyObj const&)
# 1677| <params>:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
#-----| Type = [LValueReferenceType] const CapturedLambdaMyObj &
# 1677| [MoveAssignmentOperator] CapturedLambdaMyObj& CapturedLambdaMyObj::operator=(CapturedLambdaMyObj&&)
# 1677| <params>:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
#-----| Type = [RValueReferenceType] CapturedLambdaMyObj &&
# 1677| [CopyConstructor] void CapturedLambdaMyObj::CapturedLambdaMyObj(CapturedLambdaMyObj const&)
# 1677| <params>:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
#-----| Type = [LValueReferenceType] const CapturedLambdaMyObj &
# 1677| [MoveConstructor] void CapturedLambdaMyObj::CapturedLambdaMyObj(CapturedLambdaMyObj&&)
# 1677| <params>:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
#-----| Type = [RValueReferenceType] CapturedLambdaMyObj &&
# 1680| [Constructor] void CapturedLambdaMyObj::CapturedLambdaMyObj()
# 1680| <params>:
# 1680| <initializations>:
# 1680| getEntryPoint(): [BlockStmt] { ... }
# 1680| getStmt(0): [ReturnStmt] return ...
# 1683| [TopLevelFunction] void captured_lambda(int, int&, int&&)
# 1683| <params>:
# 1683| getParameter(0): [Parameter] x
# 1683| Type = [IntType] int
# 1683| getParameter(1): [Parameter] y
# 1683| Type = [LValueReferenceType] int &
# 1683| getParameter(2): [Parameter] z
# 1683| Type = [RValueReferenceType] int &&
# 1684| getEntryPoint(): [BlockStmt] { ... }
# 1685| getStmt(0): [DeclStmt] declaration
# 1685| getDeclarationEntry(0): [VariableDeclarationEntry] definition of obj1
# 1685| Type = [LValueReferenceType] const CapturedLambdaMyObj &
# 1685| getVariable().getInitializer(): [Initializer] initializer for obj1
# 1685| getExpr(): [ConstructorCall] call to CapturedLambdaMyObj
# 1685| Type = [VoidType] void
# 1685| ValueCategory = prvalue
# 1685| getExpr().getFullyConverted(): [ReferenceToExpr] (reference to)
# 1685| Type = [LValueReferenceType] const CapturedLambdaMyObj &
# 1685| ValueCategory = prvalue
# 1685| getExpr(): [CStyleCast] (const CapturedLambdaMyObj)...
# 1685| Conversion = [GlvalueConversion] glvalue conversion
# 1685| Type = [SpecifiedType] const CapturedLambdaMyObj
# 1685| ValueCategory = lvalue
# 1685| getExpr(): [TemporaryObjectExpr] temporary object
# 1685| Type = [Class] CapturedLambdaMyObj
# 1685| ValueCategory = lvalue
# 1686| getStmt(1): [DeclStmt] declaration
# 1686| getDeclarationEntry(0): [VariableDeclarationEntry] definition of obj2
# 1686| Type = [Class] CapturedLambdaMyObj
# 1686| getVariable().getInitializer(): [Initializer] initializer for obj2
# 1686| getExpr(): [ConstructorCall] call to CapturedLambdaMyObj
# 1686| Type = [VoidType] void
# 1686| ValueCategory = prvalue
# 1688| getStmt(2): [DeclStmt] declaration
# 1688| getDeclarationEntry(0): [VariableDeclarationEntry] definition of lambda_outer
# 1688| Type = [Closure,LocalClass] decltype([...](...){...})
# 1688| getVariable().getInitializer(): [Initializer] initializer for lambda_outer
# 1688| getExpr(): [LambdaExpression] [...](...){...}
# 1688| Type = [Closure,LocalClass] decltype([...](...){...})
# 1688| ValueCategory = prvalue
# 1688| getInitializer(): [ClassAggregateLiteral] {...}
# 1688| Type = [Closure,LocalClass] decltype([...](...){...})
# 1688| ValueCategory = prvalue
# 1688| getFieldExpr(obj1): [Literal] Unknown literal
# 1688| Type = [SpecifiedType] const CapturedLambdaMyObj
# 1688| ValueCategory = prvalue
# 1688| getFieldExpr(obj2): [Literal] Unknown literal
# 1688| Type = [Class] CapturedLambdaMyObj
# 1688| ValueCategory = prvalue
# 1688| getFieldExpr(x): [VariableAccess] x
# 1688| Type = [IntType] int
# 1688| ValueCategory = prvalue(load)
# 1688| getFieldExpr(y): [VariableAccess] y
# 1688| Type = [LValueReferenceType] int &
# 1688| ValueCategory = prvalue(load)
# 1688| getFieldExpr(z): [VariableAccess] z
# 1688| Type = [RValueReferenceType] int &&
# 1688| ValueCategory = prvalue(load)
# 1690| getFieldExpr(y).getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
# 1690| Type = [IntType] int
# 1690| ValueCategory = prvalue(load)
# 1690| getFieldExpr(z).getFullyConverted(): [ReferenceDereferenceExpr] (reference dereference)
# 1690| Type = [IntType] int
# 1690| ValueCategory = prvalue(load)
# 1691| getStmt(3): [ReturnStmt] return ...
# 1688| [CopyAssignmentOperator] (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)& (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator=((void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25) const&)
# 1688| <params>:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
#-----| Type = [LValueReferenceType] const lambda [] type at line 1688, col. 25 &
# 1688| [CopyConstructor] void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::(unnamed constructor)((void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25) const&)
# 1688| <params>:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
#-----| Type = [LValueReferenceType] const lambda [] type at line 1688, col. 25 &
# 1688| [MoveConstructor] void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::(unnamed constructor)((void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)&&)
# 1688| <params>:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
#-----| Type = [RValueReferenceType] lambda [] type at line 1688, col. 25 &&
# 1688| [Constructor] void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::(unnamed constructor)()
# 1688| <params>:
# 1688| [ConstMemberFunction] void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const
# 1688| <params>:
# 1688| getEntryPoint(): [BlockStmt] { ... }
# 1689| getStmt(0): [DeclStmt] declaration
# 1689| getDeclarationEntry(0): [VariableDeclarationEntry] definition of lambda_inner
# 1689| Type = [Closure,LocalClass] decltype([...](...){...})
# 1689| getVariable().getInitializer(): [Initializer] initializer for lambda_inner
# 1689| getExpr(): [LambdaExpression] [...](...){...}
# 1689| Type = [Closure,LocalClass] decltype([...](...){...})
# 1689| ValueCategory = prvalue
# 1689| getInitializer(): [ClassAggregateLiteral] {...}
# 1689| Type = [Closure,LocalClass] decltype([...](...){...})
# 1689| ValueCategory = prvalue
# 1689| getFieldExpr(obj1): [Literal] Unknown literal
# 1689| Type = [SpecifiedType] const CapturedLambdaMyObj
# 1689| ValueCategory = prvalue
# 1689| getFieldExpr(obj2): [Literal] Unknown literal
# 1689| Type = [Class] CapturedLambdaMyObj
# 1689| ValueCategory = prvalue
# 1689| getFieldExpr(x): [PointerFieldAccess] x
# 1689| Type = [IntType] int
# 1689| ValueCategory = prvalue(load)
# 1689| getQualifier(): [ThisExpr] this
# 1689| Type = [PointerType] const lambda [] type at line 1688, col. 25 *
# 1689| ValueCategory = prvalue(load)
# 1689| getFieldExpr(y): [PointerFieldAccess] y
# 1689| Type = [IntType] int
# 1689| ValueCategory = prvalue(load)
# 1689| getQualifier(): [ThisExpr] this
# 1689| Type = [PointerType] const lambda [] type at line 1688, col. 25 *
# 1689| ValueCategory = prvalue(load)
# 1689| getFieldExpr(z): [PointerFieldAccess] z
# 1689| Type = [IntType] int
# 1689| ValueCategory = prvalue(load)
# 1689| getQualifier(): [ThisExpr] this
# 1689| Type = [PointerType] const lambda [] type at line 1688, col. 25 *
# 1689| ValueCategory = prvalue(load)
# 1690| getStmt(1): [ReturnStmt] return ...
# 1689| [CopyAssignmentOperator] (void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const)::(lambda [] type at line 1689, col. 29)& (void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const)::(lambda [] type at line 1689, col. 29)::operator=((void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const)::(lambda [] type at line 1689, col. 29) const&)
# 1689| <params>:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
#-----| Type = [LValueReferenceType] const lambda [] type at line 1689, col. 29 &
# 1689| [CopyConstructor] void (void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const)::(lambda [] type at line 1689, col. 29)::(unnamed constructor)((void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const)::(lambda [] type at line 1689, col. 29) const&)
# 1689| <params>:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
#-----| Type = [LValueReferenceType] const lambda [] type at line 1689, col. 29 &
# 1689| [MoveConstructor] void (void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const)::(lambda [] type at line 1689, col. 29)::(unnamed constructor)((void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const)::(lambda [] type at line 1689, col. 29)&&)
# 1689| <params>:
#-----| getParameter(0): [Parameter] (unnamed parameter 0)
#-----| Type = [RValueReferenceType] lambda [] type at line 1689, col. 29 &&
# 1689| [Constructor] void (void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const)::(lambda [] type at line 1689, col. 29)::(unnamed constructor)()
# 1689| <params>:
# 1689| [ConstMemberFunction] void (void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const)::(lambda [] type at line 1689, col. 29)::operator()() const
# 1689| <params>:
# 1689| getEntryPoint(): [BlockStmt] { ... }
# 1689| getStmt(0): [EmptyStmt] ;
# 1689| getStmt(1): [ReturnStmt] return ...
# 1693| [TopLevelFunction] int goto_on_same_line()
# 1693| <params>:
# 1693| getEntryPoint(): [BlockStmt] { ... }
# 1694| getStmt(0): [DeclStmt] declaration
# 1694| getDeclarationEntry(0): [VariableDeclarationEntry] definition of x
# 1694| Type = [IntType] int
# 1694| getVariable().getInitializer(): [Initializer] initializer for x
# 1694| getExpr(): [Literal] 42
# 1694| Type = [IntType] int
# 1694| Value = [Literal] 42
# 1694| ValueCategory = prvalue
# 1695| getStmt(1): [GotoStmt] goto ...
# 1695| getStmt(2): [LabelStmt] label ...:
# 1696| getStmt(3): [ReturnStmt] return ...
# 1696| getExpr(): [VariableAccess] x
# 1696| Type = [IntType] int
# 1696| ValueCategory = prvalue(load)
perf-regression.cpp:
# 4| [CopyAssignmentOperator] Big& Big::operator=(Big const&)
# 4| <params>:

View File

@@ -6,6 +6,8 @@ missingOperandType
duplicateChiOperand
sideEffectWithoutPrimary
instructionWithoutSuccessor
| ir.cpp:1688:24:1690:5 | FieldAddress: {...} | Instruction 'FieldAddress: {...}' has no successors in function '$@'. | ir.cpp:1683:6:1683:20 | void captured_lambda(int, int&, int&&) | void captured_lambda(int, int&, int&&) |
| ir.cpp:1689:28:1689:54 | FieldAddress: {...} | Instruction 'FieldAddress: {...}' has no successors in function '$@'. | ir.cpp:1688:46:1688:46 | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const |
ambiguousSuccessors
unexplainedLoop
unnecessaryPhiInstruction

View File

@@ -6,6 +6,8 @@ missingOperandType
duplicateChiOperand
sideEffectWithoutPrimary
instructionWithoutSuccessor
| ir.cpp:1688:24:1690:5 | FieldAddress: {...} | Instruction 'FieldAddress: {...}' has no successors in function '$@'. | ir.cpp:1683:6:1683:20 | void captured_lambda(int, int&, int&&) | void captured_lambda(int, int&, int&&) |
| ir.cpp:1689:28:1689:54 | FieldAddress: {...} | Instruction 'FieldAddress: {...}' has no successors in function '$@'. | ir.cpp:1688:46:1688:46 | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const |
ambiguousSuccessors
unexplainedLoop
unnecessaryPhiInstruction

View File

@@ -1669,4 +1669,31 @@ void tuple_structured_binding_no_ref_get() {
}
}
void array_structured_binding_non_ref_init() {
int xs[2] = {1, 2};
auto [x0, x1] = xs;
}
class CapturedLambdaMyObj
{
public:
CapturedLambdaMyObj() {}
};
void captured_lambda(int x, int &y, int &&z)
{
const auto &obj1 = CapturedLambdaMyObj();
auto obj2 = CapturedLambdaMyObj();
auto lambda_outer = [obj1, obj2, x, y, z](){
auto lambda_inner = [obj1, obj2, x, y, z](){;};
};
}
int goto_on_same_line() {
int x = 42;
goto next; next:
return x;
}
// semmle-extractor-options: -std=c++17 --clang

View File

@@ -41,6 +41,35 @@
| bad_asts.cpp:16:7:16:23 | ChiTotal | total:m14_4 |
| bad_asts.cpp:16:7:16:23 | SideEffect | ~m14_4 |
| bad_asts.cpp:16:25:16:25 | Arg(0) | 0:r16_3 |
| bad_asts.cpp:19:10:19:10 | Address | &:r19_5 |
| bad_asts.cpp:19:10:19:10 | Address | &:r19_5 |
| bad_asts.cpp:19:10:19:10 | Address | &:r19_7 |
| bad_asts.cpp:19:10:19:10 | Address | &:r19_7 |
| bad_asts.cpp:19:10:19:10 | Address | &:r19_9 |
| bad_asts.cpp:19:10:19:10 | Address | &:r19_10 |
| bad_asts.cpp:19:10:19:10 | Address | &:r19_12 |
| bad_asts.cpp:19:10:19:10 | Address | &:r19_16 |
| bad_asts.cpp:19:10:19:10 | Address | &:r19_17 |
| bad_asts.cpp:19:10:19:10 | Address | &:r19_19 |
| bad_asts.cpp:19:10:19:10 | ChiPartial | partial:m19_3 |
| bad_asts.cpp:19:10:19:10 | ChiPartial | partial:m19_14 |
| bad_asts.cpp:19:10:19:10 | ChiPartial | partial:m19_21 |
| bad_asts.cpp:19:10:19:10 | ChiTotal | total:m19_2 |
| bad_asts.cpp:19:10:19:10 | ChiTotal | total:m19_8 |
| bad_asts.cpp:19:10:19:10 | ChiTotal | total:m19_15 |
| bad_asts.cpp:19:10:19:10 | Load | m0_2 |
| bad_asts.cpp:19:10:19:10 | Load | m0_2 |
| bad_asts.cpp:19:10:19:10 | Load | m19_6 |
| bad_asts.cpp:19:10:19:10 | Load | ~m0_4 |
| bad_asts.cpp:19:10:19:10 | Load | ~m0_4 |
| bad_asts.cpp:19:10:19:10 | SideEffect | m19_3 |
| bad_asts.cpp:19:10:19:10 | SideEffect | m19_22 |
| bad_asts.cpp:19:10:19:10 | StoreValue | r19_13 |
| bad_asts.cpp:19:10:19:10 | StoreValue | r19_20 |
| bad_asts.cpp:19:10:19:10 | Unary | m19_6 |
| bad_asts.cpp:19:10:19:10 | Unary | m19_6 |
| bad_asts.cpp:19:10:19:10 | Unary | r19_11 |
| bad_asts.cpp:19:10:19:10 | Unary | r19_18 |
| bad_asts.cpp:22:5:22:9 | Address | &:r22_5 |
| bad_asts.cpp:22:5:22:9 | Address | &:r22_5 |
| bad_asts.cpp:22:5:22:9 | Address | &:r22_7 |
@@ -633,6 +662,12 @@
| file://:0:0:0:0 | Address | &:r0_1 |
| file://:0:0:0:0 | Address | &:r0_1 |
| file://:0:0:0:0 | Address | &:r0_1 |
| file://:0:0:0:0 | Address | &:r0_1 |
| file://:0:0:0:0 | Address | &:r0_1 |
| file://:0:0:0:0 | Address | &:r0_1 |
| file://:0:0:0:0 | Address | &:r0_1 |
| file://:0:0:0:0 | Address | &:r0_1 |
| file://:0:0:0:0 | Address | &:r0_1 |
| file://:0:0:0:0 | Address | &:r0_2 |
| file://:0:0:0:0 | Address | &:r0_3 |
| file://:0:0:0:0 | Address | &:r0_3 |
@@ -643,6 +678,12 @@
| file://:0:0:0:0 | Address | &:r0_3 |
| file://:0:0:0:0 | Address | &:r0_3 |
| file://:0:0:0:0 | Address | &:r0_3 |
| file://:0:0:0:0 | Address | &:r0_3 |
| file://:0:0:0:0 | Address | &:r0_3 |
| file://:0:0:0:0 | Address | &:r0_3 |
| file://:0:0:0:0 | Address | &:r0_3 |
| file://:0:0:0:0 | Address | &:r0_3 |
| file://:0:0:0:0 | Address | &:r0_3 |
| file://:0:0:0:0 | Address | &:r0_5 |
| file://:0:0:0:0 | Address | &:r0_5 |
| file://:0:0:0:0 | Address | &:r0_5 |
@@ -684,24 +725,34 @@
| file://:0:0:0:0 | ChiTotal | total:m763_8 |
| file://:0:0:0:0 | ChiTotal | total:m1043_10 |
| file://:0:0:0:0 | ChiTotal | total:m1240_4 |
| file://:0:0:0:0 | Left | r0_2 |
| file://:0:0:0:0 | Left | r0_4 |
| file://:0:0:0:0 | Left | r0_7 |
| file://:0:0:0:0 | Left | r0_11 |
| file://:0:0:0:0 | Load | m0_2 |
| file://:0:0:0:0 | Load | m0_2 |
| file://:0:0:0:0 | Load | m0_2 |
| file://:0:0:0:0 | Load | m0_2 |
| file://:0:0:0:0 | Load | m0_2 |
| file://:0:0:0:0 | Load | m0_2 |
| file://:0:0:0:0 | Load | m0_2 |
| file://:0:0:0:0 | Load | m745_6 |
| file://:0:0:0:0 | Load | m754_6 |
| file://:0:0:0:0 | Load | m763_6 |
| file://:0:0:0:0 | Load | m1466_4 |
| file://:0:0:0:0 | Load | m1466_4 |
| file://:0:0:0:0 | Load | ~m1444_6 |
| file://:0:0:0:0 | Right | r0_3 |
| file://:0:0:0:0 | Right | r0_5 |
| file://:0:0:0:0 | Right | r0_8 |
| file://:0:0:0:0 | Right | r0_12 |
| file://:0:0:0:0 | SideEffect | m0_4 |
| file://:0:0:0:0 | SideEffect | m0_4 |
| file://:0:0:0:0 | SideEffect | m0_4 |
| file://:0:0:0:0 | SideEffect | m0_4 |
| file://:0:0:0:0 | SideEffect | m0_4 |
| file://:0:0:0:0 | SideEffect | m0_4 |
| file://:0:0:0:0 | SideEffect | m0_4 |
| file://:0:0:0:0 | SideEffect | m1078_23 |
| file://:0:0:0:0 | SideEffect | m1078_23 |
| file://:0:0:0:0 | SideEffect | m1084_23 |
@@ -726,12 +777,15 @@
| file://:0:0:0:0 | StoreValue | r0_1 |
| file://:0:0:0:0 | StoreValue | r0_1 |
| file://:0:0:0:0 | StoreValue | r0_3 |
| file://:0:0:0:0 | StoreValue | r0_4 |
| file://:0:0:0:0 | StoreValue | r0_6 |
| file://:0:0:0:0 | StoreValue | r0_9 |
| file://:0:0:0:0 | StoreValue | r0_13 |
| file://:0:0:0:0 | StoreValue | r0_13 |
| file://:0:0:0:0 | StoreValue | r0_22 |
| file://:0:0:0:0 | StoreValue | r0_22 |
| file://:0:0:0:0 | Unary | r0_1 |
| file://:0:0:0:0 | Unary | r0_1 |
| file://:0:0:0:0 | Unary | r0_2 |
| file://:0:0:0:0 | Unary | r0_3 |
| file://:0:0:0:0 | Unary | r0_5 |
@@ -739,6 +793,7 @@
| file://:0:0:0:0 | Unary | r0_6 |
| file://:0:0:0:0 | Unary | r0_6 |
| file://:0:0:0:0 | Unary | r0_6 |
| file://:0:0:0:0 | Unary | r0_6 |
| file://:0:0:0:0 | Unary | r0_7 |
| file://:0:0:0:0 | Unary | r0_7 |
| file://:0:0:0:0 | Unary | r0_7 |
@@ -6761,13 +6816,102 @@
| ir.cpp:1482:8:1482:8 | SideEffect | m1482_8 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_5 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_5 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_5 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_5 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_7 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_7 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_7 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_7 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_9 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_10 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_12 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_16 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_17 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_19 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_23 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_24 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_26 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_30 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_31 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_33 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_37 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_38 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_40 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_44 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_45 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_47 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_51 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_52 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_54 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_58 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_59 |
| ir.cpp:1486:8:1486:8 | Address | &:r1486_61 |
| ir.cpp:1486:8:1486:8 | ChiPartial | partial:m1486_3 |
| ir.cpp:1486:8:1486:8 | ChiPartial | partial:m1486_3 |
| ir.cpp:1486:8:1486:8 | ChiPartial | partial:m1486_14 |
| ir.cpp:1486:8:1486:8 | ChiPartial | partial:m1486_21 |
| ir.cpp:1486:8:1486:8 | ChiPartial | partial:m1486_28 |
| ir.cpp:1486:8:1486:8 | ChiPartial | partial:m1486_35 |
| ir.cpp:1486:8:1486:8 | ChiPartial | partial:m1486_42 |
| ir.cpp:1486:8:1486:8 | ChiPartial | partial:m1486_49 |
| ir.cpp:1486:8:1486:8 | ChiPartial | partial:m1486_56 |
| ir.cpp:1486:8:1486:8 | ChiPartial | partial:m1486_63 |
| ir.cpp:1486:8:1486:8 | ChiTotal | total:m1486_2 |
| ir.cpp:1486:8:1486:8 | ChiTotal | total:m1486_2 |
| ir.cpp:1486:8:1486:8 | ChiTotal | total:m1486_8 |
| ir.cpp:1486:8:1486:8 | ChiTotal | total:m1486_15 |
| ir.cpp:1486:8:1486:8 | ChiTotal | total:m1486_22 |
| ir.cpp:1486:8:1486:8 | ChiTotal | total:m1486_29 |
| ir.cpp:1486:8:1486:8 | ChiTotal | total:m1486_36 |
| ir.cpp:1486:8:1486:8 | ChiTotal | total:m1486_43 |
| ir.cpp:1486:8:1486:8 | ChiTotal | total:m1486_50 |
| ir.cpp:1486:8:1486:8 | ChiTotal | total:m1486_57 |
| ir.cpp:1486:8:1486:8 | Load | m0_2 |
| ir.cpp:1486:8:1486:8 | Load | m0_2 |
| ir.cpp:1486:8:1486:8 | Load | m0_2 |
| ir.cpp:1486:8:1486:8 | Load | m0_2 |
| ir.cpp:1486:8:1486:8 | Load | m0_2 |
| ir.cpp:1486:8:1486:8 | Load | m0_2 |
| ir.cpp:1486:8:1486:8 | Load | m0_2 |
| ir.cpp:1486:8:1486:8 | Load | m0_2 |
| ir.cpp:1486:8:1486:8 | Load | m1486_6 |
| ir.cpp:1486:8:1486:8 | Load | m1486_6 |
| ir.cpp:1486:8:1486:8 | Load | ~m0_4 |
| ir.cpp:1486:8:1486:8 | Load | ~m0_4 |
| ir.cpp:1486:8:1486:8 | Load | ~m0_4 |
| ir.cpp:1486:8:1486:8 | Load | ~m0_4 |
| ir.cpp:1486:8:1486:8 | Load | ~m0_4 |
| ir.cpp:1486:8:1486:8 | Load | ~m0_4 |
| ir.cpp:1486:8:1486:8 | Load | ~m0_4 |
| ir.cpp:1486:8:1486:8 | Load | ~m0_4 |
| ir.cpp:1486:8:1486:8 | SideEffect | m1486_3 |
| ir.cpp:1486:8:1486:8 | SideEffect | m1486_3 |
| ir.cpp:1486:8:1486:8 | SideEffect | m1486_8 |
| ir.cpp:1486:8:1486:8 | SideEffect | m1486_64 |
| ir.cpp:1486:8:1486:8 | StoreValue | r1486_13 |
| ir.cpp:1486:8:1486:8 | StoreValue | r1486_20 |
| ir.cpp:1486:8:1486:8 | StoreValue | r1486_27 |
| ir.cpp:1486:8:1486:8 | StoreValue | r1486_34 |
| ir.cpp:1486:8:1486:8 | StoreValue | r1486_41 |
| ir.cpp:1486:8:1486:8 | StoreValue | r1486_48 |
| ir.cpp:1486:8:1486:8 | StoreValue | r1486_55 |
| ir.cpp:1486:8:1486:8 | StoreValue | r1486_62 |
| ir.cpp:1486:8:1486:8 | Unary | m1486_6 |
| ir.cpp:1486:8:1486:8 | Unary | m1486_6 |
| ir.cpp:1486:8:1486:8 | Unary | m1486_6 |
| ir.cpp:1486:8:1486:8 | Unary | m1486_6 |
| ir.cpp:1486:8:1486:8 | Unary | m1486_6 |
| ir.cpp:1486:8:1486:8 | Unary | m1486_6 |
| ir.cpp:1486:8:1486:8 | Unary | m1486_6 |
| ir.cpp:1486:8:1486:8 | Unary | m1486_6 |
| ir.cpp:1486:8:1486:8 | Unary | r1486_11 |
| ir.cpp:1486:8:1486:8 | Unary | r1486_18 |
| ir.cpp:1486:8:1486:8 | Unary | r1486_25 |
| ir.cpp:1486:8:1486:8 | Unary | r1486_32 |
| ir.cpp:1486:8:1486:8 | Unary | r1486_39 |
| ir.cpp:1486:8:1486:8 | Unary | r1486_46 |
| ir.cpp:1486:8:1486:8 | Unary | r1486_53 |
| ir.cpp:1486:8:1486:8 | Unary | r1486_60 |
| ir.cpp:1499:6:1499:35 | ChiPartial | partial:m1499_3 |
| ir.cpp:1499:6:1499:35 | ChiTotal | total:m1499_2 |
| ir.cpp:1499:6:1499:35 | SideEffect | ~m1525_7 |
@@ -6940,13 +7084,52 @@
| ir.cpp:1528:17:1528:17 | StoreValue | r1528_4 |
| ir.cpp:1539:8:1539:8 | Address | &:r1539_5 |
| ir.cpp:1539:8:1539:8 | Address | &:r1539_5 |
| ir.cpp:1539:8:1539:8 | Address | &:r1539_5 |
| ir.cpp:1539:8:1539:8 | Address | &:r1539_5 |
| ir.cpp:1539:8:1539:8 | Address | &:r1539_7 |
| ir.cpp:1539:8:1539:8 | Address | &:r1539_7 |
| ir.cpp:1539:8:1539:8 | Address | &:r1539_7 |
| ir.cpp:1539:8:1539:8 | Address | &:r1539_7 |
| ir.cpp:1539:8:1539:8 | Address | &:r1539_9 |
| ir.cpp:1539:8:1539:8 | Address | &:r1539_10 |
| ir.cpp:1539:8:1539:8 | Address | &:r1539_12 |
| ir.cpp:1539:8:1539:8 | Address | &:r1539_16 |
| ir.cpp:1539:8:1539:8 | Address | &:r1539_17 |
| ir.cpp:1539:8:1539:8 | Address | &:r1539_19 |
| ir.cpp:1539:8:1539:8 | Address | &:r1539_23 |
| ir.cpp:1539:8:1539:8 | Address | &:r1539_24 |
| ir.cpp:1539:8:1539:8 | Address | &:r1539_26 |
| ir.cpp:1539:8:1539:8 | ChiPartial | partial:m1539_3 |
| ir.cpp:1539:8:1539:8 | ChiPartial | partial:m1539_3 |
| ir.cpp:1539:8:1539:8 | ChiPartial | partial:m1539_14 |
| ir.cpp:1539:8:1539:8 | ChiPartial | partial:m1539_21 |
| ir.cpp:1539:8:1539:8 | ChiPartial | partial:m1539_28 |
| ir.cpp:1539:8:1539:8 | ChiTotal | total:m1539_2 |
| ir.cpp:1539:8:1539:8 | ChiTotal | total:m1539_2 |
| ir.cpp:1539:8:1539:8 | ChiTotal | total:m1539_8 |
| ir.cpp:1539:8:1539:8 | ChiTotal | total:m1539_15 |
| ir.cpp:1539:8:1539:8 | ChiTotal | total:m1539_22 |
| ir.cpp:1539:8:1539:8 | Load | m0_2 |
| ir.cpp:1539:8:1539:8 | Load | m0_2 |
| ir.cpp:1539:8:1539:8 | Load | m0_2 |
| ir.cpp:1539:8:1539:8 | Load | m1539_6 |
| ir.cpp:1539:8:1539:8 | Load | m1539_6 |
| ir.cpp:1539:8:1539:8 | Load | ~m0_4 |
| ir.cpp:1539:8:1539:8 | Load | ~m0_4 |
| ir.cpp:1539:8:1539:8 | Load | ~m0_4 |
| ir.cpp:1539:8:1539:8 | SideEffect | m1539_3 |
| ir.cpp:1539:8:1539:8 | SideEffect | m1539_3 |
| ir.cpp:1539:8:1539:8 | SideEffect | m1539_8 |
| ir.cpp:1539:8:1539:8 | SideEffect | m1539_29 |
| ir.cpp:1539:8:1539:8 | StoreValue | r1539_13 |
| ir.cpp:1539:8:1539:8 | StoreValue | r1539_20 |
| ir.cpp:1539:8:1539:8 | StoreValue | r1539_27 |
| ir.cpp:1539:8:1539:8 | Unary | m1539_6 |
| ir.cpp:1539:8:1539:8 | Unary | m1539_6 |
| ir.cpp:1539:8:1539:8 | Unary | m1539_6 |
| ir.cpp:1539:8:1539:8 | Unary | r1539_11 |
| ir.cpp:1539:8:1539:8 | Unary | r1539_18 |
| ir.cpp:1539:8:1539:8 | Unary | r1539_25 |
| ir.cpp:1567:60:1567:95 | Address | &:r1567_5 |
| ir.cpp:1567:60:1567:95 | Address | &:r1567_5 |
| ir.cpp:1567:60:1567:95 | Address | &:r1567_7 |
@@ -7436,6 +7619,100 @@
| ir.cpp:1668:17:1668:17 | Load | m1661_14 |
| ir.cpp:1668:17:1668:17 | Load | ~m1666_6 |
| ir.cpp:1668:17:1668:17 | StoreValue | r1668_4 |
| ir.cpp:1672:6:1672:42 | ChiPartial | partial:m1672_3 |
| ir.cpp:1672:6:1672:42 | ChiTotal | total:m1672_2 |
| ir.cpp:1672:6:1672:42 | SideEffect | m1672_3 |
| ir.cpp:1673:9:1673:10 | Address | &:r1673_1 |
| ir.cpp:1673:9:1673:10 | Left | r1673_1 |
| ir.cpp:1673:9:1673:10 | Left | r1673_1 |
| ir.cpp:1673:16:1673:22 | Address | &:r1673_4 |
| ir.cpp:1673:16:1673:22 | Address | &:r1673_9 |
| ir.cpp:1673:16:1673:22 | Right | r1673_3 |
| ir.cpp:1673:16:1673:22 | Right | r1673_8 |
| ir.cpp:1673:18:1673:18 | ChiPartial | partial:m1673_6 |
| ir.cpp:1673:18:1673:18 | ChiTotal | total:m1673_2 |
| ir.cpp:1673:18:1673:18 | StoreValue | r1673_5 |
| ir.cpp:1673:21:1673:21 | ChiPartial | partial:m1673_11 |
| ir.cpp:1673:21:1673:21 | ChiTotal | total:m1673_7 |
| ir.cpp:1673:21:1673:21 | StoreValue | r1673_10 |
| ir.cpp:1674:10:1674:10 | Address | &:r1674_1 |
| ir.cpp:1674:11:1674:11 | Address | &:r1674_5 |
| ir.cpp:1674:15:1674:15 | Address | &:r1674_6 |
| ir.cpp:1674:21:1674:22 | Address | &:r1674_2 |
| ir.cpp:1674:21:1674:22 | Load | m1673_12 |
| ir.cpp:1674:21:1674:22 | StoreValue | r1674_3 |
| ir.cpp:1680:5:1680:23 | Address | &:r1680_5 |
| ir.cpp:1680:5:1680:23 | Address | &:r1680_5 |
| ir.cpp:1680:5:1680:23 | Address | &:r1680_7 |
| ir.cpp:1680:5:1680:23 | Address | &:r1680_7 |
| ir.cpp:1680:5:1680:23 | ChiPartial | partial:m1680_3 |
| ir.cpp:1680:5:1680:23 | ChiTotal | total:m1680_2 |
| ir.cpp:1680:5:1680:23 | Load | m1680_6 |
| ir.cpp:1680:5:1680:23 | SideEffect | m1680_3 |
| ir.cpp:1680:5:1680:23 | SideEffect | m1680_8 |
| ir.cpp:1683:6:1683:20 | ChiPartial | partial:m1683_3 |
| ir.cpp:1683:6:1683:20 | ChiTotal | total:m1683_2 |
| ir.cpp:1683:26:1683:26 | Address | &:r1683_5 |
| ir.cpp:1683:34:1683:34 | Address | &:r1683_7 |
| ir.cpp:1683:34:1683:34 | Address | &:r1683_7 |
| ir.cpp:1683:34:1683:34 | Address | &:r1683_9 |
| ir.cpp:1683:34:1683:34 | Load | m1683_8 |
| ir.cpp:1683:43:1683:43 | Address | &:r1683_11 |
| ir.cpp:1683:43:1683:43 | Address | &:r1683_11 |
| ir.cpp:1683:43:1683:43 | Address | &:r1683_13 |
| ir.cpp:1683:43:1683:43 | Load | m1683_12 |
| ir.cpp:1685:17:1685:20 | Address | &:r1685_1 |
| ir.cpp:1685:24:1685:44 | Address | &:r1685_2 |
| ir.cpp:1685:24:1685:44 | Address | &:r1685_2 |
| ir.cpp:1685:24:1685:44 | Arg(this) | this:r1685_2 |
| ir.cpp:1685:24:1685:44 | CallTarget | func:r1685_4 |
| ir.cpp:1685:24:1685:44 | ChiPartial | partial:m1685_6 |
| ir.cpp:1685:24:1685:44 | ChiPartial | partial:m1685_8 |
| ir.cpp:1685:24:1685:44 | ChiTotal | total:m1683_4 |
| ir.cpp:1685:24:1685:44 | ChiTotal | total:m1685_3 |
| ir.cpp:1685:24:1685:44 | SideEffect | ~m1683_4 |
| ir.cpp:1685:24:1685:44 | StoreValue | r1685_11 |
| ir.cpp:1685:24:1685:44 | Unary | r1685_2 |
| ir.cpp:1685:24:1685:44 | Unary | r1685_10 |
| ir.cpp:1686:10:1686:13 | Address | &:r1686_1 |
| ir.cpp:1686:10:1686:13 | Address | &:r1686_1 |
| ir.cpp:1686:10:1686:13 | Arg(this) | this:r1686_1 |
| ir.cpp:1686:16:1686:37 | CallTarget | func:r1686_3 |
| ir.cpp:1686:16:1686:37 | ChiPartial | partial:m1686_5 |
| ir.cpp:1686:16:1686:37 | ChiPartial | partial:m1686_7 |
| ir.cpp:1686:16:1686:37 | ChiTotal | total:m1685_7 |
| ir.cpp:1686:16:1686:37 | ChiTotal | total:m1686_2 |
| ir.cpp:1686:16:1686:37 | SideEffect | ~m1685_7 |
| ir.cpp:1688:24:1690:5 | Address | &:r1688_2 |
| ir.cpp:1688:24:1690:5 | Unary | r1688_2 |
| ir.cpp:1688:46:1688:46 | Address | &:r1688_5 |
| ir.cpp:1688:46:1688:46 | Address | &:r1688_5 |
| ir.cpp:1688:46:1688:46 | Address | &:r1688_7 |
| ir.cpp:1688:46:1688:46 | ChiPartial | partial:m1688_3 |
| ir.cpp:1688:46:1688:46 | ChiTotal | total:m1688_2 |
| ir.cpp:1688:46:1688:46 | Load | m1688_6 |
| ir.cpp:1689:28:1689:54 | Address | &:r1689_2 |
| ir.cpp:1689:28:1689:54 | Unary | r1689_2 |
| ir.cpp:1689:50:1689:50 | Address | &:r1689_5 |
| ir.cpp:1689:50:1689:50 | Address | &:r1689_5 |
| ir.cpp:1689:50:1689:50 | Address | &:r1689_7 |
| ir.cpp:1689:50:1689:50 | Address | &:r1689_7 |
| ir.cpp:1689:50:1689:50 | ChiPartial | partial:m1689_3 |
| ir.cpp:1689:50:1689:50 | ChiTotal | total:m1689_2 |
| ir.cpp:1689:50:1689:50 | Load | m1689_6 |
| ir.cpp:1689:50:1689:50 | SideEffect | m1689_3 |
| ir.cpp:1689:50:1689:50 | SideEffect | m1689_8 |
| ir.cpp:1693:5:1693:21 | Address | &:r1693_5 |
| ir.cpp:1693:5:1693:21 | ChiPartial | partial:m1693_3 |
| ir.cpp:1693:5:1693:21 | ChiTotal | total:m1693_2 |
| ir.cpp:1693:5:1693:21 | Load | m1696_4 |
| ir.cpp:1693:5:1693:21 | SideEffect | m1693_3 |
| ir.cpp:1694:7:1694:7 | Address | &:r1694_1 |
| ir.cpp:1694:10:1694:12 | StoreValue | r1694_2 |
| ir.cpp:1696:3:1696:11 | Address | &:r1696_1 |
| ir.cpp:1696:10:1696:10 | Address | &:r1696_2 |
| ir.cpp:1696:10:1696:10 | Load | m1694_3 |
| ir.cpp:1696:10:1696:10 | StoreValue | r1696_3 |
| perf-regression.cpp:6:3:6:5 | Address | &:r6_5 |
| perf-regression.cpp:6:3:6:5 | Address | &:r6_5 |
| perf-regression.cpp:6:3:6:5 | Address | &:r6_7 |

View File

@@ -1,4 +1,8 @@
missingOperand
| ir.cpp:1688:24:1690:5 | Store: Unknown literal | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | ir.cpp:1683:6:1683:20 | void captured_lambda(int, int&, int&&) | void captured_lambda(int, int&, int&&) |
| ir.cpp:1688:24:1690:5 | Store: Unknown literal | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | ir.cpp:1683:6:1683:20 | void captured_lambda(int, int&, int&&) | void captured_lambda(int, int&, int&&) |
| ir.cpp:1689:28:1689:54 | Store: Unknown literal | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | ir.cpp:1688:46:1688:46 | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const |
| ir.cpp:1689:28:1689:54 | Store: Unknown literal | Instruction 'Store' is missing an expected operand with tag 'StoreValue' in function '$@'. | ir.cpp:1688:46:1688:46 | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const |
unexpectedOperand
duplicateOperand
missingPhiOperand
@@ -7,6 +11,10 @@ duplicateChiOperand
sideEffectWithoutPrimary
instructionWithoutSuccessor
| ../../../include/memory.h:68:25:68:33 | CopyValue: (reference to) | Instruction 'CopyValue: (reference to)' has no successors in function '$@'. | ../../../include/memory.h:67:5:67:5 | void std::unique_ptr<int, std::default_delete<int>>::~unique_ptr() | void std::unique_ptr<int, std::default_delete<int>>::~unique_ptr() |
| ir.cpp:1688:24:1690:5 | FieldAddress: {...} | Instruction 'FieldAddress: {...}' has no successors in function '$@'. | ir.cpp:1683:6:1683:20 | void captured_lambda(int, int&, int&&) | void captured_lambda(int, int&, int&&) |
| ir.cpp:1688:24:1690:5 | FieldAddress: {...} | Instruction 'FieldAddress: {...}' has no successors in function '$@'. | ir.cpp:1683:6:1683:20 | void captured_lambda(int, int&, int&&) | void captured_lambda(int, int&, int&&) |
| ir.cpp:1689:28:1689:54 | FieldAddress: {...} | Instruction 'FieldAddress: {...}' has no successors in function '$@'. | ir.cpp:1688:46:1688:46 | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const |
| ir.cpp:1689:28:1689:54 | FieldAddress: {...} | Instruction 'FieldAddress: {...}' has no successors in function '$@'. | ir.cpp:1688:46:1688:46 | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const |
ambiguousSuccessors
unexplainedLoop
unnecessaryPhiInstruction
@@ -18,6 +26,25 @@ lostReachability
backEdgeCountMismatch
useNotDominatedByDefinition
| ir.cpp:1486:8:1486:8 | Unary | Operand 'Unary' is not dominated by its definition in function '$@'. | ir.cpp:1486:8:1486:8 | void StructuredBindingDataMemberStruct::StructuredBindingDataMemberStruct() | void StructuredBindingDataMemberStruct::StructuredBindingDataMemberStruct() |
| ir.cpp:1683:34:1683:34 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:1683:6:1683:20 | void captured_lambda(int, int&, int&&) | void captured_lambda(int, int&, int&&) |
| ir.cpp:1683:43:1683:43 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:1683:6:1683:20 | void captured_lambda(int, int&, int&&) | void captured_lambda(int, int&, int&&) |
| ir.cpp:1688:10:1688:21 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:1683:6:1683:20 | void captured_lambda(int, int&, int&&) | void captured_lambda(int, int&, int&&) |
| ir.cpp:1688:24:1690:5 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:1683:6:1683:20 | void captured_lambda(int, int&, int&&) | void captured_lambda(int, int&, int&&) |
| ir.cpp:1688:24:1690:5 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:1683:6:1683:20 | void captured_lambda(int, int&, int&&) | void captured_lambda(int, int&, int&&) |
| ir.cpp:1688:24:1690:5 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:1683:6:1683:20 | void captured_lambda(int, int&, int&&) | void captured_lambda(int, int&, int&&) |
| ir.cpp:1688:24:1690:5 | Unary | Operand 'Unary' is not dominated by its definition in function '$@'. | ir.cpp:1683:6:1683:20 | void captured_lambda(int, int&, int&&) | void captured_lambda(int, int&, int&&) |
| ir.cpp:1688:24:1690:5 | Unary | Operand 'Unary' is not dominated by its definition in function '$@'. | ir.cpp:1683:6:1683:20 | void captured_lambda(int, int&, int&&) | void captured_lambda(int, int&, int&&) |
| ir.cpp:1688:24:1690:5 | Unary | Operand 'Unary' is not dominated by its definition in function '$@'. | ir.cpp:1683:6:1683:20 | void captured_lambda(int, int&, int&&) | void captured_lambda(int, int&, int&&) |
| ir.cpp:1688:24:1690:5 | Unary | Operand 'Unary' is not dominated by its definition in function '$@'. | ir.cpp:1683:6:1683:20 | void captured_lambda(int, int&, int&&) | void captured_lambda(int, int&, int&&) |
| ir.cpp:1688:46:1688:46 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:1688:46:1688:46 | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const |
| ir.cpp:1689:14:1689:25 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:1688:46:1688:46 | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const |
| ir.cpp:1689:28:1689:54 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:1688:46:1688:46 | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const |
| ir.cpp:1689:28:1689:54 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:1688:46:1688:46 | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const |
| ir.cpp:1689:28:1689:54 | Address | Operand 'Address' is not dominated by its definition in function '$@'. | ir.cpp:1688:46:1688:46 | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const |
| ir.cpp:1689:28:1689:54 | Unary | Operand 'Unary' is not dominated by its definition in function '$@'. | ir.cpp:1688:46:1688:46 | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const |
| ir.cpp:1689:28:1689:54 | Unary | Operand 'Unary' is not dominated by its definition in function '$@'. | ir.cpp:1688:46:1688:46 | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const |
| ir.cpp:1689:28:1689:54 | Unary | Operand 'Unary' is not dominated by its definition in function '$@'. | ir.cpp:1688:46:1688:46 | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const |
| ir.cpp:1689:28:1689:54 | Unary | Operand 'Unary' is not dominated by its definition in function '$@'. | ir.cpp:1688:46:1688:46 | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const |
switchInstructionWithoutDefaultEdge
notMarkedAsConflated
wronglyMarkedAsConflated

View File

@@ -49,6 +49,38 @@ bad_asts.cpp:
# 14| v14_5(void) = AliasedUse : ~m?
# 14| v14_6(void) = ExitFunction :
# 19| void Bad::Point::Point(Bad::Point const&)
# 19| Block 0
# 19| v19_1(void) = EnterFunction :
# 19| mu19_2(unknown) = AliasedDefinition :
# 19| mu19_3(unknown) = InitializeNonLocal :
# 19| r19_4(glval<unknown>) = VariableAddress[#this] :
# 19| mu19_5(glval<Point>) = InitializeParameter[#this] : &:r19_4
# 19| r19_6(glval<Point>) = Load[#this] : &:r19_4, ~m?
# 19| mu19_7(Point) = InitializeIndirection[#this] : &:r19_6
#-----| r0_1(glval<Point &>) = VariableAddress[(unnamed parameter 0)] :
#-----| mu0_2(Point &) = InitializeParameter[(unnamed parameter 0)] : &:r0_1
#-----| r0_3(Point &) = Load[(unnamed parameter 0)] : &:r0_1, ~m?
#-----| mu0_4(unknown) = InitializeIndirection[(unnamed parameter 0)] : &:r0_3
# 19| r19_8(glval<int>) = FieldAddress[x] : mu19_5
# 19| r19_9(glval<Point &>) = VariableAddress[(unnamed parameter 0)] :
# 19| r19_10(Point &) = Load[(unnamed parameter 0)] : &:r19_9, ~m?
# 19| r19_11(glval<int>) = FieldAddress[x] : r19_10
# 19| r19_12(int) = Load[?] : &:r19_11, ~m?
# 19| mu19_13(int) = Store[?] : &:r19_8, r19_12
# 19| r19_14(glval<int>) = FieldAddress[y] : mu19_5
# 19| r19_15(glval<Point &>) = VariableAddress[(unnamed parameter 0)] :
# 19| r19_16(Point &) = Load[(unnamed parameter 0)] : &:r19_15, ~m?
# 19| r19_17(glval<int>) = FieldAddress[y] : r19_16
# 19| r19_18(int) = Load[?] : &:r19_17, ~m?
# 19| mu19_19(int) = Store[?] : &:r19_14, r19_18
# 19| v19_20(void) = NoOp :
# 19| v19_21(void) = ReturnIndirection[#this] : &:r19_6, ~m?
#-----| v0_5(void) = ReturnIndirection[(unnamed parameter 0)] : &:r0_3, ~m?
# 19| v19_22(void) = ReturnVoid :
# 19| v19_23(void) = AliasedUse : ~m?
# 19| v19_24(void) = ExitFunction :
# 22| void Bad::Point::Point()
# 22| Block 0
# 22| v22_1(void) = EnterFunction :
@@ -8029,6 +8061,74 @@ ir.cpp:
# 1486| v1486_16(void) = AliasedUse : ~m?
# 1486| v1486_17(void) = ExitFunction :
# 1486| void StructuredBindingDataMemberStruct::StructuredBindingDataMemberStruct(StructuredBindingDataMemberStruct const&)
# 1486| Block 0
# 1486| v1486_1(void) = EnterFunction :
# 1486| mu1486_2(unknown) = AliasedDefinition :
# 1486| mu1486_3(unknown) = InitializeNonLocal :
# 1486| r1486_4(glval<unknown>) = VariableAddress[#this] :
# 1486| mu1486_5(glval<StructuredBindingDataMemberStruct>) = InitializeParameter[#this] : &:r1486_4
# 1486| r1486_6(glval<StructuredBindingDataMemberStruct>) = Load[#this] : &:r1486_4, ~m?
# 1486| mu1486_7(StructuredBindingDataMemberStruct) = InitializeIndirection[#this] : &:r1486_6
#-----| r0_1(glval<StructuredBindingDataMemberStruct &>) = VariableAddress[(unnamed parameter 0)] :
#-----| mu0_2(StructuredBindingDataMemberStruct &) = InitializeParameter[(unnamed parameter 0)] : &:r0_1
#-----| r0_3(StructuredBindingDataMemberStruct &) = Load[(unnamed parameter 0)] : &:r0_1, ~m?
#-----| mu0_4(unknown) = InitializeIndirection[(unnamed parameter 0)] : &:r0_3
# 1486| r1486_8(glval<int>) = FieldAddress[i] : mu1486_5
# 1486| r1486_9(glval<StructuredBindingDataMemberStruct &>) = VariableAddress[(unnamed parameter 0)] :
# 1486| r1486_10(StructuredBindingDataMemberStruct &) = Load[(unnamed parameter 0)] : &:r1486_9, ~m?
# 1486| r1486_11(glval<int>) = FieldAddress[i] : r1486_10
# 1486| r1486_12(int) = Load[?] : &:r1486_11, ~m?
# 1486| mu1486_13(int) = Store[?] : &:r1486_8, r1486_12
# 1486| r1486_14(glval<double>) = FieldAddress[d] : mu1486_5
# 1486| r1486_15(glval<StructuredBindingDataMemberStruct &>) = VariableAddress[(unnamed parameter 0)] :
# 1486| r1486_16(StructuredBindingDataMemberStruct &) = Load[(unnamed parameter 0)] : &:r1486_15, ~m?
# 1486| r1486_17(glval<double>) = FieldAddress[d] : r1486_16
# 1486| r1486_18(double) = Load[?] : &:r1486_17, ~m?
# 1486| mu1486_19(double) = Store[?] : &:r1486_14, r1486_18
# 1486| r1486_20(glval<unsigned int>) = FieldAddress[b] : mu1486_5
# 1486| r1486_21(glval<StructuredBindingDataMemberStruct &>) = VariableAddress[(unnamed parameter 0)] :
# 1486| r1486_22(StructuredBindingDataMemberStruct &) = Load[(unnamed parameter 0)] : &:r1486_21, ~m?
# 1486| r1486_23(glval<unsigned int>) = FieldAddress[b] : r1486_22
# 1486| r1486_24(unsigned int) = Load[?] : &:r1486_23, ~m?
# 1486| mu1486_25(unsigned int) = Store[?] : &:r1486_20, r1486_24
# 1486| r1486_26(glval<int &>) = FieldAddress[r] : mu1486_5
# 1486| r1486_27(glval<StructuredBindingDataMemberStruct &>) = VariableAddress[(unnamed parameter 0)] :
# 1486| r1486_28(StructuredBindingDataMemberStruct &) = Load[(unnamed parameter 0)] : &:r1486_27, ~m?
# 1486| r1486_29(glval<int &>) = FieldAddress[r] : r1486_28
# 1486| r1486_30(int &) = Load[?] : &:r1486_29, ~m?
# 1486| mu1486_31(int &) = Store[?] : &:r1486_26, r1486_30
# 1486| r1486_32(glval<int *>) = FieldAddress[p] : mu1486_5
# 1486| r1486_33(glval<StructuredBindingDataMemberStruct &>) = VariableAddress[(unnamed parameter 0)] :
# 1486| r1486_34(StructuredBindingDataMemberStruct &) = Load[(unnamed parameter 0)] : &:r1486_33, ~m?
# 1486| r1486_35(glval<int *>) = FieldAddress[p] : r1486_34
# 1486| r1486_36(int *) = Load[?] : &:r1486_35, ~m?
# 1486| mu1486_37(int *) = Store[?] : &:r1486_32, r1486_36
# 1486| r1486_38(glval<int[2]>) = FieldAddress[xs] : mu1486_5
# 1486| r1486_39(glval<StructuredBindingDataMemberStruct &>) = VariableAddress[(unnamed parameter 0)] :
# 1486| r1486_40(StructuredBindingDataMemberStruct &) = Load[(unnamed parameter 0)] : &:r1486_39, ~m?
# 1486| r1486_41(glval<int[2]>) = FieldAddress[xs] : r1486_40
# 1486| r1486_42(int[2]) = Load[?] : &:r1486_41, ~m?
# 1486| mu1486_43(int[2]) = Store[?] : &:r1486_38, r1486_42
# 1486| r1486_44(glval<int &>) = FieldAddress[r_alt] : mu1486_5
# 1486| r1486_45(glval<StructuredBindingDataMemberStruct &>) = VariableAddress[(unnamed parameter 0)] :
# 1486| r1486_46(StructuredBindingDataMemberStruct &) = Load[(unnamed parameter 0)] : &:r1486_45, ~m?
# 1486| r1486_47(glval<int &>) = FieldAddress[r_alt] : r1486_46
# 1486| r1486_48(int &) = Load[?] : &:r1486_47, ~m?
# 1486| mu1486_49(int &) = Store[?] : &:r1486_44, r1486_48
# 1486| r1486_50(glval<StructuredBindingDataMemberMemberStruct>) = FieldAddress[m] : mu1486_5
# 1486| r1486_51(glval<StructuredBindingDataMemberStruct &>) = VariableAddress[(unnamed parameter 0)] :
# 1486| r1486_52(StructuredBindingDataMemberStruct &) = Load[(unnamed parameter 0)] : &:r1486_51, ~m?
# 1486| r1486_53(glval<StructuredBindingDataMemberMemberStruct>) = FieldAddress[m] : r1486_52
# 1486| r1486_54(StructuredBindingDataMemberMemberStruct) = Load[?] : &:r1486_53, ~m?
# 1486| mu1486_55(StructuredBindingDataMemberMemberStruct) = Store[?] : &:r1486_50, r1486_54
# 1486| v1486_56(void) = NoOp :
# 1486| v1486_57(void) = ReturnIndirection[#this] : &:r1486_6, ~m?
#-----| v0_5(void) = ReturnIndirection[(unnamed parameter 0)] : &:r0_3, ~m?
# 1486| v1486_58(void) = ReturnVoid :
# 1486| v1486_59(void) = AliasedUse : ~m?
# 1486| v1486_60(void) = ExitFunction :
# 1499| void data_member_structured_binding()
# 1499| Block 0
# 1499| v1499_1(void) = EnterFunction :
@@ -8209,6 +8309,44 @@ ir.cpp:
# 1539| v1539_11(void) = AliasedUse : ~m?
# 1539| v1539_12(void) = ExitFunction :
# 1539| void StructuredBindingTupleRefGet::StructuredBindingTupleRefGet(StructuredBindingTupleRefGet const&)
# 1539| Block 0
# 1539| v1539_1(void) = EnterFunction :
# 1539| mu1539_2(unknown) = AliasedDefinition :
# 1539| mu1539_3(unknown) = InitializeNonLocal :
# 1539| r1539_4(glval<unknown>) = VariableAddress[#this] :
# 1539| mu1539_5(glval<StructuredBindingTupleRefGet>) = InitializeParameter[#this] : &:r1539_4
# 1539| r1539_6(glval<StructuredBindingTupleRefGet>) = Load[#this] : &:r1539_4, ~m?
# 1539| mu1539_7(StructuredBindingTupleRefGet) = InitializeIndirection[#this] : &:r1539_6
#-----| r0_1(glval<StructuredBindingTupleRefGet &>) = VariableAddress[(unnamed parameter 0)] :
#-----| mu0_2(StructuredBindingTupleRefGet &) = InitializeParameter[(unnamed parameter 0)] : &:r0_1
#-----| r0_3(StructuredBindingTupleRefGet &) = Load[(unnamed parameter 0)] : &:r0_1, ~m?
#-----| mu0_4(unknown) = InitializeIndirection[(unnamed parameter 0)] : &:r0_3
# 1539| r1539_8(glval<int>) = FieldAddress[i] : mu1539_5
# 1539| r1539_9(glval<StructuredBindingTupleRefGet &>) = VariableAddress[(unnamed parameter 0)] :
# 1539| r1539_10(StructuredBindingTupleRefGet &) = Load[(unnamed parameter 0)] : &:r1539_9, ~m?
# 1539| r1539_11(glval<int>) = FieldAddress[i] : r1539_10
# 1539| r1539_12(int) = Load[?] : &:r1539_11, ~m?
# 1539| mu1539_13(int) = Store[?] : &:r1539_8, r1539_12
# 1539| r1539_14(glval<double>) = FieldAddress[d] : mu1539_5
# 1539| r1539_15(glval<StructuredBindingTupleRefGet &>) = VariableAddress[(unnamed parameter 0)] :
# 1539| r1539_16(StructuredBindingTupleRefGet &) = Load[(unnamed parameter 0)] : &:r1539_15, ~m?
# 1539| r1539_17(glval<double>) = FieldAddress[d] : r1539_16
# 1539| r1539_18(double) = Load[?] : &:r1539_17, ~m?
# 1539| mu1539_19(double) = Store[?] : &:r1539_14, r1539_18
# 1539| r1539_20(glval<int &>) = FieldAddress[r] : mu1539_5
# 1539| r1539_21(glval<StructuredBindingTupleRefGet &>) = VariableAddress[(unnamed parameter 0)] :
# 1539| r1539_22(StructuredBindingTupleRefGet &) = Load[(unnamed parameter 0)] : &:r1539_21, ~m?
# 1539| r1539_23(glval<int &>) = FieldAddress[r] : r1539_22
# 1539| r1539_24(int &) = Load[?] : &:r1539_23, ~m?
# 1539| mu1539_25(int &) = Store[?] : &:r1539_20, r1539_24
# 1539| v1539_26(void) = NoOp :
# 1539| v1539_27(void) = ReturnIndirection[#this] : &:r1539_6, ~m?
#-----| v0_5(void) = ReturnIndirection[(unnamed parameter 0)] : &:r0_3, ~m?
# 1539| v1539_28(void) = ReturnVoid :
# 1539| v1539_29(void) = AliasedUse : ~m?
# 1539| v1539_30(void) = ExitFunction :
# 1567| std::tuple_element<int 0, StructuredBindingTupleRefGet>::type& StructuredBindingTupleRefGet::get<int 0>()
# 1567| Block 0
# 1567| v1567_1(void) = EnterFunction :
@@ -8664,6 +8802,203 @@ ir.cpp:
# 1645| v1645_5(void) = AliasedUse : ~m?
# 1645| v1645_6(void) = ExitFunction :
# 1672| void array_structured_binding_non_ref_init()
# 1672| Block 0
# 1672| v1672_1(void) = EnterFunction :
# 1672| mu1672_2(unknown) = AliasedDefinition :
# 1672| mu1672_3(unknown) = InitializeNonLocal :
# 1673| r1673_1(glval<int[2]>) = VariableAddress[xs] :
# 1673| mu1673_2(int[2]) = Uninitialized[xs] : &:r1673_1
# 1673| r1673_3(int) = Constant[0] :
# 1673| r1673_4(glval<int>) = PointerAdd[4] : r1673_1, r1673_3
# 1673| r1673_5(int) = Constant[1] :
# 1673| mu1673_6(int) = Store[?] : &:r1673_4, r1673_5
# 1673| r1673_7(int) = Constant[1] :
# 1673| r1673_8(glval<int>) = PointerAdd[4] : r1673_1, r1673_7
# 1673| r1673_9(int) = Constant[2] :
# 1673| mu1673_10(int) = Store[?] : &:r1673_8, r1673_9
# 1674| r1674_1(glval<int[2]>) = VariableAddress[(unnamed local variable)] :
# 1674| r1674_2(glval<int[2]>) = VariableAddress[xs] :
# 1674| r1674_3(int[2]) = Load[xs] : &:r1674_2, ~m?
# 1674| mu1674_4(int[2]) = Store[(unnamed local variable)] : &:r1674_1, r1674_3
# 1674| r1674_5(glval<int &>) = VariableAddress[x0] :
#-----| r0_1(glval<int[2]>) = VariableAddress[(unnamed local variable)] :
#-----| r0_2(int *) = Convert : r0_1
#-----| r0_3(unsigned long) = Constant[0] :
#-----| r0_4(glval<int>) = PointerAdd[4] : r0_2, r0_3
#-----| mu0_5(int &) = Store[x0] : &:r1674_5, r0_4
# 1674| r1674_6(glval<int &>) = VariableAddress[x1] :
#-----| r0_6(glval<int[2]>) = VariableAddress[(unnamed local variable)] :
#-----| r0_7(int *) = Convert : r0_6
#-----| r0_8(unsigned long) = Constant[1] :
#-----| r0_9(glval<int>) = PointerAdd[4] : r0_7, r0_8
#-----| mu0_10(int &) = Store[x1] : &:r1674_6, r0_9
# 1675| v1675_1(void) = NoOp :
# 1672| v1672_4(void) = ReturnVoid :
# 1672| v1672_5(void) = AliasedUse : ~m?
# 1672| v1672_6(void) = ExitFunction :
# 1680| void CapturedLambdaMyObj::CapturedLambdaMyObj()
# 1680| Block 0
# 1680| v1680_1(void) = EnterFunction :
# 1680| mu1680_2(unknown) = AliasedDefinition :
# 1680| mu1680_3(unknown) = InitializeNonLocal :
# 1680| r1680_4(glval<unknown>) = VariableAddress[#this] :
# 1680| mu1680_5(glval<CapturedLambdaMyObj>) = InitializeParameter[#this] : &:r1680_4
# 1680| r1680_6(glval<CapturedLambdaMyObj>) = Load[#this] : &:r1680_4, ~m?
# 1680| mu1680_7(CapturedLambdaMyObj) = InitializeIndirection[#this] : &:r1680_6
# 1680| v1680_8(void) = NoOp :
# 1680| v1680_9(void) = ReturnIndirection[#this] : &:r1680_6, ~m?
# 1680| v1680_10(void) = ReturnVoid :
# 1680| v1680_11(void) = AliasedUse : ~m?
# 1680| v1680_12(void) = ExitFunction :
# 1683| void captured_lambda(int, int&, int&&)
# 1683| Block 0
# 1683| v1683_1(void) = EnterFunction :
# 1683| mu1683_2(unknown) = AliasedDefinition :
# 1683| mu1683_3(unknown) = InitializeNonLocal :
# 1683| r1683_4(glval<int>) = VariableAddress[x] :
# 1683| mu1683_5(int) = InitializeParameter[x] : &:r1683_4
# 1683| r1683_6(glval<int &>) = VariableAddress[y] :
# 1683| mu1683_7(int &) = InitializeParameter[y] : &:r1683_6
# 1683| r1683_8(int &) = Load[y] : &:r1683_6, ~m?
# 1683| mu1683_9(unknown) = InitializeIndirection[y] : &:r1683_8
# 1683| r1683_10(glval<int &&>) = VariableAddress[z] :
# 1683| mu1683_11(int &&) = InitializeParameter[z] : &:r1683_10
# 1683| r1683_12(int &&) = Load[z] : &:r1683_10, ~m?
# 1683| mu1683_13(unknown) = InitializeIndirection[z] : &:r1683_12
# 1685| r1685_1(glval<CapturedLambdaMyObj &>) = VariableAddress[obj1] :
# 1685| r1685_2(glval<CapturedLambdaMyObj>) = VariableAddress[#temp1685:24] :
# 1685| mu1685_3(CapturedLambdaMyObj) = Uninitialized[#temp1685:24] : &:r1685_2
# 1685| r1685_4(glval<unknown>) = FunctionAddress[CapturedLambdaMyObj] :
# 1685| v1685_5(void) = Call[CapturedLambdaMyObj] : func:r1685_4, this:r1685_2
# 1685| mu1685_6(unknown) = ^CallSideEffect : ~m?
# 1685| mu1685_7(CapturedLambdaMyObj) = ^IndirectMayWriteSideEffect[-1] : &:r1685_2
# 1685| r1685_8(glval<CapturedLambdaMyObj>) = Convert : r1685_2
# 1685| r1685_9(CapturedLambdaMyObj &) = CopyValue : r1685_8
# 1685| mu1685_10(CapturedLambdaMyObj &) = Store[obj1] : &:r1685_1, r1685_9
# 1686| r1686_1(glval<CapturedLambdaMyObj>) = VariableAddress[obj2] :
# 1686| mu1686_2(CapturedLambdaMyObj) = Uninitialized[obj2] : &:r1686_1
# 1686| r1686_3(glval<unknown>) = FunctionAddress[CapturedLambdaMyObj] :
# 1686| v1686_4(void) = Call[CapturedLambdaMyObj] : func:r1686_3, this:r1686_1
# 1686| mu1686_5(unknown) = ^CallSideEffect : ~m?
# 1686| mu1686_6(CapturedLambdaMyObj) = ^IndirectMayWriteSideEffect[-1] : &:r1686_1
# 1688| r1688_1(glval<decltype([...](...){...})>) = VariableAddress[lambda_outer] :
# 1688| r1688_2(glval<decltype([...](...){...})>) = VariableAddress[#temp1688:24] :
# 1688| mu1688_3(decltype([...](...){...})) = Uninitialized[#temp1688:24] : &:r1688_2
# 1688| r1688_4(glval<CapturedLambdaMyObj>) = FieldAddress[obj1] : r1688_2
# 1688| Block 1
# 1688| mu1688_5(CapturedLambdaMyObj) = Store[?] : &:r1688_4
# 1688| r1688_6(glval<CapturedLambdaMyObj>) = FieldAddress[obj2] : r1688_2
# 1688| Block 2
# 1688| mu1688_7(CapturedLambdaMyObj) = Store[?] : &:r1688_6
# 1688| r1688_8(glval<int>) = FieldAddress[x] : r1688_2
# 1688| r1688_9(glval<int>) = VariableAddress[x] :
# 1688| r1688_10(int) = Load[x] : &:r1688_9, ~m?
# 1688| mu1688_11(int) = Store[?] : &:r1688_8, r1688_10
# 1688| r1688_12(glval<int>) = FieldAddress[y] : r1688_2
# 1688| r1688_13(glval<int &>) = VariableAddress[y] :
# 1688| r1688_14(int &) = Load[y] : &:r1688_13, ~m?
# 1690| r1690_1(int) = Load[?] : &:r1688_14, ~m?
# 1690| mu1690_2(int) = Store[?] : &:r1688_12, r1690_1
# 1688| r1688_15(glval<int>) = FieldAddress[z] : r1688_2
# 1688| r1688_16(glval<int &&>) = VariableAddress[z] :
# 1688| r1688_17(int &&) = Load[z] : &:r1688_16, ~m?
# 1690| r1690_3(int) = Load[?] : &:r1688_17, ~m?
# 1690| mu1690_4(int) = Store[?] : &:r1688_15, r1690_3
# 1688| r1688_18(decltype([...](...){...})) = Load[#temp1688:24] : &:r1688_2, ~m?
# 1688| mu1688_19(decltype([...](...){...})) = Store[lambda_outer] : &:r1688_1, r1688_18
# 1691| v1691_1(void) = NoOp :
# 1683| v1683_14(void) = ReturnIndirection[y] : &:r1683_8, ~m?
# 1683| v1683_15(void) = ReturnIndirection[z] : &:r1683_12, ~m?
# 1683| v1683_16(void) = ReturnVoid :
# 1683| v1683_17(void) = AliasedUse : ~m?
# 1683| v1683_18(void) = ExitFunction :
# 1688| void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const
# 1688| Block 0
# 1688| v1688_1(void) = EnterFunction :
# 1688| mu1688_2(unknown) = AliasedDefinition :
# 1688| mu1688_3(unknown) = InitializeNonLocal :
# 1688| r1688_4(glval<unknown>) = VariableAddress[#this] :
# 1688| mu1688_5(glval<decltype([...](...){...})>) = InitializeParameter[#this] : &:r1688_4
# 1688| r1688_6(glval<decltype([...](...){...})>) = Load[#this] : &:r1688_4, ~m?
# 1688| mu1688_7(decltype([...](...){...})) = InitializeIndirection[#this] : &:r1688_6
# 1689| r1689_1(glval<decltype([...](...){...})>) = VariableAddress[lambda_inner] :
# 1689| r1689_2(glval<decltype([...](...){...})>) = VariableAddress[#temp1689:28] :
# 1689| mu1689_3(decltype([...](...){...})) = Uninitialized[#temp1689:28] : &:r1689_2
# 1689| r1689_4(glval<CapturedLambdaMyObj>) = FieldAddress[obj1] : r1689_2
# 1689| Block 1
# 1689| mu1689_5(CapturedLambdaMyObj) = Store[?] : &:r1689_4
# 1689| r1689_6(glval<CapturedLambdaMyObj>) = FieldAddress[obj2] : r1689_2
# 1689| Block 2
# 1689| mu1689_7(CapturedLambdaMyObj) = Store[?] : &:r1689_6
# 1689| r1689_8(glval<int>) = FieldAddress[x] : r1689_2
# 1689| r1689_9(glval<unknown>) = VariableAddress[#this] :
# 1689| r1689_10(lambda [] type at line 1688, col. 25 *) = Load[#this] : &:r1689_9, ~m?
# 1689| r1689_11(glval<int>) = FieldAddress[x] : r1689_10
# 1689| r1689_12(int) = Load[?] : &:r1689_11, ~m?
# 1689| mu1689_13(int) = Store[?] : &:r1689_8, r1689_12
# 1689| r1689_14(glval<int>) = FieldAddress[y] : r1689_2
# 1689| r1689_15(glval<unknown>) = VariableAddress[#this] :
# 1689| r1689_16(lambda [] type at line 1688, col. 25 *) = Load[#this] : &:r1689_15, ~m?
# 1689| r1689_17(glval<int>) = FieldAddress[y] : r1689_16
# 1689| r1689_18(int) = Load[?] : &:r1689_17, ~m?
# 1689| mu1689_19(int) = Store[?] : &:r1689_14, r1689_18
# 1689| r1689_20(glval<int>) = FieldAddress[z] : r1689_2
# 1689| r1689_21(glval<unknown>) = VariableAddress[#this] :
# 1689| r1689_22(lambda [] type at line 1688, col. 25 *) = Load[#this] : &:r1689_21, ~m?
# 1689| r1689_23(glval<int>) = FieldAddress[z] : r1689_22
# 1689| r1689_24(int) = Load[?] : &:r1689_23, ~m?
# 1689| mu1689_25(int) = Store[?] : &:r1689_20, r1689_24
# 1689| r1689_26(decltype([...](...){...})) = Load[#temp1689:28] : &:r1689_2, ~m?
# 1689| mu1689_27(decltype([...](...){...})) = Store[lambda_inner] : &:r1689_1, r1689_26
# 1690| v1690_1(void) = NoOp :
# 1688| v1688_8(void) = ReturnIndirection[#this] : &:r1688_6, ~m?
# 1688| v1688_9(void) = ReturnVoid :
# 1688| v1688_10(void) = AliasedUse : ~m?
# 1688| v1688_11(void) = ExitFunction :
# 1689| void (void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const)::(lambda [] type at line 1689, col. 29)::operator()() const
# 1689| Block 0
# 1689| v1689_1(void) = EnterFunction :
# 1689| mu1689_2(unknown) = AliasedDefinition :
# 1689| mu1689_3(unknown) = InitializeNonLocal :
# 1689| r1689_4(glval<unknown>) = VariableAddress[#this] :
# 1689| mu1689_5(glval<decltype([...](...){...})>) = InitializeParameter[#this] : &:r1689_4
# 1689| r1689_6(glval<decltype([...](...){...})>) = Load[#this] : &:r1689_4, ~m?
# 1689| mu1689_7(decltype([...](...){...})) = InitializeIndirection[#this] : &:r1689_6
# 1689| v1689_8(void) = NoOp :
# 1689| v1689_9(void) = NoOp :
# 1689| v1689_10(void) = ReturnIndirection[#this] : &:r1689_6, ~m?
# 1689| v1689_11(void) = ReturnVoid :
# 1689| v1689_12(void) = AliasedUse : ~m?
# 1689| v1689_13(void) = ExitFunction :
# 1693| int goto_on_same_line()
# 1693| Block 0
# 1693| v1693_1(void) = EnterFunction :
# 1693| mu1693_2(unknown) = AliasedDefinition :
# 1693| mu1693_3(unknown) = InitializeNonLocal :
# 1694| r1694_1(glval<int>) = VariableAddress[x] :
# 1694| r1694_2(int) = Constant[42] :
# 1694| mu1694_3(int) = Store[x] : &:r1694_1, r1694_2
# 1695| v1695_1(void) = NoOp :
# 1695| v1695_2(void) = NoOp :
# 1696| r1696_1(glval<int>) = VariableAddress[#return] :
# 1696| r1696_2(glval<int>) = VariableAddress[x] :
# 1696| r1696_3(int) = Load[x] : &:r1696_2, ~m?
# 1696| mu1696_4(int) = Store[#return] : &:r1696_1, r1696_3
# 1693| r1693_4(glval<int>) = VariableAddress[#return] :
# 1693| v1693_5(void) = ReturnValue : &:r1693_4, ~m?
# 1693| v1693_6(void) = AliasedUse : ~m?
# 1693| v1693_7(void) = ExitFunction :
perf-regression.cpp:
# 6| void Big::Big()
# 6| Block 0

View File

@@ -6,6 +6,8 @@ missingOperandType
duplicateChiOperand
sideEffectWithoutPrimary
instructionWithoutSuccessor
| ir.cpp:1688:24:1690:5 | FieldAddress: {...} | Instruction 'FieldAddress: {...}' has no successors in function '$@'. | ir.cpp:1683:6:1683:20 | void captured_lambda(int, int&, int&&) | void captured_lambda(int, int&, int&&) |
| ir.cpp:1689:28:1689:54 | FieldAddress: {...} | Instruction 'FieldAddress: {...}' has no successors in function '$@'. | ir.cpp:1688:46:1688:46 | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const |
ambiguousSuccessors
unexplainedLoop
unnecessaryPhiInstruction

View File

@@ -6,6 +6,8 @@ missingOperandType
duplicateChiOperand
sideEffectWithoutPrimary
instructionWithoutSuccessor
| ir.cpp:1688:24:1690:5 | FieldAddress: {...} | Instruction 'FieldAddress: {...}' has no successors in function '$@'. | ir.cpp:1683:6:1683:20 | void captured_lambda(int, int&, int&&) | void captured_lambda(int, int&, int&&) |
| ir.cpp:1689:28:1689:54 | FieldAddress: {...} | Instruction 'FieldAddress: {...}' has no successors in function '$@'. | ir.cpp:1688:46:1688:46 | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const | void (void captured_lambda(int, int&, int&&))::(lambda [] type at line 1688, col. 25)::operator()() const |
ambiguousSuccessors
unexplainedLoop
unnecessaryPhiInstruction

View File

@@ -125,8 +125,8 @@
| captures.cpp:22:19:22:19 | (unnamed constructor) |
| captures.cpp:22:19:22:19 | (unnamed constructor) |
| captures.cpp:22:19:22:19 | (unnamed constructor) |
| captures.cpp:22:19:22:19 | Unknown literal |
| captures.cpp:22:19:22:19 | Unknown literal |
| captures.cpp:22:19:22:19 | (unnamed parameter 0) |
| captures.cpp:22:19:22:19 | (unnamed parameter 0) |
| captures.cpp:22:19:22:19 | constructor init of field x |
| captures.cpp:22:19:22:19 | constructor init of field y |
| captures.cpp:22:19:22:19 | declaration of (unnamed constructor) |
@@ -135,6 +135,8 @@
| captures.cpp:22:19:22:19 | definition of operator= |
| captures.cpp:22:19:22:19 | operator= |
| captures.cpp:22:19:22:19 | return ... |
| captures.cpp:22:19:22:19 | x |
| captures.cpp:22:19:22:19 | y |
| captures.cpp:22:19:22:19 | { ... } |
| captures.cpp:22:23:22:23 | definition of x |
| captures.cpp:22:23:22:23 | x |
@@ -185,12 +187,13 @@
| end_pos.cpp:9:15:9:15 | (unnamed constructor) |
| end_pos.cpp:9:15:9:15 | (unnamed constructor) |
| end_pos.cpp:9:15:9:15 | (unnamed constructor) |
| end_pos.cpp:9:15:9:15 | Unknown literal |
| end_pos.cpp:9:15:9:15 | (unnamed parameter 0) |
| end_pos.cpp:9:15:9:15 | constructor init of field ii |
| end_pos.cpp:9:15:9:15 | declaration of (unnamed constructor) |
| end_pos.cpp:9:15:9:15 | definition of (unnamed constructor) |
| end_pos.cpp:9:15:9:15 | definition of (unnamed constructor) |
| end_pos.cpp:9:15:9:15 | definition of operator= |
| end_pos.cpp:9:15:9:15 | ii |
| end_pos.cpp:9:15:9:15 | operator= |
| end_pos.cpp:9:15:9:15 | return ... |
| end_pos.cpp:9:15:9:15 | { ... } |

View File

@@ -1498,6 +1498,8 @@ postWithInFlow
| bad_asts.cpp:15:10:15:12 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| bad_asts.cpp:16:5:16:5 | s [post update] | PostUpdateNode should not be the target of local flow. |
| bad_asts.cpp:16:5:16:5 | s [post update] | PostUpdateNode should not be the target of local flow. |
| bad_asts.cpp:19:10:19:10 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| bad_asts.cpp:19:10:19:10 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| bad_asts.cpp:27:11:27:11 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| break_labels.c:3:9:3:14 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| break_labels.c:5:9:5:14 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
@@ -1626,11 +1628,15 @@ postWithInFlow
| cpp11.cpp:60:15:60:16 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| cpp11.cpp:65:10:65:16 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| cpp11.cpp:65:19:65:45 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| cpp11.cpp:65:20:65:20 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| cpp11.cpp:65:35:65:43 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| cpp11.cpp:77:19:77:21 | Argument this [post update] | PostUpdateNode should not be the target of local flow. |
| cpp11.cpp:77:19:77:21 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| cpp11.cpp:82:11:82:14 | Argument this [post update] | PostUpdateNode should not be the target of local flow. |
| cpp11.cpp:82:11:82:14 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| cpp11.cpp:82:17:82:17 | Argument this [post update] | PostUpdateNode should not be the target of local flow. |
| cpp11.cpp:82:17:82:17 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| cpp11.cpp:82:17:82:17 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| cpp11.cpp:82:17:82:55 | Argument this [post update] | PostUpdateNode should not be the target of local flow. |
| cpp11.cpp:82:17:82:55 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| cpp11.cpp:82:17:82:55 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |

View File

@@ -3,7 +3,6 @@ edges
| tests.cpp:33:34:33:39 | call to getenv | tests.cpp:38:39:38:49 | environment indirection |
| tests.cpp:38:25:38:36 | strncat output argument | tests.cpp:26:15:26:23 | ReturnValue |
| tests.cpp:38:39:38:49 | environment indirection | tests.cpp:38:25:38:36 | strncat output argument |
| tests.cpp:38:39:38:49 | environment indirection | tests.cpp:38:25:38:36 | strncat output argument |
| tests.cpp:51:12:51:20 | call to badSource | tests.cpp:53:16:53:19 | data indirection |
nodes
| tests.cpp:26:15:26:23 | ReturnValue | semmle.label | ReturnValue |

View File

@@ -2,39 +2,77 @@ edges
| test.cpp:16:20:16:23 | argv | test.cpp:22:45:22:52 | userName indirection |
| test.cpp:22:13:22:20 | sprintf output argument | test.cpp:23:12:23:19 | command1 indirection |
| test.cpp:22:45:22:52 | userName indirection | test.cpp:22:13:22:20 | sprintf output argument |
| test.cpp:22:45:22:52 | userName indirection | test.cpp:22:13:22:20 | sprintf output argument |
| test.cpp:47:21:47:26 | call to getenv | test.cpp:50:35:50:43 | envCflags indirection |
| test.cpp:50:11:50:17 | sprintf output argument | test.cpp:51:10:51:16 | command indirection |
| test.cpp:50:35:50:43 | envCflags indirection | test.cpp:50:11:50:17 | sprintf output argument |
| test.cpp:50:35:50:43 | envCflags indirection | test.cpp:50:11:50:17 | sprintf output argument |
| test.cpp:62:9:62:16 | fread output argument | test.cpp:64:20:64:27 | filename indirection |
| test.cpp:64:11:64:17 | strncat output argument | test.cpp:65:10:65:16 | command indirection |
| test.cpp:64:20:64:27 | filename indirection | test.cpp:64:11:64:17 | strncat output argument |
| test.cpp:64:20:64:27 | filename indirection | test.cpp:64:11:64:17 | strncat output argument |
| test.cpp:82:9:82:16 | fread output argument | test.cpp:84:20:84:27 | filename indirection |
| test.cpp:84:11:84:17 | strncat output argument | test.cpp:85:32:85:38 | command indirection |
| test.cpp:84:20:84:27 | filename indirection | test.cpp:84:11:84:17 | strncat output argument |
| test.cpp:84:20:84:27 | filename indirection | test.cpp:84:11:84:17 | strncat output argument |
| test.cpp:91:9:91:16 | fread output argument | test.cpp:93:17:93:24 | filename indirection |
| test.cpp:93:11:93:14 | strncat output argument | test.cpp:94:45:94:48 | path indirection |
| test.cpp:93:17:93:24 | filename indirection | test.cpp:93:11:93:14 | strncat output argument |
| test.cpp:93:17:93:24 | filename indirection | test.cpp:93:11:93:14 | strncat output argument |
| test.cpp:106:20:106:25 | call to getenv | test.cpp:107:33:107:36 | path indirection |
| test.cpp:107:31:107:31 | call to operator+ | test.cpp:108:18:108:22 | call to c_str indirection |
| test.cpp:107:33:107:36 | path indirection | test.cpp:107:31:107:31 | call to operator+ |
| test.cpp:107:33:107:36 | path indirection | test.cpp:107:31:107:31 | call to operator+ |
| test.cpp:113:20:113:25 | call to getenv | test.cpp:114:19:114:22 | path indirection |
| test.cpp:114:17:114:17 | Call | test.cpp:114:25:114:29 | call to c_str indirection |
| test.cpp:114:19:114:22 | path indirection | test.cpp:114:17:114:17 | Call |
| test.cpp:114:19:114:22 | path indirection | test.cpp:114:17:114:17 | Call |
| test.cpp:119:20:119:25 | call to getenv | test.cpp:120:19:120:22 | path indirection |
| test.cpp:120:17:120:17 | Call | test.cpp:120:10:120:30 | call to data indirection |
| test.cpp:120:19:120:22 | path indirection | test.cpp:120:17:120:17 | Call |
| test.cpp:120:19:120:22 | path indirection | test.cpp:120:17:120:17 | Call |
| test.cpp:140:9:140:11 | fread output argument | test.cpp:142:31:142:33 | str indirection |
| test.cpp:142:11:142:17 | sprintf output argument | test.cpp:143:10:143:16 | command indirection |
| test.cpp:142:31:142:33 | str indirection | test.cpp:142:11:142:17 | sprintf output argument |
| test.cpp:142:31:142:33 | str indirection | test.cpp:142:11:142:17 | sprintf output argument |
| test.cpp:174:9:174:16 | fread output argument | test.cpp:177:20:177:27 | filename indirection |
| test.cpp:174:9:174:16 | fread output argument | test.cpp:178:22:178:26 | flags indirection |
| test.cpp:174:9:174:16 | fread output argument | test.cpp:180:22:180:29 | filename indirection |
| test.cpp:177:13:177:17 | strncat output argument | test.cpp:183:32:183:38 | command indirection |
| test.cpp:177:20:177:27 | filename indirection | test.cpp:177:13:177:17 | strncat output argument |
| test.cpp:178:13:178:19 | strncat output argument | test.cpp:183:32:183:38 | command indirection |
| test.cpp:178:22:178:26 | flags indirection | test.cpp:178:13:178:19 | strncat output argument |
| test.cpp:180:13:180:19 | strncat output argument | test.cpp:183:32:183:38 | command indirection |
| test.cpp:180:22:180:29 | filename indirection | test.cpp:180:13:180:19 | strncat output argument |
| test.cpp:186:47:186:54 | *filename | test.cpp:187:18:187:25 | filename indirection |
| test.cpp:186:47:186:54 | *filename | test.cpp:188:20:188:24 | flags indirection |
| test.cpp:186:47:186:54 | filename | test.cpp:187:18:187:25 | filename indirection |
| test.cpp:186:47:186:54 | filename | test.cpp:188:20:188:24 | flags indirection |
| test.cpp:187:11:187:15 | strncat output argument | test.cpp:188:11:188:17 | command [post update] |
| test.cpp:187:11:187:15 | strncat output argument | test.cpp:188:11:188:17 | command [post update] |
| test.cpp:187:11:187:15 | strncat output argument | test.cpp:188:11:188:17 | command [post update] |
| test.cpp:187:11:187:15 | strncat output argument | test.cpp:188:11:188:17 | command [post update] |
| test.cpp:187:18:187:25 | filename indirection | test.cpp:187:11:187:15 | strncat output argument |
| test.cpp:187:18:187:25 | filename indirection | test.cpp:187:11:187:15 | strncat output argument |
| test.cpp:188:11:188:17 | command [post update] | test.cpp:188:11:188:17 | command [post update] |
| test.cpp:188:11:188:17 | command [post update] | test.cpp:188:11:188:17 | command [post update] |
| test.cpp:188:11:188:17 | command [post update] | test.cpp:188:11:188:17 | command [post update] |
| test.cpp:188:11:188:17 | command [post update] | test.cpp:188:11:188:17 | command [post update] |
| test.cpp:188:11:188:17 | strncat output argument | test.cpp:188:11:188:17 | command [post update] |
| test.cpp:188:11:188:17 | strncat output argument | test.cpp:188:11:188:17 | command [post update] |
| test.cpp:188:11:188:17 | strncat output argument | test.cpp:188:11:188:17 | command [post update] |
| test.cpp:188:11:188:17 | strncat output argument | test.cpp:188:11:188:17 | command [post update] |
| test.cpp:188:20:188:24 | flags indirection | test.cpp:188:11:188:17 | strncat output argument |
| test.cpp:188:20:188:24 | flags indirection | test.cpp:188:11:188:17 | strncat output argument |
| test.cpp:194:9:194:16 | fread output argument | test.cpp:196:26:196:33 | filename |
| test.cpp:194:9:194:16 | fread output argument | test.cpp:196:26:196:33 | filename indirection |
| test.cpp:196:10:196:16 | command [post update] | test.cpp:198:32:198:38 | command indirection |
| test.cpp:196:10:196:16 | command [post update] | test.cpp:198:32:198:38 | command indirection |
| test.cpp:196:26:196:33 | filename | test.cpp:186:47:186:54 | filename |
| test.cpp:196:26:196:33 | filename | test.cpp:196:10:196:16 | command [post update] |
| test.cpp:196:26:196:33 | filename | test.cpp:196:10:196:16 | command [post update] |
| test.cpp:196:26:196:33 | filename indirection | test.cpp:186:47:186:54 | *filename |
| test.cpp:196:26:196:33 | filename indirection | test.cpp:196:10:196:16 | command [post update] |
| test.cpp:196:26:196:33 | filename indirection | test.cpp:196:10:196:16 | command [post update] |
| test.cpp:218:9:218:16 | fread output argument | test.cpp:220:19:220:26 | filename indirection |
| test.cpp:218:9:218:16 | fread output argument | test.cpp:220:19:220:26 | filename indirection |
| test.cpp:220:10:220:16 | strncat output argument | test.cpp:222:32:222:38 | command indirection |
| test.cpp:220:10:220:16 | strncat output argument | test.cpp:222:32:222:38 | command indirection |
| test.cpp:220:19:220:26 | filename indirection | test.cpp:220:10:220:16 | strncat output argument |
| test.cpp:220:19:220:26 | filename indirection | test.cpp:220:10:220:16 | strncat output argument |
| test.cpp:220:19:220:26 | filename indirection | test.cpp:220:10:220:16 | strncat output argument |
| test.cpp:220:19:220:26 | filename indirection | test.cpp:220:10:220:16 | strncat output argument |
nodes
| test.cpp:16:20:16:23 | argv | semmle.label | argv |
| test.cpp:22:13:22:20 | sprintf output argument | semmle.label | sprintf output argument |
@@ -72,7 +110,56 @@ nodes
| test.cpp:142:11:142:17 | sprintf output argument | semmle.label | sprintf output argument |
| test.cpp:142:31:142:33 | str indirection | semmle.label | str indirection |
| test.cpp:143:10:143:16 | command indirection | semmle.label | command indirection |
| test.cpp:174:9:174:16 | fread output argument | semmle.label | fread output argument |
| test.cpp:177:13:177:17 | strncat output argument | semmle.label | strncat output argument |
| test.cpp:177:20:177:27 | filename indirection | semmle.label | filename indirection |
| test.cpp:178:13:178:19 | strncat output argument | semmle.label | strncat output argument |
| test.cpp:178:22:178:26 | flags indirection | semmle.label | flags indirection |
| test.cpp:180:13:180:19 | strncat output argument | semmle.label | strncat output argument |
| test.cpp:180:22:180:29 | filename indirection | semmle.label | filename indirection |
| test.cpp:183:32:183:38 | command indirection | semmle.label | command indirection |
| test.cpp:183:32:183:38 | command indirection | semmle.label | command indirection |
| test.cpp:183:32:183:38 | command indirection | semmle.label | command indirection |
| test.cpp:186:47:186:54 | *filename | semmle.label | *filename |
| test.cpp:186:47:186:54 | filename | semmle.label | filename |
| test.cpp:187:11:187:15 | strncat output argument | semmle.label | strncat output argument |
| test.cpp:187:11:187:15 | strncat output argument | semmle.label | strncat output argument |
| test.cpp:187:18:187:25 | filename indirection | semmle.label | filename indirection |
| test.cpp:187:18:187:25 | filename indirection | semmle.label | filename indirection |
| test.cpp:188:11:188:17 | command [post update] | semmle.label | command [post update] |
| test.cpp:188:11:188:17 | command [post update] | semmle.label | command [post update] |
| test.cpp:188:11:188:17 | command [post update] | semmle.label | command [post update] |
| test.cpp:188:11:188:17 | command [post update] | semmle.label | command [post update] |
| test.cpp:188:11:188:17 | command [post update] | semmle.label | command [post update] |
| test.cpp:188:11:188:17 | command [post update] | semmle.label | command [post update] |
| test.cpp:188:11:188:17 | command [post update] | semmle.label | command [post update] |
| test.cpp:188:11:188:17 | command [post update] | semmle.label | command [post update] |
| test.cpp:188:11:188:17 | strncat output argument | semmle.label | strncat output argument |
| test.cpp:188:11:188:17 | strncat output argument | semmle.label | strncat output argument |
| test.cpp:188:20:188:24 | flags indirection | semmle.label | flags indirection |
| test.cpp:188:20:188:24 | flags indirection | semmle.label | flags indirection |
| test.cpp:194:9:194:16 | fread output argument | semmle.label | fread output argument |
| test.cpp:196:10:196:16 | command [post update] | semmle.label | command [post update] |
| test.cpp:196:10:196:16 | command [post update] | semmle.label | command [post update] |
| test.cpp:196:26:196:33 | filename | semmle.label | filename |
| test.cpp:196:26:196:33 | filename indirection | semmle.label | filename indirection |
| test.cpp:198:32:198:38 | command indirection | semmle.label | command indirection |
| test.cpp:198:32:198:38 | command indirection | semmle.label | command indirection |
| test.cpp:218:9:218:16 | fread output argument | semmle.label | fread output argument |
| test.cpp:220:10:220:16 | strncat output argument | semmle.label | strncat output argument |
| test.cpp:220:10:220:16 | strncat output argument | semmle.label | strncat output argument |
| test.cpp:220:19:220:26 | filename indirection | semmle.label | filename indirection |
| test.cpp:220:19:220:26 | filename indirection | semmle.label | filename indirection |
| test.cpp:222:32:222:38 | command indirection | semmle.label | command indirection |
subpaths
| test.cpp:196:26:196:33 | filename | test.cpp:186:47:186:54 | filename | test.cpp:188:11:188:17 | command [post update] | test.cpp:196:10:196:16 | command [post update] |
| test.cpp:196:26:196:33 | filename | test.cpp:186:47:186:54 | filename | test.cpp:188:11:188:17 | command [post update] | test.cpp:196:10:196:16 | command [post update] |
| test.cpp:196:26:196:33 | filename | test.cpp:186:47:186:54 | filename | test.cpp:188:11:188:17 | command [post update] | test.cpp:196:10:196:16 | command [post update] |
| test.cpp:196:26:196:33 | filename | test.cpp:186:47:186:54 | filename | test.cpp:188:11:188:17 | command [post update] | test.cpp:196:10:196:16 | command [post update] |
| test.cpp:196:26:196:33 | filename indirection | test.cpp:186:47:186:54 | *filename | test.cpp:188:11:188:17 | command [post update] | test.cpp:196:10:196:16 | command [post update] |
| test.cpp:196:26:196:33 | filename indirection | test.cpp:186:47:186:54 | *filename | test.cpp:188:11:188:17 | command [post update] | test.cpp:196:10:196:16 | command [post update] |
| test.cpp:196:26:196:33 | filename indirection | test.cpp:186:47:186:54 | *filename | test.cpp:188:11:188:17 | command [post update] | test.cpp:196:10:196:16 | command [post update] |
| test.cpp:196:26:196:33 | filename indirection | test.cpp:186:47:186:54 | *filename | test.cpp:188:11:188:17 | command [post update] | test.cpp:196:10:196:16 | command [post update] |
#select
| test.cpp:23:12:23:19 | command1 | test.cpp:16:20:16:23 | argv | test.cpp:23:12:23:19 | command1 indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string) | test.cpp:16:20:16:23 | argv | user input (a command-line argument) | test.cpp:22:13:22:20 | sprintf output argument | sprintf output argument |
| test.cpp:51:10:51:16 | command | test.cpp:47:21:47:26 | call to getenv | test.cpp:51:10:51:16 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string) | test.cpp:47:21:47:26 | call to getenv | user input (an environment variable) | test.cpp:50:11:50:17 | sprintf output argument | sprintf output argument |
@@ -83,3 +170,10 @@ subpaths
| test.cpp:114:25:114:29 | call to c_str | test.cpp:113:20:113:25 | call to getenv | test.cpp:114:25:114:29 | call to c_str indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string) | test.cpp:113:20:113:25 | call to getenv | user input (an environment variable) | test.cpp:114:17:114:17 | Call | Call |
| test.cpp:120:25:120:28 | call to data | test.cpp:119:20:119:25 | call to getenv | test.cpp:120:10:120:30 | call to data indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string) | test.cpp:119:20:119:25 | call to getenv | user input (an environment variable) | test.cpp:120:17:120:17 | Call | Call |
| test.cpp:143:10:143:16 | command | test.cpp:140:9:140:11 | fread output argument | test.cpp:143:10:143:16 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to system(string) | test.cpp:140:9:140:11 | fread output argument | user input (String read by fread) | test.cpp:142:11:142:17 | sprintf output argument | sprintf output argument |
| test.cpp:183:32:183:38 | command | test.cpp:174:9:174:16 | fread output argument | test.cpp:183:32:183:38 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to execl | test.cpp:174:9:174:16 | fread output argument | user input (String read by fread) | test.cpp:177:13:177:17 | strncat output argument | strncat output argument |
| test.cpp:183:32:183:38 | command | test.cpp:174:9:174:16 | fread output argument | test.cpp:183:32:183:38 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to execl | test.cpp:174:9:174:16 | fread output argument | user input (String read by fread) | test.cpp:178:13:178:19 | strncat output argument | strncat output argument |
| test.cpp:183:32:183:38 | command | test.cpp:174:9:174:16 | fread output argument | test.cpp:183:32:183:38 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to execl | test.cpp:174:9:174:16 | fread output argument | user input (String read by fread) | test.cpp:180:13:180:19 | strncat output argument | strncat output argument |
| test.cpp:198:32:198:38 | command | test.cpp:194:9:194:16 | fread output argument | test.cpp:198:32:198:38 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to execl | test.cpp:194:9:194:16 | fread output argument | user input (String read by fread) | test.cpp:187:11:187:15 | strncat output argument | strncat output argument |
| test.cpp:198:32:198:38 | command | test.cpp:194:9:194:16 | fread output argument | test.cpp:198:32:198:38 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to execl | test.cpp:194:9:194:16 | fread output argument | user input (String read by fread) | test.cpp:188:11:188:17 | strncat output argument | strncat output argument |
| test.cpp:222:32:222:38 | command | test.cpp:218:9:218:16 | fread output argument | test.cpp:222:32:222:38 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to execl | test.cpp:218:9:218:16 | fread output argument | user input (String read by fread) | test.cpp:220:10:220:16 | strncat output argument | strncat output argument |
| test.cpp:222:32:222:38 | command | test.cpp:218:9:218:16 | fread output argument | test.cpp:222:32:222:38 | command indirection | This argument to an OS command is derived from $@, dangerously concatenated into $@, and then passed to execl | test.cpp:218:9:218:16 | fread output argument | user input (String read by fread) | test.cpp:220:10:220:16 | strncat output argument | strncat output argument |

View File

@@ -168,7 +168,58 @@ void test15(FILE *f) {
system(command); // GOOD: the user string was converted to an integer and back
}
void test16(FILE *f, bool use_flags) {
// BAD: the user string is injected directly into a command
char command[1000] = "mv ", flags[1000] = "-R", filename[1000];
fread(filename, 1, 1000, f);
// TODO: test for call context sensitivity at concatenation site
if (use_flags) {
strncat(flags, filename, 1000);
strncat(command, flags, 1000);
} else {
strncat(command, filename, 1000);
}
execl("/bin/sh", "sh", "-c", command);
}
void concat(char *command, char *flags, char *filename) {
strncat(flags, filename, 1000);
strncat(command, flags, 1000);
}
void test17(FILE *f) {
// BAD: the user string is injected directly into a command
char command[1000] = "mv ", flags[1000] = "-R", filename[1000];
fread(filename, 1, 1000, f);
concat(command, flags, filename);
execl("/bin/sh", "sh", "-c", command);
}
void test18() {
// GOOD
char command[1000] = "ls ", flags[1000] = "-l", filename[1000] = ".";
concat(command, flags, filename);
execl("/bin/sh", "sh", "-c", command);
}
#define CONCAT(COMMAND, FILENAME) \
strncat(COMMAND, FILENAME, 1000); \
strncat(COMMAND, " ", 1000); \
strncat(COMMAND, FILENAME, 1000);
void test19(FILE *f) {
// BAD: the user string is injected directly into a command
char command[1000] = "mv ", filename[1000];
fread(filename, 1, 1000, f);
CONCAT(command, filename)
execl("/bin/sh", "sh", "-c", command);
}
// open question: do we want to report certain sources even when they're the start of the string?

View File

@@ -0,0 +1,8 @@
edges
| tests.c:57:21:57:28 | password | tests.c:70:70:70:77 | array to pointer conversion |
nodes
| tests.c:57:21:57:28 | password | semmle.label | password |
| tests.c:70:70:70:77 | array to pointer conversion | semmle.label | array to pointer conversion |
subpaths
#select
| tests.c:70:70:70:77 | array to pointer conversion | tests.c:57:21:57:28 | password | tests.c:70:70:70:77 | array to pointer conversion | This operation potentially exposes sensitive system data from $@. | tests.c:57:21:57:28 | password | password |

View File

@@ -0,0 +1 @@
Security/CWE/CWE-497/PotentiallyExposedSystemData.ql

View File

@@ -67,6 +67,6 @@ void CWE535_Info_Exposure_Shell_Error__w32_char_01_bad()
printLine("Unable to login.");
}
/* FLAW: Write sensitive data to stderr */
fprintf(stderr, "User attempted access with password: %s\n", password); // [NOT DETECTED]
fprintf(stderr, "User attempted access with password: %s\n", password);
}
}

View File

@@ -2,15 +2,26 @@ edges
| tests2.cpp:63:13:63:18 | call to getenv | tests2.cpp:63:13:63:26 | (const char *)... |
| tests2.cpp:64:13:64:18 | call to getenv | tests2.cpp:64:13:64:26 | (const char *)... |
| tests2.cpp:65:13:65:18 | call to getenv | tests2.cpp:65:13:65:30 | (const char *)... |
| tests2.cpp:76:18:76:38 | call to mysql_get_client_info | tests2.cpp:79:14:79:19 | (const char *)... |
| tests2.cpp:78:14:78:34 | call to mysql_get_client_info | tests2.cpp:78:14:78:34 | call to mysql_get_client_info |
| tests2.cpp:78:14:78:34 | call to mysql_get_client_info | tests2.cpp:78:14:78:34 | call to mysql_get_client_info |
| tests2.cpp:89:42:89:45 | str1 | tests2.cpp:91:14:91:17 | str1 |
| tests2.cpp:99:8:99:15 | call to getpwuid | tests2.cpp:100:14:100:15 | pw |
| tests2.cpp:107:3:107:4 | c1 [post update] [ptr] | tests2.cpp:109:14:109:15 | c1 [read] [ptr] |
| tests2.cpp:107:6:107:8 | ptr [post update] | tests2.cpp:107:3:107:4 | c1 [post update] [ptr] |
| tests2.cpp:107:12:107:17 | call to getenv | tests2.cpp:107:6:107:8 | ptr [post update] |
| tests2.cpp:109:14:109:15 | c1 [read] [ptr] | tests2.cpp:109:14:109:19 | (const char *)... |
| tests2.cpp:66:13:66:18 | call to getenv | tests2.cpp:66:13:66:34 | (const char *)... |
| tests2.cpp:78:18:78:38 | call to mysql_get_client_info | tests2.cpp:81:14:81:19 | (const char *)... |
| tests2.cpp:80:14:80:34 | call to mysql_get_client_info | tests2.cpp:80:14:80:34 | call to mysql_get_client_info |
| tests2.cpp:80:14:80:34 | call to mysql_get_client_info | tests2.cpp:80:14:80:34 | call to mysql_get_client_info |
| tests2.cpp:91:42:91:45 | str1 | tests2.cpp:93:14:93:17 | str1 |
| tests2.cpp:101:8:101:15 | call to getpwuid | tests2.cpp:102:14:102:15 | pw |
| tests2.cpp:109:3:109:4 | c1 [post update] [ptr] | tests2.cpp:111:14:111:15 | c1 [read] [ptr] |
| tests2.cpp:109:6:109:8 | ptr [post update] | tests2.cpp:109:3:109:4 | c1 [post update] [ptr] |
| tests2.cpp:109:12:109:17 | call to getenv | tests2.cpp:109:6:109:8 | ptr [post update] |
| tests2.cpp:111:14:111:15 | c1 [read] [ptr] | tests2.cpp:111:14:111:19 | (const char *)... |
| tests_sockets.cpp:26:15:26:20 | call to getenv | tests_sockets.cpp:39:19:39:22 | (const void *)... |
| tests_sockets.cpp:26:15:26:20 | call to getenv | tests_sockets.cpp:39:19:39:22 | path |
| tests_sockets.cpp:26:15:26:20 | call to getenv | tests_sockets.cpp:43:20:43:23 | (const void *)... |
| tests_sockets.cpp:26:15:26:20 | call to getenv | tests_sockets.cpp:43:20:43:23 | path |
| tests_sockets.cpp:63:15:63:20 | call to getenv | tests_sockets.cpp:76:19:76:22 | (const void *)... |
| tests_sockets.cpp:63:15:63:20 | call to getenv | tests_sockets.cpp:76:19:76:22 | path |
| tests_sockets.cpp:63:15:63:20 | call to getenv | tests_sockets.cpp:80:20:80:23 | (const void *)... |
| tests_sockets.cpp:63:15:63:20 | call to getenv | tests_sockets.cpp:80:20:80:23 | path |
| tests_sysconf.cpp:36:21:36:27 | confstr output argument | tests_sysconf.cpp:39:19:39:25 | (const void *)... |
| tests_sysconf.cpp:36:21:36:27 | confstr output argument | tests_sysconf.cpp:39:19:39:25 | pathbuf |
nodes
| tests2.cpp:63:13:63:18 | call to getenv | semmle.label | call to getenv |
| tests2.cpp:63:13:63:18 | call to getenv | semmle.label | call to getenv |
@@ -21,27 +32,49 @@ nodes
| tests2.cpp:65:13:65:18 | call to getenv | semmle.label | call to getenv |
| tests2.cpp:65:13:65:18 | call to getenv | semmle.label | call to getenv |
| tests2.cpp:65:13:65:30 | (const char *)... | semmle.label | (const char *)... |
| tests2.cpp:76:18:76:38 | call to mysql_get_client_info | semmle.label | call to mysql_get_client_info |
| tests2.cpp:78:14:78:34 | call to mysql_get_client_info | semmle.label | call to mysql_get_client_info |
| tests2.cpp:78:14:78:34 | call to mysql_get_client_info | semmle.label | call to mysql_get_client_info |
| tests2.cpp:79:14:79:19 | (const char *)... | semmle.label | (const char *)... |
| tests2.cpp:89:42:89:45 | str1 | semmle.label | str1 |
| tests2.cpp:91:14:91:17 | str1 | semmle.label | str1 |
| tests2.cpp:99:8:99:15 | call to getpwuid | semmle.label | call to getpwuid |
| tests2.cpp:100:14:100:15 | pw | semmle.label | pw |
| tests2.cpp:107:3:107:4 | c1 [post update] [ptr] | semmle.label | c1 [post update] [ptr] |
| tests2.cpp:107:6:107:8 | ptr [post update] | semmle.label | ptr [post update] |
| tests2.cpp:107:12:107:17 | call to getenv | semmle.label | call to getenv |
| tests2.cpp:109:14:109:15 | c1 [read] [ptr] | semmle.label | c1 [read] [ptr] |
| tests2.cpp:109:14:109:19 | (const char *)... | semmle.label | (const char *)... |
| tests2.cpp:66:13:66:18 | call to getenv | semmle.label | call to getenv |
| tests2.cpp:66:13:66:18 | call to getenv | semmle.label | call to getenv |
| tests2.cpp:66:13:66:34 | (const char *)... | semmle.label | (const char *)... |
| tests2.cpp:78:18:78:38 | call to mysql_get_client_info | semmle.label | call to mysql_get_client_info |
| tests2.cpp:80:14:80:34 | call to mysql_get_client_info | semmle.label | call to mysql_get_client_info |
| tests2.cpp:80:14:80:34 | call to mysql_get_client_info | semmle.label | call to mysql_get_client_info |
| tests2.cpp:81:14:81:19 | (const char *)... | semmle.label | (const char *)... |
| tests2.cpp:91:42:91:45 | str1 | semmle.label | str1 |
| tests2.cpp:93:14:93:17 | str1 | semmle.label | str1 |
| tests2.cpp:101:8:101:15 | call to getpwuid | semmle.label | call to getpwuid |
| tests2.cpp:102:14:102:15 | pw | semmle.label | pw |
| tests2.cpp:109:3:109:4 | c1 [post update] [ptr] | semmle.label | c1 [post update] [ptr] |
| tests2.cpp:109:6:109:8 | ptr [post update] | semmle.label | ptr [post update] |
| tests2.cpp:109:12:109:17 | call to getenv | semmle.label | call to getenv |
| tests2.cpp:111:14:111:15 | c1 [read] [ptr] | semmle.label | c1 [read] [ptr] |
| tests2.cpp:111:14:111:19 | (const char *)... | semmle.label | (const char *)... |
| tests_sockets.cpp:26:15:26:20 | call to getenv | semmle.label | call to getenv |
| tests_sockets.cpp:39:19:39:22 | (const void *)... | semmle.label | (const void *)... |
| tests_sockets.cpp:39:19:39:22 | path | semmle.label | path |
| tests_sockets.cpp:43:20:43:23 | (const void *)... | semmle.label | (const void *)... |
| tests_sockets.cpp:43:20:43:23 | path | semmle.label | path |
| tests_sockets.cpp:63:15:63:20 | call to getenv | semmle.label | call to getenv |
| tests_sockets.cpp:76:19:76:22 | (const void *)... | semmle.label | (const void *)... |
| tests_sockets.cpp:76:19:76:22 | path | semmle.label | path |
| tests_sockets.cpp:80:20:80:23 | (const void *)... | semmle.label | (const void *)... |
| tests_sockets.cpp:80:20:80:23 | path | semmle.label | path |
| tests_sysconf.cpp:36:21:36:27 | confstr output argument | semmle.label | confstr output argument |
| tests_sysconf.cpp:39:19:39:25 | (const void *)... | semmle.label | (const void *)... |
| tests_sysconf.cpp:39:19:39:25 | pathbuf | semmle.label | pathbuf |
subpaths
#select
| tests2.cpp:63:13:63:18 | call to getenv | tests2.cpp:63:13:63:18 | call to getenv | tests2.cpp:63:13:63:18 | call to getenv | This operation exposes system data from $@. | tests2.cpp:63:13:63:18 | call to getenv | call to getenv |
| tests2.cpp:64:13:64:18 | call to getenv | tests2.cpp:64:13:64:18 | call to getenv | tests2.cpp:64:13:64:18 | call to getenv | This operation exposes system data from $@. | tests2.cpp:64:13:64:18 | call to getenv | call to getenv |
| tests2.cpp:65:13:65:18 | call to getenv | tests2.cpp:65:13:65:18 | call to getenv | tests2.cpp:65:13:65:18 | call to getenv | This operation exposes system data from $@. | tests2.cpp:65:13:65:18 | call to getenv | call to getenv |
| tests2.cpp:78:14:78:34 | call to mysql_get_client_info | tests2.cpp:78:14:78:34 | call to mysql_get_client_info | tests2.cpp:78:14:78:34 | call to mysql_get_client_info | This operation exposes system data from $@. | tests2.cpp:78:14:78:34 | call to mysql_get_client_info | call to mysql_get_client_info |
| tests2.cpp:78:14:78:34 | call to mysql_get_client_info | tests2.cpp:78:14:78:34 | call to mysql_get_client_info | tests2.cpp:78:14:78:34 | call to mysql_get_client_info | This operation exposes system data from $@. | tests2.cpp:78:14:78:34 | call to mysql_get_client_info | call to mysql_get_client_info |
| tests2.cpp:79:14:79:19 | (const char *)... | tests2.cpp:76:18:76:38 | call to mysql_get_client_info | tests2.cpp:79:14:79:19 | (const char *)... | This operation exposes system data from $@. | tests2.cpp:76:18:76:38 | call to mysql_get_client_info | call to mysql_get_client_info |
| tests2.cpp:91:14:91:17 | str1 | tests2.cpp:89:42:89:45 | str1 | tests2.cpp:91:14:91:17 | str1 | This operation exposes system data from $@. | tests2.cpp:89:42:89:45 | str1 | str1 |
| tests2.cpp:100:14:100:15 | pw | tests2.cpp:99:8:99:15 | call to getpwuid | tests2.cpp:100:14:100:15 | pw | This operation exposes system data from $@. | tests2.cpp:99:8:99:15 | call to getpwuid | call to getpwuid |
| tests2.cpp:109:14:109:19 | (const char *)... | tests2.cpp:107:12:107:17 | call to getenv | tests2.cpp:109:14:109:19 | (const char *)... | This operation exposes system data from $@. | tests2.cpp:107:12:107:17 | call to getenv | call to getenv |
| tests2.cpp:66:13:66:18 | call to getenv | tests2.cpp:66:13:66:18 | call to getenv | tests2.cpp:66:13:66:18 | call to getenv | This operation exposes system data from $@. | tests2.cpp:66:13:66:18 | call to getenv | call to getenv |
| tests2.cpp:80:14:80:34 | call to mysql_get_client_info | tests2.cpp:80:14:80:34 | call to mysql_get_client_info | tests2.cpp:80:14:80:34 | call to mysql_get_client_info | This operation exposes system data from $@. | tests2.cpp:80:14:80:34 | call to mysql_get_client_info | call to mysql_get_client_info |
| tests2.cpp:80:14:80:34 | call to mysql_get_client_info | tests2.cpp:80:14:80:34 | call to mysql_get_client_info | tests2.cpp:80:14:80:34 | call to mysql_get_client_info | This operation exposes system data from $@. | tests2.cpp:80:14:80:34 | call to mysql_get_client_info | call to mysql_get_client_info |
| tests2.cpp:81:14:81:19 | (const char *)... | tests2.cpp:78:18:78:38 | call to mysql_get_client_info | tests2.cpp:81:14:81:19 | (const char *)... | This operation exposes system data from $@. | tests2.cpp:78:18:78:38 | call to mysql_get_client_info | call to mysql_get_client_info |
| tests2.cpp:93:14:93:17 | str1 | tests2.cpp:91:42:91:45 | str1 | tests2.cpp:93:14:93:17 | str1 | This operation exposes system data from $@. | tests2.cpp:91:42:91:45 | str1 | str1 |
| tests2.cpp:102:14:102:15 | pw | tests2.cpp:101:8:101:15 | call to getpwuid | tests2.cpp:102:14:102:15 | pw | This operation exposes system data from $@. | tests2.cpp:101:8:101:15 | call to getpwuid | call to getpwuid |
| tests2.cpp:111:14:111:19 | (const char *)... | tests2.cpp:109:12:109:17 | call to getenv | tests2.cpp:111:14:111:19 | (const char *)... | This operation exposes system data from $@. | tests2.cpp:109:12:109:17 | call to getenv | call to getenv |
| tests_sockets.cpp:39:19:39:22 | path | tests_sockets.cpp:26:15:26:20 | call to getenv | tests_sockets.cpp:39:19:39:22 | path | This operation exposes system data from $@. | tests_sockets.cpp:26:15:26:20 | call to getenv | call to getenv |
| tests_sockets.cpp:43:20:43:23 | path | tests_sockets.cpp:26:15:26:20 | call to getenv | tests_sockets.cpp:43:20:43:23 | path | This operation exposes system data from $@. | tests_sockets.cpp:26:15:26:20 | call to getenv | call to getenv |
| tests_sockets.cpp:76:19:76:22 | path | tests_sockets.cpp:63:15:63:20 | call to getenv | tests_sockets.cpp:76:19:76:22 | path | This operation exposes system data from $@. | tests_sockets.cpp:63:15:63:20 | call to getenv | call to getenv |
| tests_sockets.cpp:80:20:80:23 | path | tests_sockets.cpp:63:15:63:20 | call to getenv | tests_sockets.cpp:80:20:80:23 | path | This operation exposes system data from $@. | tests_sockets.cpp:63:15:63:20 | call to getenv | call to getenv |
| tests_sysconf.cpp:39:19:39:25 | pathbuf | tests_sysconf.cpp:36:21:36:27 | confstr output argument | tests_sysconf.cpp:39:19:39:25 | pathbuf | This operation exposes system data from $@. | tests_sysconf.cpp:36:21:36:27 | confstr output argument | confstr output argument |

View File

@@ -0,0 +1,109 @@
edges
| tests.cpp:48:15:48:20 | call to getenv | tests.cpp:48:15:48:36 | (const char *)... |
| tests.cpp:49:15:49:20 | call to getenv | tests.cpp:49:15:49:36 | (const char *)... |
| tests.cpp:50:15:50:20 | call to getenv | tests.cpp:50:15:50:36 | (const char *)... |
| tests.cpp:57:18:57:23 | call to getenv | tests.cpp:57:18:57:39 | (const char_type *)... |
| tests.cpp:58:41:58:46 | call to getenv | tests.cpp:58:41:58:62 | (const char_type *)... |
| tests.cpp:59:43:59:48 | call to getenv | tests.cpp:59:43:59:64 | (const char *)... |
| tests.cpp:86:29:86:31 | *msg | tests.cpp:88:15:88:17 | msg |
| tests.cpp:86:29:86:31 | msg | tests.cpp:88:15:88:17 | msg |
| tests.cpp:97:13:97:18 | call to getenv | tests.cpp:97:13:97:34 | (const char *)... |
| tests.cpp:97:13:97:18 | call to getenv | tests.cpp:97:13:97:34 | call to getenv |
| tests.cpp:97:13:97:18 | call to getenv | tests.cpp:97:13:97:34 | call to getenv indirection |
| tests.cpp:97:13:97:34 | call to getenv | tests.cpp:86:29:86:31 | msg |
| tests.cpp:97:13:97:34 | call to getenv indirection | tests.cpp:86:29:86:31 | *msg |
| tests.cpp:107:30:107:32 | *msg | tests.cpp:111:15:111:17 | tmp |
| tests.cpp:107:30:107:32 | msg | tests.cpp:111:15:111:17 | tmp |
| tests.cpp:114:30:114:32 | *msg | tests.cpp:119:7:119:12 | (const char *)... |
| tests.cpp:114:30:114:32 | msg | tests.cpp:119:7:119:12 | (const char *)... |
| tests.cpp:122:30:122:32 | *msg | tests.cpp:124:15:124:17 | msg |
| tests.cpp:122:30:122:32 | msg | tests.cpp:124:15:124:17 | msg |
| tests.cpp:131:14:131:19 | call to getenv | tests.cpp:131:14:131:35 | call to getenv |
| tests.cpp:131:14:131:19 | call to getenv | tests.cpp:131:14:131:35 | call to getenv indirection |
| tests.cpp:131:14:131:35 | call to getenv | tests.cpp:107:30:107:32 | msg |
| tests.cpp:131:14:131:35 | call to getenv indirection | tests.cpp:107:30:107:32 | *msg |
| tests.cpp:132:14:132:19 | call to getenv | tests.cpp:132:14:132:35 | call to getenv |
| tests.cpp:132:14:132:19 | call to getenv | tests.cpp:132:14:132:35 | call to getenv indirection |
| tests.cpp:132:14:132:35 | call to getenv | tests.cpp:114:30:114:32 | msg |
| tests.cpp:132:14:132:35 | call to getenv indirection | tests.cpp:114:30:114:32 | *msg |
| tests.cpp:133:14:133:19 | call to getenv | tests.cpp:133:14:133:35 | (const char *)... |
| tests.cpp:133:14:133:19 | call to getenv | tests.cpp:133:14:133:35 | call to getenv |
| tests.cpp:133:14:133:19 | call to getenv | tests.cpp:133:14:133:35 | call to getenv indirection |
| tests.cpp:133:14:133:35 | call to getenv | tests.cpp:122:30:122:32 | msg |
| tests.cpp:133:14:133:35 | call to getenv indirection | tests.cpp:122:30:122:32 | *msg |
| tests_passwd.cpp:16:8:16:15 | call to getpwnam | tests_passwd.cpp:18:29:18:31 | pwd |
| tests_passwd.cpp:16:8:16:15 | call to getpwnam | tests_passwd.cpp:19:26:19:28 | pwd |
nodes
| tests.cpp:48:15:48:20 | call to getenv | semmle.label | call to getenv |
| tests.cpp:48:15:48:20 | call to getenv | semmle.label | call to getenv |
| tests.cpp:48:15:48:36 | (const char *)... | semmle.label | (const char *)... |
| tests.cpp:49:15:49:20 | call to getenv | semmle.label | call to getenv |
| tests.cpp:49:15:49:20 | call to getenv | semmle.label | call to getenv |
| tests.cpp:49:15:49:36 | (const char *)... | semmle.label | (const char *)... |
| tests.cpp:50:15:50:20 | call to getenv | semmle.label | call to getenv |
| tests.cpp:50:15:50:20 | call to getenv | semmle.label | call to getenv |
| tests.cpp:50:15:50:36 | (const char *)... | semmle.label | (const char *)... |
| tests.cpp:57:18:57:23 | call to getenv | semmle.label | call to getenv |
| tests.cpp:57:18:57:23 | call to getenv | semmle.label | call to getenv |
| tests.cpp:57:18:57:39 | (const char_type *)... | semmle.label | (const char_type *)... |
| tests.cpp:58:41:58:46 | call to getenv | semmle.label | call to getenv |
| tests.cpp:58:41:58:46 | call to getenv | semmle.label | call to getenv |
| tests.cpp:58:41:58:62 | (const char_type *)... | semmle.label | (const char_type *)... |
| tests.cpp:59:43:59:48 | call to getenv | semmle.label | call to getenv |
| tests.cpp:59:43:59:48 | call to getenv | semmle.label | call to getenv |
| tests.cpp:59:43:59:64 | (const char *)... | semmle.label | (const char *)... |
| tests.cpp:86:29:86:31 | *msg | semmle.label | *msg |
| tests.cpp:86:29:86:31 | msg | semmle.label | msg |
| tests.cpp:88:15:88:17 | msg | semmle.label | msg |
| tests.cpp:97:13:97:18 | call to getenv | semmle.label | call to getenv |
| tests.cpp:97:13:97:18 | call to getenv | semmle.label | call to getenv |
| tests.cpp:97:13:97:34 | (const char *)... | semmle.label | (const char *)... |
| tests.cpp:97:13:97:34 | call to getenv | semmle.label | call to getenv |
| tests.cpp:97:13:97:34 | call to getenv indirection | semmle.label | call to getenv indirection |
| tests.cpp:107:30:107:32 | *msg | semmle.label | *msg |
| tests.cpp:107:30:107:32 | msg | semmle.label | msg |
| tests.cpp:111:15:111:17 | tmp | semmle.label | tmp |
| tests.cpp:114:30:114:32 | *msg | semmle.label | *msg |
| tests.cpp:114:30:114:32 | msg | semmle.label | msg |
| tests.cpp:119:7:119:12 | (const char *)... | semmle.label | (const char *)... |
| tests.cpp:122:30:122:32 | *msg | semmle.label | *msg |
| tests.cpp:122:30:122:32 | msg | semmle.label | msg |
| tests.cpp:124:15:124:17 | msg | semmle.label | msg |
| tests.cpp:131:14:131:19 | call to getenv | semmle.label | call to getenv |
| tests.cpp:131:14:131:35 | call to getenv | semmle.label | call to getenv |
| tests.cpp:131:14:131:35 | call to getenv indirection | semmle.label | call to getenv indirection |
| tests.cpp:132:14:132:19 | call to getenv | semmle.label | call to getenv |
| tests.cpp:132:14:132:35 | call to getenv | semmle.label | call to getenv |
| tests.cpp:132:14:132:35 | call to getenv indirection | semmle.label | call to getenv indirection |
| tests.cpp:133:14:133:19 | call to getenv | semmle.label | call to getenv |
| tests.cpp:133:14:133:19 | call to getenv | semmle.label | call to getenv |
| tests.cpp:133:14:133:35 | (const char *)... | semmle.label | (const char *)... |
| tests.cpp:133:14:133:35 | call to getenv | semmle.label | call to getenv |
| tests.cpp:133:14:133:35 | call to getenv indirection | semmle.label | call to getenv indirection |
| tests_passwd.cpp:16:8:16:15 | call to getpwnam | semmle.label | call to getpwnam |
| tests_passwd.cpp:18:29:18:31 | pwd | semmle.label | pwd |
| tests_passwd.cpp:19:26:19:28 | pwd | semmle.label | pwd |
subpaths
#select
| tests.cpp:48:15:48:20 | call to getenv | tests.cpp:48:15:48:20 | call to getenv | tests.cpp:48:15:48:20 | call to getenv | This operation potentially exposes sensitive system data from $@. | tests.cpp:48:15:48:20 | call to getenv | call to getenv |
| tests.cpp:48:15:48:36 | (const char *)... | tests.cpp:48:15:48:20 | call to getenv | tests.cpp:48:15:48:36 | (const char *)... | This operation potentially exposes sensitive system data from $@. | tests.cpp:48:15:48:20 | call to getenv | call to getenv |
| tests.cpp:49:15:49:20 | call to getenv | tests.cpp:49:15:49:20 | call to getenv | tests.cpp:49:15:49:20 | call to getenv | This operation potentially exposes sensitive system data from $@. | tests.cpp:49:15:49:20 | call to getenv | call to getenv |
| tests.cpp:49:15:49:36 | (const char *)... | tests.cpp:49:15:49:20 | call to getenv | tests.cpp:49:15:49:36 | (const char *)... | This operation potentially exposes sensitive system data from $@. | tests.cpp:49:15:49:20 | call to getenv | call to getenv |
| tests.cpp:50:15:50:20 | call to getenv | tests.cpp:50:15:50:20 | call to getenv | tests.cpp:50:15:50:20 | call to getenv | This operation potentially exposes sensitive system data from $@. | tests.cpp:50:15:50:20 | call to getenv | call to getenv |
| tests.cpp:50:15:50:36 | (const char *)... | tests.cpp:50:15:50:20 | call to getenv | tests.cpp:50:15:50:36 | (const char *)... | This operation potentially exposes sensitive system data from $@. | tests.cpp:50:15:50:20 | call to getenv | call to getenv |
| tests.cpp:57:18:57:23 | call to getenv | tests.cpp:57:18:57:23 | call to getenv | tests.cpp:57:18:57:23 | call to getenv | This operation potentially exposes sensitive system data from $@. | tests.cpp:57:18:57:23 | call to getenv | call to getenv |
| tests.cpp:57:18:57:39 | (const char_type *)... | tests.cpp:57:18:57:23 | call to getenv | tests.cpp:57:18:57:39 | (const char_type *)... | This operation potentially exposes sensitive system data from $@. | tests.cpp:57:18:57:23 | call to getenv | call to getenv |
| tests.cpp:58:41:58:46 | call to getenv | tests.cpp:58:41:58:46 | call to getenv | tests.cpp:58:41:58:46 | call to getenv | This operation potentially exposes sensitive system data from $@. | tests.cpp:58:41:58:46 | call to getenv | call to getenv |
| tests.cpp:58:41:58:62 | (const char_type *)... | tests.cpp:58:41:58:46 | call to getenv | tests.cpp:58:41:58:62 | (const char_type *)... | This operation potentially exposes sensitive system data from $@. | tests.cpp:58:41:58:46 | call to getenv | call to getenv |
| tests.cpp:59:43:59:48 | call to getenv | tests.cpp:59:43:59:48 | call to getenv | tests.cpp:59:43:59:48 | call to getenv | This operation potentially exposes sensitive system data from $@. | tests.cpp:59:43:59:48 | call to getenv | call to getenv |
| tests.cpp:59:43:59:64 | (const char *)... | tests.cpp:59:43:59:48 | call to getenv | tests.cpp:59:43:59:64 | (const char *)... | This operation potentially exposes sensitive system data from $@. | tests.cpp:59:43:59:48 | call to getenv | call to getenv |
| tests.cpp:88:15:88:17 | msg | tests.cpp:97:13:97:18 | call to getenv | tests.cpp:88:15:88:17 | msg | This operation potentially exposes sensitive system data from $@. | tests.cpp:97:13:97:18 | call to getenv | call to getenv |
| tests.cpp:97:13:97:18 | call to getenv | tests.cpp:97:13:97:18 | call to getenv | tests.cpp:97:13:97:18 | call to getenv | This operation potentially exposes sensitive system data from $@. | tests.cpp:97:13:97:18 | call to getenv | call to getenv |
| tests.cpp:97:13:97:34 | (const char *)... | tests.cpp:97:13:97:18 | call to getenv | tests.cpp:97:13:97:34 | (const char *)... | This operation potentially exposes sensitive system data from $@. | tests.cpp:97:13:97:18 | call to getenv | call to getenv |
| tests.cpp:111:15:111:17 | tmp | tests.cpp:131:14:131:19 | call to getenv | tests.cpp:111:15:111:17 | tmp | This operation potentially exposes sensitive system data from $@. | tests.cpp:131:14:131:19 | call to getenv | call to getenv |
| tests.cpp:119:7:119:12 | (const char *)... | tests.cpp:132:14:132:19 | call to getenv | tests.cpp:119:7:119:12 | (const char *)... | This operation potentially exposes sensitive system data from $@. | tests.cpp:132:14:132:19 | call to getenv | call to getenv |
| tests.cpp:124:15:124:17 | msg | tests.cpp:133:14:133:19 | call to getenv | tests.cpp:124:15:124:17 | msg | This operation potentially exposes sensitive system data from $@. | tests.cpp:133:14:133:19 | call to getenv | call to getenv |
| tests.cpp:133:14:133:19 | call to getenv | tests.cpp:133:14:133:19 | call to getenv | tests.cpp:133:14:133:19 | call to getenv | This operation potentially exposes sensitive system data from $@. | tests.cpp:133:14:133:19 | call to getenv | call to getenv |
| tests.cpp:133:14:133:35 | (const char *)... | tests.cpp:133:14:133:19 | call to getenv | tests.cpp:133:14:133:35 | (const char *)... | This operation potentially exposes sensitive system data from $@. | tests.cpp:133:14:133:19 | call to getenv | call to getenv |
| tests_passwd.cpp:18:29:18:31 | pwd | tests_passwd.cpp:16:8:16:15 | call to getpwnam | tests_passwd.cpp:18:29:18:31 | pwd | This operation potentially exposes sensitive system data from $@. | tests_passwd.cpp:16:8:16:15 | call to getpwnam | call to getpwnam |
| tests_passwd.cpp:19:26:19:28 | pwd | tests_passwd.cpp:16:8:16:15 | call to getpwnam | tests_passwd.cpp:19:26:19:28 | pwd | This operation potentially exposes sensitive system data from $@. | tests_passwd.cpp:16:8:16:15 | call to getpwnam | call to getpwnam |

View File

@@ -0,0 +1 @@
Security/CWE/CWE-497/PotentiallyExposedSystemData.ql

View File

@@ -0,0 +1,134 @@
// test cases for rule CWE-497
// library functions etc
#include "tests.h"
typedef struct {} FILE;
FILE *stdout;
int puts(const char *s);
int printf(const char *format, ...);
int sprintf(char *s, const char *format, ...);
int snprintf(char *s, size_t n, const char *format, ...);
size_t strlen(const char *s);
char *getenv(const char *name);
extern std::ostream someotherostream;
#define NULL (0)
// test cases
void test1()
{
std::ostream cout_copy = std::cout;
std::cout << getenv("SECRET_TOKEN"); // BAD: outputs SECRET_TOKEN environment variable
std::cerr << getenv("SECRET_TOKEN"); // BAD: outputs SECRET_TOKEN environment variable
std::clog << getenv("SECRET_TOKEN"); // BAD: outputs SECRET_TOKEN environment variable
someotherostream << getenv("SECRET_TOKEN"); // GOOD: not output
cout_copy << getenv("SECRET_TOKEN"); // BAD: outputs SECRET_TOKEN environment variable [NOT DETECTED]
std::cout << getenv("USERPROFILE"); // BAD: outputs PATH environment variable [NOT DETECTED]
std::cout << getenv("PATH"); // BAD: outputs PATH environment variable [NOT DETECTED]
std::cout.write(getenv("SECRET_TOKEN"), strlen(getenv("SECRET_TOKEN"))); // BAD: outputs SECRET_TOKEN environment variable
(std::cout << "SECRET_TOKEN = ").write(getenv("SECRET_TOKEN"), strlen(getenv("SECRET_TOKEN"))); // BAD: outputs SECRET_TOKEN environment variable
std::cout.write("SECRET_TOKEN = ", 7) << getenv("SECRET_TOKEN"); // BAD: outputs SECRET_TOKEN environment variable
}
char *global_token = getenv("SECRET_TOKEN");
char *global_other = "Hello, world!";
void test2(bool cond)
{
char *maybe;
maybe = cond ? global_token : global_other;
printf("token = '%s'\n", global_token); // BAD: outputs SECRET_TOKEN environment variable [NOT DETECTED]
printf("other = '%s'\n", global_other);
printf("maybe = '%s'\n", maybe); // BAD: may output SECRET_TOKEN environment variable [NOT DETECTED]
}
void test3()
{
char *path_string = getenv("PATH");
char buf[4096];
// ...
snprintf(buf, 4096, "invalid path '%s'\n", path_string);
puts(buf); // BAD: outputs PATH environment variable [NOT DETECTED]
}
void myOutputFn(const char *msg)
{
printf("%s", msg);
}
void myOtherFn(const char *msg)
{
}
void test4()
{
myOutputFn(getenv("SECRET_TOKEN")); // BAD: outputs the SECRET_TOKEN environment variable
myOtherFn(getenv("SECRET_TOKEN")); // GOOD: does not output anything.
}
void myOutputFn2(const char *msg)
{
msg = "";
printf("%s", msg);
}
void myOutputFn3(const char *msg)
{
const char *tmp = msg;
printf("%s", tmp);
}
void myOutputFn4(const char *msg)
{
char buffer[4096];
sprintf(buffer, "log: %s\n", msg);
puts(buffer);
}
void myOutputFn5(const char *msg)
{
printf("%s", msg);
msg = "";
}
void test5()
{
myOutputFn2(getenv("SECRET_TOKEN")); // GOOD: myOutputFn2 doesn't actually output the parameter
myOutputFn3(getenv("SECRET_TOKEN")); // BAD: outputs the SECRET_TOKEN environment variable
myOutputFn4(getenv("SECRET_TOKEN")); // BAD: outputs the SECRET_TOKEN environment variable
myOutputFn5(getenv("SECRET_TOKEN")); // BAD: outputs the SECRET_TOKEN environment variable
}

View File

@@ -0,0 +1,25 @@
typedef unsigned long size_t;
namespace std
{
typedef size_t streamsize;
template<class charT> struct char_traits;
template <class charT, class traits = char_traits<charT> >
class basic_ostream /*: virtual public basic_ios<charT,traits> - not needed for this test */ {
public:
typedef charT char_type;
basic_ostream<charT,traits>& write(const char_type* s, streamsize n);
basic_ostream<charT, traits>& operator<<(int n);
};
template<class charT, class traits> basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>&, const charT*);
typedef basic_ostream<char> ostream;
extern ostream cout;
extern ostream cerr;
extern ostream clog;
}

View File

@@ -2,24 +2,24 @@
// library functions etc
#include "tests.h"
char *getenv(const char *name);
char *strcpy(char *s1, const char *s2);
namespace std
{
template<class charT> struct char_traits;
template <class charT, class traits = char_traits<charT> >
class basic_ostream /*: virtual public basic_ios<charT,traits> - not needed for this test */ {
public:
};
template<class charT, class traits> basic_ostream<charT,traits>& operator<<(basic_ostream<charT,traits>&, const charT*);
typedef basic_ostream<char> ostream;
extern ostream cout;
}
int socket(int p1, int p2, int p3);
void send(int sock, const char *buffer, int p3, int p4);
@@ -63,10 +63,12 @@ void test1()
send(sock, getenv("HOME"), val(), val()); // BAD
send(sock, getenv("PATH"), val(), val()); // BAD
send(sock, getenv("USERNAME"), val(), val()); // BAD
send(sock, getenv("APP_PASSWORD"), val(), val()); // BAD
send(sock, getenv("HARMLESS"), val(), val()); // GOOD: harmless information
send(sock, "HOME", val(), val()); // GOOD: not system data
send(sock, "PATH", val(), val()); // GOOD: not system data
send(sock, "USERNAME", val(), val()); // GOOD: not system data
send(sock, "APP_PASSWORD", val(), val()); // GOOD: not system data
send(sock, "HARMLESS", val(), val()); // GOOD: not system data
// tests for `mysql_get_client_info`, including via a global

View File

@@ -0,0 +1,21 @@
int printf(const char *format, ...);
struct passwd {
char *pw_passwd;
char *pw_dir;
// ...
};
struct passwd *getpwnam(const char *name);
void test6(char *username)
{
passwd *pwd;
pwd = getpwnam(username);
printf("pw_passwd = %s\n", pwd->pw_passwd); // BAD
printf("pw_dir = %s\n", pwd->pw_dir); // BAD
printf("sizeof(passwd) = %i\n", sizeof(passwd)); // GOOD
}

View File

@@ -0,0 +1,84 @@
typedef unsigned long size_t;
size_t strlen(const char *s);
char *getenv(const char *name);
#define AF_INET (2)
#define SOCK_STREAM (1)
struct sockaddr {
int sa_family;
// ...
};
int socket(int domain, int type, int protocol);
int connect(int socket, const struct sockaddr *address, size_t address_len);
size_t send(int socket, const void *buffer, size_t length, int flags);
int write(int handle, const void *buffer, size_t length);
void test_sockets1()
{
int sockfd;
sockaddr addr_remote;
char *msg = "Hello, world!";
char *path = getenv("PATH");
// create socket
sockfd = socket(AF_INET, SOCK_STREAM, 0);
if (sockfd < 0) return;
// connect socket to a remote address
addr_remote.sa_family = AF_INET;
// ...
if (connect(sockfd, &addr_remote, sizeof(addr_remote)) != 0) return;
// send something using 'send'
if (send(sockfd, msg, strlen(msg) + 1, 0) < 0) return; // GOOD
if (send(sockfd, path, strlen(path) + 1, 0) < 0) return; // BAD
// send something using 'write'
if (write(sockfd, msg, strlen(msg) + 1) < 0) return; // GOOD
if (write(sockfd, path, strlen(path) + 1) < 0) return; // BAD
// clean up
// ...
}
int mksocket()
{
int fd;
fd = socket(AF_INET, SOCK_STREAM, 0);
return fd;
}
void test_sockets2()
{
int sockfd;
sockaddr addr_remote;
char *msg = "Hello, world!";
char *path = getenv("PATH");
// create socket
sockfd = mksocket();
if (sockfd < 0) return;
// connect socket to a remote address
addr_remote.sa_family = AF_INET;
// ...
if (connect(sockfd, &addr_remote, sizeof(addr_remote)) != 0) return;
// send something using 'send'
if (send(sockfd, msg, strlen(msg) + 1, 0) < 0) return; // GOOD
if (send(sockfd, path, strlen(path) + 1, 0) < 0) return; // BAD
// send something using 'write'
if (write(sockfd, msg, strlen(msg) + 1) < 0) return; // GOOD
if (write(sockfd, path, strlen(path) + 1) < 0) return; // BAD
// clean up
// ...
}

View File

@@ -0,0 +1,41 @@
typedef unsigned long size_t;
typedef signed long ssize_t;
void *malloc(size_t size);
#define NULL (0)
int printf(const char *format, ...);
size_t strlen(const char *s);
int get_fd();
int write(int handle, const void *buffer, size_t length);
long sysconf(int name);
#define _SC_CHILD_MAX (2)
size_t confstr(int name, char *buffer, size_t length);
#define _CS_PATH (1)
void test_sc_1()
{
int value = sysconf(_SC_CHILD_MAX);
printf("_SC_CHILD_MAX = %i\n", _SC_CHILD_MAX); // GOOD
printf("_SC_CHILD_MAX = %i\n", value); // BAD [NOT DETECTED]
}
void test_sc_2()
{
char *pathbuf;
size_t n;
n = confstr(_CS_PATH, NULL, (size_t)0);
pathbuf = (char *)malloc(n);
if (pathbuf != NULL)
{
confstr(_CS_PATH, pathbuf, n);
printf("path: %s", pathbuf); // BAD [NOT DETECTED]
write(get_fd(), pathbuf, strlen(pathbuf)); // BAD
}
}

View File

@@ -0,0 +1,4 @@
---
category: feature
---
* The data flow and taint tracking libraries have been extended with versions of `isBarrierIn`, `isBarrierOut`, and `isBarrierGuard`, respectively `isSanitizerIn`, `isSanitizerOut`, and `isSanitizerGuard`, that support flow states.

View File

@@ -1,6 +1,7 @@
/** Provides classes for collections. */
import csharp
import semmle.code.csharp.frameworks.system.Collections
private string modifyMethodName() {
result =
@@ -66,6 +67,12 @@ class CollectionType extends RefType {
}
}
/** Holds if `t` is a collection type. */
predicate isCollectionType(ValueOrRefType t) {
t.getABaseType*() instanceof SystemCollectionsIEnumerableInterface and
not t instanceof StringType
}
/** An object creation that creates an empty collection. */
class EmptyCollectionCreation extends ObjectCreation {
EmptyCollectionCreation() {

View File

@@ -105,31 +105,12 @@ private module ConstantComparisonOperation {
}
}
private class StructuralComparisonConfig extends StructuralComparison::StructuralComparisonConfiguration {
StructuralComparisonConfig() { this = "CompareIdenticalValues" }
override predicate candidate(ControlFlowElement x, ControlFlowElement y) {
exists(ComparisonTest ct |
x = ct.getFirstArgument() and
y = ct.getSecondArgument()
)
}
ComparisonTest getComparisonTest() {
exists(Element x, Element y |
result.getFirstArgument() = x and
result.getSecondArgument() = y and
same(x, y)
)
}
}
/**
* Holds if comparison test `ct` compares two structurally identical
* expressions.
*/
predicate comparesIdenticalValues(ComparisonTest ct) {
ct = any(StructuralComparisonConfig c).getComparisonTest()
StructuralComparison::sameGvn(ct.getFirstArgument(), ct.getSecondArgument())
}
/**

View File

@@ -192,13 +192,18 @@ private import Cached
predicate toGvn = toGvnCached/1;
/**
* Holds if the control flow elements `x` and `y` are structurally equal.
*/
pragma[inline]
private predicate sameGvn(ControlFlowElement x, ControlFlowElement y) {
predicate sameGvn(ControlFlowElement x, ControlFlowElement y) {
pragma[only_bind_into](toGvn(pragma[only_bind_out](x))) =
pragma[only_bind_into](toGvn(pragma[only_bind_out](y)))
}
/**
* DEPRECATED: Use `sameGvn` instead.
*
* A configuration for performing structural comparisons of program elements
* (expressions and statements).
*
@@ -207,7 +212,7 @@ private predicate sameGvn(ControlFlowElement x, ControlFlowElement y) {
*
* Each use of the library is identified by a unique string value.
*/
abstract class StructuralComparisonConfiguration extends string {
abstract deprecated class StructuralComparisonConfiguration extends string {
bindingset[this]
StructuralComparisonConfiguration() { any() }
@@ -235,55 +240,3 @@ abstract class StructuralComparisonConfiguration extends string {
*/
predicate same(ControlFlowElement x, ControlFlowElement y) { candidate(x, y) and sameGvn(x, y) }
}
/**
* INTERNAL: Do not use.
*
* A verbatim copy of the class `StructuralComparisonConfiguration` for internal
* use.
*
* A copy is needed in order to use structural comparison within the standard
* library without running into caching issues.
*/
module Internal {
// Import all uses of the internal library to make sure caching works
private import semmle.code.csharp.controlflow.Guards as G
/**
* A configuration for performing structural comparisons of program elements
* (expressions and statements).
*
* The predicate `candidate()` must be overridden, in order to identify the
* elements for which to perform structural comparison.
*
* Each use of the library is identified by a unique string value.
*/
abstract class InternalStructuralComparisonConfiguration extends string {
bindingset[this]
InternalStructuralComparisonConfiguration() { any() }
/**
* Holds if elements `x` and `y` are candidates for testing structural
* equality.
*
* Subclasses are expected to override this predicate to identify the
* top-level elements which they want to compare. Care should be
* taken to avoid identifying too many pairs of elements, as in general
* there are very many structurally equal subtrees in a program, and
* in order to keep the computation feasible we must focus attention.
*
* Note that this relation is not expected to be symmetric -- it's
* fine to include a pair `(x, y)` but not `(y, x)`.
* In fact, not including the symmetrically implied fact will save
* half the computation time on the structural comparison.
*/
abstract predicate candidate(ControlFlowElement x, ControlFlowElement y);
/**
* Holds if elements `x` and `y` structurally equal. `x` and `y` must be
* flagged as candidates for structural equality, that is,
* `candidate(x, y)` must hold.
*/
predicate same(ControlFlowElement x, ControlFlowElement y) { candidate(x, y) and sameGvn(x, y) }
}
}

View File

@@ -8,7 +8,7 @@ private import dotnet
private import ControlFlow::SuccessorTypes
private import semmle.code.csharp.commons.Assertions
private import semmle.code.csharp.commons.ComparisonTest
private import semmle.code.csharp.commons.StructuralComparison::Internal
private import semmle.code.csharp.commons.StructuralComparison as SC
private import semmle.code.csharp.controlflow.BasicBlocks
private import semmle.code.csharp.controlflow.internal.Completion
private import semmle.code.csharp.frameworks.System
@@ -1798,32 +1798,30 @@ module Internal {
}
/**
* A helper class for calculating structurally equal access/call expressions.
* Holds if access/call expression `e` (targeting declaration `target`)
* is a sub expression of a guard that controls whether basic block
* `bb` is reached.
*/
private class ConditionOnExprComparisonConfig extends InternalStructuralComparisonConfiguration {
ConditionOnExprComparisonConfig() { this = "ConditionOnExprComparisonConfig" }
pragma[noinline]
private predicate candidateAux(AccessOrCallExpr e, Declaration target, BasicBlock bb) {
target = e.getTarget() and
guardControlsSub(_, bb, e)
}
override predicate candidate(ControlFlowElement x, ControlFlowElement y) {
exists(BasicBlock bb, Declaration d |
this.candidateAux(x, d, bb) and
y =
any(AccessOrCallExpr e |
e.getAControlFlowNode().getBasicBlock() = bb and
e.getTarget() = d
)
)
}
private predicate candidate(AccessOrCallExpr x, AccessOrCallExpr y) {
exists(BasicBlock bb, Declaration d |
candidateAux(x, d, bb) and
y =
any(AccessOrCallExpr e |
e.getAControlFlowNode().getBasicBlock() = bb and
e.getTarget() = d
)
)
}
/**
* Holds if access/call expression `e` (targeting declaration `target`)
* is a sub expression of a guard that controls whether basic block
* `bb` is reached.
*/
pragma[noinline]
private predicate candidateAux(AccessOrCallExpr e, Declaration target, BasicBlock bb) {
target = e.getTarget() and
guardControlsSub(_, bb, e)
}
private predicate same(AccessOrCallExpr x, AccessOrCallExpr y) {
candidate(x, y) and
SC::sameGvn(x, y)
}
cached
@@ -1849,7 +1847,7 @@ module Internal {
pragma[nomagic]
private predicate guardControlsSubSame(Guard g, BasicBlock bb, ControlGuardDescendant sub) {
guardControlsSub(g, bb, sub) and
any(ConditionOnExprComparisonConfig c).same(sub, _)
same(sub, _)
}
pragma[nomagic]
@@ -1862,7 +1860,7 @@ module Internal {
guardedBB = guardedCfn.getBasicBlock() and
guardControls(g, guardedBB, v) and
guardControlsSubSame(g, guardedBB, sub) and
any(ConditionOnExprComparisonConfig c).same(sub, guarded)
same(sub, guarded)
}
pragma[nomagic]

View File

@@ -87,12 +87,30 @@ abstract class Configuration extends string {
/** Holds if data flow into `node` is prohibited. */
predicate isBarrierIn(Node node) { none() }
/**
* Holds if data flow into `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierIn(Node node, FlowState state) { none() }
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/**
* Holds if data flow out of `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierOut(Node node, FlowState state) { none() }
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if the additional flow step from `node1` to `node2` must be taken
* into account in the analysis.
@@ -305,7 +323,7 @@ private class RetNodeEx extends NodeEx {
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
}
private predicate inBarrier(NodeEx node, Configuration config) {
private predicate fullInBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n)
@@ -314,7 +332,16 @@ private predicate inBarrier(NodeEx node, Configuration config) {
)
}
private predicate outBarrier(NodeEx node, Configuration config) {
private predicate stateInBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n, state)
|
config.isSource(n, state)
)
}
private predicate fullOutBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n)
@@ -323,6 +350,15 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
private predicate stateOutBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n, state)
|
config.isSink(n, state)
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -345,9 +381,19 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
pragma[nomagic]
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
exists(Node n | node.asNode() = n |
config.isBarrier(n, state)
or
config.isBarrierIn(n, state) and
not config.isSource(n, state)
or
config.isBarrierOut(n, state) and
not config.isSink(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
)
}
@@ -376,8 +422,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
/** Provides the relevant barriers for a step from `node1` to `node2`. */
pragma[inline]
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullOutBarrier(node1, config) and
not fullInBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
@@ -430,6 +476,8 @@ private predicate additionalLocalStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config)
)
@@ -471,6 +519,8 @@ private predicate additionalJumpStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
@@ -870,8 +920,8 @@ private module Stage1 {
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
revFlow(node, true, config) and
fwdFlow(node, true, config) and
not inBarrier(node, config) and
not outBarrier(node, config)
not fullInBarrier(node, config) and
not fullOutBarrier(node, config)
}
/** Holds if flow may return from `callable`. */
@@ -966,8 +1016,8 @@ private predicate flowOutOfCallNodeCand1(
) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and
not inBarrier(out, config)
not fullOutBarrier(ret, config) and
not fullInBarrier(out, config)
}
pragma[nomagic]
@@ -988,8 +1038,8 @@ private predicate flowIntoCallNodeCand1(
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
not outBarrier(arg, config) and
not inBarrier(p, config)
not fullOutBarrier(arg, config) and
not fullInBarrier(p, config)
}
/**
@@ -1706,18 +1756,31 @@ private module LocalFlowBigStep {
* Holds if `node` can be the first node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
private predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
Stage2::revFlow(node, state, config) and
(
sourceNode(node, state, config) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
additionalJumpStateStep(_, _, node, state, config) or
node instanceof ParamNodeEx or
node.asNode() instanceof OutNodeExt or
store(_, _, node, _, config) or
read(_, _, node, config) or
sourceNode(node, state, config)
or
jumpStep(_, node, config)
or
additionalJumpStep(_, node, config)
or
additionalJumpStateStep(_, _, node, state, config)
or
node instanceof ParamNodeEx
or
node.asNode() instanceof OutNodeExt
or
store(_, _, node, _, config)
or
read(_, _, node, config)
or
node instanceof FlowCheckNode
or
exists(FlowState s |
additionalLocalStateStep(_, s, node, state, config) and
s != state
)
)
}
@@ -1737,6 +1800,9 @@ private module LocalFlowBigStep {
or
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
additionalJumpStateStep(node, state, next, s, config)
or
additionalLocalStateStep(node, state, next, s, config) and
s != state
)
or
Stage2::revFlow(node, state, config) and
@@ -1770,42 +1836,40 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
DataFlowType t, Configuration config, LocalCallContext cc
NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t,
Configuration config, LocalCallContext cc
) {
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](state1), pragma[only_bind_into](config)) and
localFlowEntry(node1, pragma[only_bind_into](state), pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
state1 = state2 and
preservesValue = true and
t = node1.getDataFlowType() // irrelevant dummy value
t = node1.getDataFlowType() and // irrelevant dummy value
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
additionalLocalFlowStepNodeCand2(node1, state, node2, state, config) and
preservesValue = false and
t = node2.getDataFlowType()
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall())
or
exists(NodeEx mid |
localFlowStepPlus(node1, state1, mid, pragma[only_bind_into](state2), preservesValue, t,
localFlowStepPlus(node1, pragma[only_bind_into](state), mid, preservesValue, t,
pragma[only_bind_into](config), cc) and
localFlowStepNodeCand1(mid, node2, config) and
not mid instanceof FlowCheckNode and
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
)
or
exists(NodeEx mid, FlowState st |
localFlowStepPlus(node1, state1, mid, st, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, st, node2, state2, config) and
exists(NodeEx mid |
localFlowStepPlus(node1, state, mid, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, state, node2, state, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
t = node2.getDataFlowType() and
Stage2::revFlow(node2, state2, pragma[only_bind_into](config))
t = node2.getDataFlowType()
)
)
}
@@ -1819,9 +1883,19 @@ private module LocalFlowBigStep {
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
) {
localFlowStepPlus(node1, state1, node2, state2, preservesValue, apf.getType(), config,
callContext) and
localFlowExit(node2, state2, config)
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
localFlowExit(node2, state1, config) and
state1 = state2
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and
preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and
callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or
isUnreachableInCallCached(node2.asNode(), call)
)
}
}
@@ -2695,10 +2769,10 @@ private module Stage4 {
bindingset[node, cc, config]
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
localFlowEntry(node, _, config) and
result =
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
node.getEnclosingCallable())
node.getEnclosingCallable()) and
exists(config)
}
private predicate localStep(

View File

@@ -87,12 +87,30 @@ abstract class Configuration extends string {
/** Holds if data flow into `node` is prohibited. */
predicate isBarrierIn(Node node) { none() }
/**
* Holds if data flow into `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierIn(Node node, FlowState state) { none() }
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/**
* Holds if data flow out of `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierOut(Node node, FlowState state) { none() }
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if the additional flow step from `node1` to `node2` must be taken
* into account in the analysis.
@@ -305,7 +323,7 @@ private class RetNodeEx extends NodeEx {
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
}
private predicate inBarrier(NodeEx node, Configuration config) {
private predicate fullInBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n)
@@ -314,7 +332,16 @@ private predicate inBarrier(NodeEx node, Configuration config) {
)
}
private predicate outBarrier(NodeEx node, Configuration config) {
private predicate stateInBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n, state)
|
config.isSource(n, state)
)
}
private predicate fullOutBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n)
@@ -323,6 +350,15 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
private predicate stateOutBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n, state)
|
config.isSink(n, state)
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -345,9 +381,19 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
pragma[nomagic]
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
exists(Node n | node.asNode() = n |
config.isBarrier(n, state)
or
config.isBarrierIn(n, state) and
not config.isSource(n, state)
or
config.isBarrierOut(n, state) and
not config.isSink(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
)
}
@@ -376,8 +422,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
/** Provides the relevant barriers for a step from `node1` to `node2`. */
pragma[inline]
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullOutBarrier(node1, config) and
not fullInBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
@@ -430,6 +476,8 @@ private predicate additionalLocalStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config)
)
@@ -471,6 +519,8 @@ private predicate additionalJumpStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
@@ -870,8 +920,8 @@ private module Stage1 {
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
revFlow(node, true, config) and
fwdFlow(node, true, config) and
not inBarrier(node, config) and
not outBarrier(node, config)
not fullInBarrier(node, config) and
not fullOutBarrier(node, config)
}
/** Holds if flow may return from `callable`. */
@@ -966,8 +1016,8 @@ private predicate flowOutOfCallNodeCand1(
) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and
not inBarrier(out, config)
not fullOutBarrier(ret, config) and
not fullInBarrier(out, config)
}
pragma[nomagic]
@@ -988,8 +1038,8 @@ private predicate flowIntoCallNodeCand1(
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
not outBarrier(arg, config) and
not inBarrier(p, config)
not fullOutBarrier(arg, config) and
not fullInBarrier(p, config)
}
/**
@@ -1706,18 +1756,31 @@ private module LocalFlowBigStep {
* Holds if `node` can be the first node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
private predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
Stage2::revFlow(node, state, config) and
(
sourceNode(node, state, config) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
additionalJumpStateStep(_, _, node, state, config) or
node instanceof ParamNodeEx or
node.asNode() instanceof OutNodeExt or
store(_, _, node, _, config) or
read(_, _, node, config) or
sourceNode(node, state, config)
or
jumpStep(_, node, config)
or
additionalJumpStep(_, node, config)
or
additionalJumpStateStep(_, _, node, state, config)
or
node instanceof ParamNodeEx
or
node.asNode() instanceof OutNodeExt
or
store(_, _, node, _, config)
or
read(_, _, node, config)
or
node instanceof FlowCheckNode
or
exists(FlowState s |
additionalLocalStateStep(_, s, node, state, config) and
s != state
)
)
}
@@ -1737,6 +1800,9 @@ private module LocalFlowBigStep {
or
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
additionalJumpStateStep(node, state, next, s, config)
or
additionalLocalStateStep(node, state, next, s, config) and
s != state
)
or
Stage2::revFlow(node, state, config) and
@@ -1770,42 +1836,40 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
DataFlowType t, Configuration config, LocalCallContext cc
NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t,
Configuration config, LocalCallContext cc
) {
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](state1), pragma[only_bind_into](config)) and
localFlowEntry(node1, pragma[only_bind_into](state), pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
state1 = state2 and
preservesValue = true and
t = node1.getDataFlowType() // irrelevant dummy value
t = node1.getDataFlowType() and // irrelevant dummy value
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
additionalLocalFlowStepNodeCand2(node1, state, node2, state, config) and
preservesValue = false and
t = node2.getDataFlowType()
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall())
or
exists(NodeEx mid |
localFlowStepPlus(node1, state1, mid, pragma[only_bind_into](state2), preservesValue, t,
localFlowStepPlus(node1, pragma[only_bind_into](state), mid, preservesValue, t,
pragma[only_bind_into](config), cc) and
localFlowStepNodeCand1(mid, node2, config) and
not mid instanceof FlowCheckNode and
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
)
or
exists(NodeEx mid, FlowState st |
localFlowStepPlus(node1, state1, mid, st, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, st, node2, state2, config) and
exists(NodeEx mid |
localFlowStepPlus(node1, state, mid, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, state, node2, state, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
t = node2.getDataFlowType() and
Stage2::revFlow(node2, state2, pragma[only_bind_into](config))
t = node2.getDataFlowType()
)
)
}
@@ -1819,9 +1883,19 @@ private module LocalFlowBigStep {
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
) {
localFlowStepPlus(node1, state1, node2, state2, preservesValue, apf.getType(), config,
callContext) and
localFlowExit(node2, state2, config)
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
localFlowExit(node2, state1, config) and
state1 = state2
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and
preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and
callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or
isUnreachableInCallCached(node2.asNode(), call)
)
}
}
@@ -2695,10 +2769,10 @@ private module Stage4 {
bindingset[node, cc, config]
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
localFlowEntry(node, _, config) and
result =
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
node.getEnclosingCallable())
node.getEnclosingCallable()) and
exists(config)
}
private predicate localStep(

View File

@@ -87,12 +87,30 @@ abstract class Configuration extends string {
/** Holds if data flow into `node` is prohibited. */
predicate isBarrierIn(Node node) { none() }
/**
* Holds if data flow into `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierIn(Node node, FlowState state) { none() }
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/**
* Holds if data flow out of `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierOut(Node node, FlowState state) { none() }
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if the additional flow step from `node1` to `node2` must be taken
* into account in the analysis.
@@ -305,7 +323,7 @@ private class RetNodeEx extends NodeEx {
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
}
private predicate inBarrier(NodeEx node, Configuration config) {
private predicate fullInBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n)
@@ -314,7 +332,16 @@ private predicate inBarrier(NodeEx node, Configuration config) {
)
}
private predicate outBarrier(NodeEx node, Configuration config) {
private predicate stateInBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n, state)
|
config.isSource(n, state)
)
}
private predicate fullOutBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n)
@@ -323,6 +350,15 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
private predicate stateOutBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n, state)
|
config.isSink(n, state)
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -345,9 +381,19 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
pragma[nomagic]
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
exists(Node n | node.asNode() = n |
config.isBarrier(n, state)
or
config.isBarrierIn(n, state) and
not config.isSource(n, state)
or
config.isBarrierOut(n, state) and
not config.isSink(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
)
}
@@ -376,8 +422,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
/** Provides the relevant barriers for a step from `node1` to `node2`. */
pragma[inline]
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullOutBarrier(node1, config) and
not fullInBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
@@ -430,6 +476,8 @@ private predicate additionalLocalStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config)
)
@@ -471,6 +519,8 @@ private predicate additionalJumpStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
@@ -870,8 +920,8 @@ private module Stage1 {
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
revFlow(node, true, config) and
fwdFlow(node, true, config) and
not inBarrier(node, config) and
not outBarrier(node, config)
not fullInBarrier(node, config) and
not fullOutBarrier(node, config)
}
/** Holds if flow may return from `callable`. */
@@ -966,8 +1016,8 @@ private predicate flowOutOfCallNodeCand1(
) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and
not inBarrier(out, config)
not fullOutBarrier(ret, config) and
not fullInBarrier(out, config)
}
pragma[nomagic]
@@ -988,8 +1038,8 @@ private predicate flowIntoCallNodeCand1(
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
not outBarrier(arg, config) and
not inBarrier(p, config)
not fullOutBarrier(arg, config) and
not fullInBarrier(p, config)
}
/**
@@ -1706,18 +1756,31 @@ private module LocalFlowBigStep {
* Holds if `node` can be the first node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
private predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
Stage2::revFlow(node, state, config) and
(
sourceNode(node, state, config) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
additionalJumpStateStep(_, _, node, state, config) or
node instanceof ParamNodeEx or
node.asNode() instanceof OutNodeExt or
store(_, _, node, _, config) or
read(_, _, node, config) or
sourceNode(node, state, config)
or
jumpStep(_, node, config)
or
additionalJumpStep(_, node, config)
or
additionalJumpStateStep(_, _, node, state, config)
or
node instanceof ParamNodeEx
or
node.asNode() instanceof OutNodeExt
or
store(_, _, node, _, config)
or
read(_, _, node, config)
or
node instanceof FlowCheckNode
or
exists(FlowState s |
additionalLocalStateStep(_, s, node, state, config) and
s != state
)
)
}
@@ -1737,6 +1800,9 @@ private module LocalFlowBigStep {
or
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
additionalJumpStateStep(node, state, next, s, config)
or
additionalLocalStateStep(node, state, next, s, config) and
s != state
)
or
Stage2::revFlow(node, state, config) and
@@ -1770,42 +1836,40 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
DataFlowType t, Configuration config, LocalCallContext cc
NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t,
Configuration config, LocalCallContext cc
) {
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](state1), pragma[only_bind_into](config)) and
localFlowEntry(node1, pragma[only_bind_into](state), pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
state1 = state2 and
preservesValue = true and
t = node1.getDataFlowType() // irrelevant dummy value
t = node1.getDataFlowType() and // irrelevant dummy value
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
additionalLocalFlowStepNodeCand2(node1, state, node2, state, config) and
preservesValue = false and
t = node2.getDataFlowType()
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall())
or
exists(NodeEx mid |
localFlowStepPlus(node1, state1, mid, pragma[only_bind_into](state2), preservesValue, t,
localFlowStepPlus(node1, pragma[only_bind_into](state), mid, preservesValue, t,
pragma[only_bind_into](config), cc) and
localFlowStepNodeCand1(mid, node2, config) and
not mid instanceof FlowCheckNode and
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
)
or
exists(NodeEx mid, FlowState st |
localFlowStepPlus(node1, state1, mid, st, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, st, node2, state2, config) and
exists(NodeEx mid |
localFlowStepPlus(node1, state, mid, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, state, node2, state, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
t = node2.getDataFlowType() and
Stage2::revFlow(node2, state2, pragma[only_bind_into](config))
t = node2.getDataFlowType()
)
)
}
@@ -1819,9 +1883,19 @@ private module LocalFlowBigStep {
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
) {
localFlowStepPlus(node1, state1, node2, state2, preservesValue, apf.getType(), config,
callContext) and
localFlowExit(node2, state2, config)
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
localFlowExit(node2, state1, config) and
state1 = state2
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and
preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and
callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or
isUnreachableInCallCached(node2.asNode(), call)
)
}
}
@@ -2695,10 +2769,10 @@ private module Stage4 {
bindingset[node, cc, config]
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
localFlowEntry(node, _, config) and
result =
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
node.getEnclosingCallable())
node.getEnclosingCallable()) and
exists(config)
}
private predicate localStep(

View File

@@ -87,12 +87,30 @@ abstract class Configuration extends string {
/** Holds if data flow into `node` is prohibited. */
predicate isBarrierIn(Node node) { none() }
/**
* Holds if data flow into `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierIn(Node node, FlowState state) { none() }
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/**
* Holds if data flow out of `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierOut(Node node, FlowState state) { none() }
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if the additional flow step from `node1` to `node2` must be taken
* into account in the analysis.
@@ -305,7 +323,7 @@ private class RetNodeEx extends NodeEx {
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
}
private predicate inBarrier(NodeEx node, Configuration config) {
private predicate fullInBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n)
@@ -314,7 +332,16 @@ private predicate inBarrier(NodeEx node, Configuration config) {
)
}
private predicate outBarrier(NodeEx node, Configuration config) {
private predicate stateInBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n, state)
|
config.isSource(n, state)
)
}
private predicate fullOutBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n)
@@ -323,6 +350,15 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
private predicate stateOutBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n, state)
|
config.isSink(n, state)
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -345,9 +381,19 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
pragma[nomagic]
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
exists(Node n | node.asNode() = n |
config.isBarrier(n, state)
or
config.isBarrierIn(n, state) and
not config.isSource(n, state)
or
config.isBarrierOut(n, state) and
not config.isSink(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
)
}
@@ -376,8 +422,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
/** Provides the relevant barriers for a step from `node1` to `node2`. */
pragma[inline]
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullOutBarrier(node1, config) and
not fullInBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
@@ -430,6 +476,8 @@ private predicate additionalLocalStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config)
)
@@ -471,6 +519,8 @@ private predicate additionalJumpStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
@@ -870,8 +920,8 @@ private module Stage1 {
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
revFlow(node, true, config) and
fwdFlow(node, true, config) and
not inBarrier(node, config) and
not outBarrier(node, config)
not fullInBarrier(node, config) and
not fullOutBarrier(node, config)
}
/** Holds if flow may return from `callable`. */
@@ -966,8 +1016,8 @@ private predicate flowOutOfCallNodeCand1(
) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and
not inBarrier(out, config)
not fullOutBarrier(ret, config) and
not fullInBarrier(out, config)
}
pragma[nomagic]
@@ -988,8 +1038,8 @@ private predicate flowIntoCallNodeCand1(
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
not outBarrier(arg, config) and
not inBarrier(p, config)
not fullOutBarrier(arg, config) and
not fullInBarrier(p, config)
}
/**
@@ -1706,18 +1756,31 @@ private module LocalFlowBigStep {
* Holds if `node` can be the first node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
private predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
Stage2::revFlow(node, state, config) and
(
sourceNode(node, state, config) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
additionalJumpStateStep(_, _, node, state, config) or
node instanceof ParamNodeEx or
node.asNode() instanceof OutNodeExt or
store(_, _, node, _, config) or
read(_, _, node, config) or
sourceNode(node, state, config)
or
jumpStep(_, node, config)
or
additionalJumpStep(_, node, config)
or
additionalJumpStateStep(_, _, node, state, config)
or
node instanceof ParamNodeEx
or
node.asNode() instanceof OutNodeExt
or
store(_, _, node, _, config)
or
read(_, _, node, config)
or
node instanceof FlowCheckNode
or
exists(FlowState s |
additionalLocalStateStep(_, s, node, state, config) and
s != state
)
)
}
@@ -1737,6 +1800,9 @@ private module LocalFlowBigStep {
or
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
additionalJumpStateStep(node, state, next, s, config)
or
additionalLocalStateStep(node, state, next, s, config) and
s != state
)
or
Stage2::revFlow(node, state, config) and
@@ -1770,42 +1836,40 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
DataFlowType t, Configuration config, LocalCallContext cc
NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t,
Configuration config, LocalCallContext cc
) {
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](state1), pragma[only_bind_into](config)) and
localFlowEntry(node1, pragma[only_bind_into](state), pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
state1 = state2 and
preservesValue = true and
t = node1.getDataFlowType() // irrelevant dummy value
t = node1.getDataFlowType() and // irrelevant dummy value
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
additionalLocalFlowStepNodeCand2(node1, state, node2, state, config) and
preservesValue = false and
t = node2.getDataFlowType()
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall())
or
exists(NodeEx mid |
localFlowStepPlus(node1, state1, mid, pragma[only_bind_into](state2), preservesValue, t,
localFlowStepPlus(node1, pragma[only_bind_into](state), mid, preservesValue, t,
pragma[only_bind_into](config), cc) and
localFlowStepNodeCand1(mid, node2, config) and
not mid instanceof FlowCheckNode and
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
)
or
exists(NodeEx mid, FlowState st |
localFlowStepPlus(node1, state1, mid, st, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, st, node2, state2, config) and
exists(NodeEx mid |
localFlowStepPlus(node1, state, mid, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, state, node2, state, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
t = node2.getDataFlowType() and
Stage2::revFlow(node2, state2, pragma[only_bind_into](config))
t = node2.getDataFlowType()
)
)
}
@@ -1819,9 +1883,19 @@ private module LocalFlowBigStep {
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
) {
localFlowStepPlus(node1, state1, node2, state2, preservesValue, apf.getType(), config,
callContext) and
localFlowExit(node2, state2, config)
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
localFlowExit(node2, state1, config) and
state1 = state2
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and
preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and
callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or
isUnreachableInCallCached(node2.asNode(), call)
)
}
}
@@ -2695,10 +2769,10 @@ private module Stage4 {
bindingset[node, cc, config]
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
localFlowEntry(node, _, config) and
result =
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
node.getEnclosingCallable())
node.getEnclosingCallable()) and
exists(config)
}
private predicate localStep(

View File

@@ -87,12 +87,30 @@ abstract class Configuration extends string {
/** Holds if data flow into `node` is prohibited. */
predicate isBarrierIn(Node node) { none() }
/**
* Holds if data flow into `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierIn(Node node, FlowState state) { none() }
/** Holds if data flow out of `node` is prohibited. */
predicate isBarrierOut(Node node) { none() }
/**
* Holds if data flow out of `node` is prohibited when the flow state is
* `state`
*/
predicate isBarrierOut(Node node, FlowState state) { none() }
/** Holds if data flow through nodes guarded by `guard` is prohibited. */
predicate isBarrierGuard(BarrierGuard guard) { none() }
/**
* Holds if data flow through nodes guarded by `guard` is prohibited when
* the flow state is `state`
*/
predicate isBarrierGuard(BarrierGuard guard, FlowState state) { none() }
/**
* Holds if the additional flow step from `node1` to `node2` must be taken
* into account in the analysis.
@@ -305,7 +323,7 @@ private class RetNodeEx extends NodeEx {
ReturnKindExt getKind() { result = this.asNode().(ReturnNodeExt).getKind() }
}
private predicate inBarrier(NodeEx node, Configuration config) {
private predicate fullInBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n)
@@ -314,7 +332,16 @@ private predicate inBarrier(NodeEx node, Configuration config) {
)
}
private predicate outBarrier(NodeEx node, Configuration config) {
private predicate stateInBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierIn(n, state)
|
config.isSource(n, state)
)
}
private predicate fullOutBarrier(NodeEx node, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n)
@@ -323,6 +350,15 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
private predicate stateOutBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
config.isBarrierOut(n, state)
|
config.isSink(n, state)
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
@@ -345,9 +381,19 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
pragma[nomagic]
private predicate stateBarrier(NodeEx node, FlowState state, Configuration config) {
exists(Node n |
node.asNode() = n and
exists(Node n | node.asNode() = n |
config.isBarrier(n, state)
or
config.isBarrierIn(n, state) and
not config.isSource(n, state)
or
config.isBarrierOut(n, state) and
not config.isSink(n, state)
or
exists(BarrierGuard g |
config.isBarrierGuard(g, state) and
n = g.getAGuardedNode()
)
)
}
@@ -376,8 +422,8 @@ private predicate sinkNode(NodeEx node, FlowState state, Configuration config) {
/** Provides the relevant barriers for a step from `node1` to `node2`. */
pragma[inline]
private predicate stepFilter(NodeEx node1, NodeEx node2, Configuration config) {
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullOutBarrier(node1, config) and
not fullInBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
@@ -430,6 +476,8 @@ private predicate additionalLocalStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config)
)
@@ -471,6 +519,8 @@ private predicate additionalJumpStateStep(
config.isAdditionalFlowStep(n1, s1, n2, s2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
stepFilter(node1, node2, config) and
not stateOutBarrier(node1, s1, config) and
not stateInBarrier(node2, s2, config) and
not stateBarrier(node1, s1, config) and
not stateBarrier(node2, s2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
@@ -870,8 +920,8 @@ private module Stage1 {
private predicate throughFlowNodeCand(NodeEx node, Configuration config) {
revFlow(node, true, config) and
fwdFlow(node, true, config) and
not inBarrier(node, config) and
not outBarrier(node, config)
not fullInBarrier(node, config) and
not fullOutBarrier(node, config)
}
/** Holds if flow may return from `callable`. */
@@ -966,8 +1016,8 @@ private predicate flowOutOfCallNodeCand1(
) {
viableReturnPosOutNodeCand1(call, ret.getReturnPosition(), out, config) and
Stage1::revFlow(ret, config) and
not outBarrier(ret, config) and
not inBarrier(out, config)
not fullOutBarrier(ret, config) and
not fullInBarrier(out, config)
}
pragma[nomagic]
@@ -988,8 +1038,8 @@ private predicate flowIntoCallNodeCand1(
) {
viableParamArgNodeCand1(call, p, arg, config) and
Stage1::revFlow(p, config) and
not outBarrier(arg, config) and
not inBarrier(p, config)
not fullOutBarrier(arg, config) and
not fullInBarrier(p, config)
}
/**
@@ -1706,18 +1756,31 @@ private module LocalFlowBigStep {
* Holds if `node` can be the first node in a maximal subsequence of local
* flow steps in a dataflow path.
*/
predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
private predicate localFlowEntry(NodeEx node, FlowState state, Configuration config) {
Stage2::revFlow(node, state, config) and
(
sourceNode(node, state, config) or
jumpStep(_, node, config) or
additionalJumpStep(_, node, config) or
additionalJumpStateStep(_, _, node, state, config) or
node instanceof ParamNodeEx or
node.asNode() instanceof OutNodeExt or
store(_, _, node, _, config) or
read(_, _, node, config) or
sourceNode(node, state, config)
or
jumpStep(_, node, config)
or
additionalJumpStep(_, node, config)
or
additionalJumpStateStep(_, _, node, state, config)
or
node instanceof ParamNodeEx
or
node.asNode() instanceof OutNodeExt
or
store(_, _, node, _, config)
or
read(_, _, node, config)
or
node instanceof FlowCheckNode
or
exists(FlowState s |
additionalLocalStateStep(_, s, node, state, config) and
s != state
)
)
}
@@ -1737,6 +1800,9 @@ private module LocalFlowBigStep {
or
exists(NodeEx next, FlowState s | Stage2::revFlow(next, s, config) |
additionalJumpStateStep(node, state, next, s, config)
or
additionalLocalStateStep(node, state, next, s, config) and
s != state
)
or
Stage2::revFlow(node, state, config) and
@@ -1770,42 +1836,40 @@ private module LocalFlowBigStep {
*/
pragma[nomagic]
private predicate localFlowStepPlus(
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
DataFlowType t, Configuration config, LocalCallContext cc
NodeEx node1, FlowState state, NodeEx node2, boolean preservesValue, DataFlowType t,
Configuration config, LocalCallContext cc
) {
not isUnreachableInCallCached(node2.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
(
localFlowEntry(node1, pragma[only_bind_into](state1), pragma[only_bind_into](config)) and
localFlowEntry(node1, pragma[only_bind_into](state), pragma[only_bind_into](config)) and
(
localFlowStepNodeCand1(node1, node2, config) and
state1 = state2 and
preservesValue = true and
t = node1.getDataFlowType() // irrelevant dummy value
t = node1.getDataFlowType() and // irrelevant dummy value
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
additionalLocalFlowStepNodeCand2(node1, state, node2, state, config) and
preservesValue = false and
t = node2.getDataFlowType()
) and
node1 != node2 and
cc.relevantFor(node1.getEnclosingCallable()) and
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall()) and
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
not isUnreachableInCallCached(node1.asNode(), cc.(LocalCallContextSpecificCall).getCall())
or
exists(NodeEx mid |
localFlowStepPlus(node1, state1, mid, pragma[only_bind_into](state2), preservesValue, t,
localFlowStepPlus(node1, pragma[only_bind_into](state), mid, preservesValue, t,
pragma[only_bind_into](config), cc) and
localFlowStepNodeCand1(mid, node2, config) and
not mid instanceof FlowCheckNode and
Stage2::revFlow(node2, pragma[only_bind_into](state2), pragma[only_bind_into](config))
Stage2::revFlow(node2, pragma[only_bind_into](state), pragma[only_bind_into](config))
)
or
exists(NodeEx mid, FlowState st |
localFlowStepPlus(node1, state1, mid, st, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, st, node2, state2, config) and
exists(NodeEx mid |
localFlowStepPlus(node1, state, mid, _, _, pragma[only_bind_into](config), cc) and
additionalLocalFlowStepNodeCand2(mid, state, node2, state, config) and
not mid instanceof FlowCheckNode and
preservesValue = false and
t = node2.getDataFlowType() and
Stage2::revFlow(node2, state2, pragma[only_bind_into](config))
t = node2.getDataFlowType()
)
)
}
@@ -1819,9 +1883,19 @@ private module LocalFlowBigStep {
NodeEx node1, FlowState state1, NodeEx node2, FlowState state2, boolean preservesValue,
AccessPathFrontNil apf, Configuration config, LocalCallContext callContext
) {
localFlowStepPlus(node1, state1, node2, state2, preservesValue, apf.getType(), config,
callContext) and
localFlowExit(node2, state2, config)
localFlowStepPlus(node1, state1, node2, preservesValue, apf.getType(), config, callContext) and
localFlowExit(node2, state1, config) and
state1 = state2
or
additionalLocalFlowStepNodeCand2(node1, state1, node2, state2, config) and
state1 != state2 and
preservesValue = false and
apf = TFrontNil(node2.getDataFlowType()) and
callContext.relevantFor(node1.getEnclosingCallable()) and
not exists(DataFlowCall call | call = callContext.(LocalCallContextSpecificCall).getCall() |
isUnreachableInCallCached(node1.asNode(), call) or
isUnreachableInCallCached(node2.asNode(), call)
)
}
}
@@ -2695,10 +2769,10 @@ private module Stage4 {
bindingset[node, cc, config]
private LocalCc getLocalCc(NodeEx node, Cc cc, Configuration config) {
localFlowEntry(node, _, config) and
result =
getLocalCallContext(pragma[only_bind_into](pragma[only_bind_out](cc)),
node.getEnclosingCallable())
node.getEnclosingCallable()) and
exists(config)
}
private predicate localStep(

View File

@@ -2031,3 +2031,47 @@ abstract class SyntheticField extends string {
* Holds if the the content `c` is a container.
*/
predicate containerContent(DataFlow::Content c) { c instanceof DataFlow::ElementContent }
/**
* A module containing predicates related to generating models as data.
*/
module Csv {
private string parameterQualifiedTypeNamesToString(DataFlowCallable c) {
result =
concat(Parameter p, int i |
p = c.getParameter(i)
|
p.getType().getQualifiedName(), "," order by i
)
}
/** Holds if the summary should apply for all overrides of `c`. */
predicate isBaseCallableOrPrototype(DataFlowCallable c) {
c.getDeclaringType() instanceof Interface
or
exists(Modifiable m | m = [c.(Modifiable), c.(Accessor).getDeclaration()] |
m.isAbstract()
or
c.getDeclaringType().(Modifiable).isAbstract() and m.(Virtualizable).isVirtual()
)
}
/** Gets a string representing whether the summary should apply for all overrides of `c`. */
private string getCallableOverride(DataFlowCallable c) {
if isBaseCallableOrPrototype(c) then result = "true" else result = "false"
}
/** Computes the first 6 columns for CSV rows of `c`. */
string asPartialModel(DataFlowCallable c) {
exists(string namespace, string type |
c.getDeclaringType().hasQualifiedName(namespace, type) and
result =
namespace + ";" //
+ type + ";" //
+ getCallableOverride(c) + ";" //
+ c.getName() + ";" //
+ "(" + parameterQualifiedTypeNamesToString(c) + ")" //
+ /* ext + */ ";" //
)
}
}

View File

@@ -1056,7 +1056,7 @@ module Private {
|
c.relevantSummary(input, output, preservesValue) and
csv =
c.getCallableCsv() + ";;" + getComponentStackCsv(input) + ";" +
c.getCallableCsv() + ";" + getComponentStackCsv(input) + ";" +
getComponentStackCsv(output) + ";" + renderKind(preservesValue)
)
}

View File

@@ -109,6 +109,16 @@ abstract class Configuration extends DataFlow::Configuration {
/** Holds if taint propagation into `node` is prohibited. */
predicate isSanitizerIn(DataFlow::Node node) { none() }
/**
* Holds if taint propagation into `node` is prohibited when the flow state is
* `state`.
*/
predicate isSanitizerIn(DataFlow::Node node, DataFlow::FlowState state) { none() }
final override predicate isBarrierIn(DataFlow::Node node, DataFlow::FlowState state) {
this.isSanitizerIn(node, state)
}
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
/** Holds if taint propagation out of `node` is prohibited. */
@@ -116,6 +126,16 @@ abstract class Configuration extends DataFlow::Configuration {
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
/**
* Holds if taint propagation out of `node` is prohibited when the flow state is
* `state`.
*/
predicate isSanitizerOut(DataFlow::Node node, DataFlow::FlowState state) { none() }
final override predicate isBarrierOut(DataFlow::Node node, DataFlow::FlowState state) {
this.isSanitizerOut(node, state)
}
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
@@ -123,6 +143,16 @@ abstract class Configuration extends DataFlow::Configuration {
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
}
/**
* Holds if taint propagation through nodes guarded by `guard` is prohibited
* when the flow state is `state`.
*/
predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) { none() }
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
this.isSanitizerGuard(guard, state)
}
/**
* Holds if the additional taint propagation step from `node1` to `node2`
* must be taken into account in the analysis.

View File

@@ -109,6 +109,16 @@ abstract class Configuration extends DataFlow::Configuration {
/** Holds if taint propagation into `node` is prohibited. */
predicate isSanitizerIn(DataFlow::Node node) { none() }
/**
* Holds if taint propagation into `node` is prohibited when the flow state is
* `state`.
*/
predicate isSanitizerIn(DataFlow::Node node, DataFlow::FlowState state) { none() }
final override predicate isBarrierIn(DataFlow::Node node, DataFlow::FlowState state) {
this.isSanitizerIn(node, state)
}
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
/** Holds if taint propagation out of `node` is prohibited. */
@@ -116,6 +126,16 @@ abstract class Configuration extends DataFlow::Configuration {
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
/**
* Holds if taint propagation out of `node` is prohibited when the flow state is
* `state`.
*/
predicate isSanitizerOut(DataFlow::Node node, DataFlow::FlowState state) { none() }
final override predicate isBarrierOut(DataFlow::Node node, DataFlow::FlowState state) {
this.isSanitizerOut(node, state)
}
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
@@ -123,6 +143,16 @@ abstract class Configuration extends DataFlow::Configuration {
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
}
/**
* Holds if taint propagation through nodes guarded by `guard` is prohibited
* when the flow state is `state`.
*/
predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) { none() }
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
this.isSanitizerGuard(guard, state)
}
/**
* Holds if the additional taint propagation step from `node1` to `node2`
* must be taken into account in the analysis.

View File

@@ -109,6 +109,16 @@ abstract class Configuration extends DataFlow::Configuration {
/** Holds if taint propagation into `node` is prohibited. */
predicate isSanitizerIn(DataFlow::Node node) { none() }
/**
* Holds if taint propagation into `node` is prohibited when the flow state is
* `state`.
*/
predicate isSanitizerIn(DataFlow::Node node, DataFlow::FlowState state) { none() }
final override predicate isBarrierIn(DataFlow::Node node, DataFlow::FlowState state) {
this.isSanitizerIn(node, state)
}
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
/** Holds if taint propagation out of `node` is prohibited. */
@@ -116,6 +126,16 @@ abstract class Configuration extends DataFlow::Configuration {
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
/**
* Holds if taint propagation out of `node` is prohibited when the flow state is
* `state`.
*/
predicate isSanitizerOut(DataFlow::Node node, DataFlow::FlowState state) { none() }
final override predicate isBarrierOut(DataFlow::Node node, DataFlow::FlowState state) {
this.isSanitizerOut(node, state)
}
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
@@ -123,6 +143,16 @@ abstract class Configuration extends DataFlow::Configuration {
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
}
/**
* Holds if taint propagation through nodes guarded by `guard` is prohibited
* when the flow state is `state`.
*/
predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) { none() }
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
this.isSanitizerGuard(guard, state)
}
/**
* Holds if the additional taint propagation step from `node1` to `node2`
* must be taken into account in the analysis.

View File

@@ -109,6 +109,16 @@ abstract class Configuration extends DataFlow::Configuration {
/** Holds if taint propagation into `node` is prohibited. */
predicate isSanitizerIn(DataFlow::Node node) { none() }
/**
* Holds if taint propagation into `node` is prohibited when the flow state is
* `state`.
*/
predicate isSanitizerIn(DataFlow::Node node, DataFlow::FlowState state) { none() }
final override predicate isBarrierIn(DataFlow::Node node, DataFlow::FlowState state) {
this.isSanitizerIn(node, state)
}
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
/** Holds if taint propagation out of `node` is prohibited. */
@@ -116,6 +126,16 @@ abstract class Configuration extends DataFlow::Configuration {
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
/**
* Holds if taint propagation out of `node` is prohibited when the flow state is
* `state`.
*/
predicate isSanitizerOut(DataFlow::Node node, DataFlow::FlowState state) { none() }
final override predicate isBarrierOut(DataFlow::Node node, DataFlow::FlowState state) {
this.isSanitizerOut(node, state)
}
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
@@ -123,6 +143,16 @@ abstract class Configuration extends DataFlow::Configuration {
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
}
/**
* Holds if taint propagation through nodes guarded by `guard` is prohibited
* when the flow state is `state`.
*/
predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) { none() }
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
this.isSanitizerGuard(guard, state)
}
/**
* Holds if the additional taint propagation step from `node1` to `node2`
* must be taken into account in the analysis.

View File

@@ -109,6 +109,16 @@ abstract class Configuration extends DataFlow::Configuration {
/** Holds if taint propagation into `node` is prohibited. */
predicate isSanitizerIn(DataFlow::Node node) { none() }
/**
* Holds if taint propagation into `node` is prohibited when the flow state is
* `state`.
*/
predicate isSanitizerIn(DataFlow::Node node, DataFlow::FlowState state) { none() }
final override predicate isBarrierIn(DataFlow::Node node, DataFlow::FlowState state) {
this.isSanitizerIn(node, state)
}
final override predicate isBarrierIn(DataFlow::Node node) { this.isSanitizerIn(node) }
/** Holds if taint propagation out of `node` is prohibited. */
@@ -116,6 +126,16 @@ abstract class Configuration extends DataFlow::Configuration {
final override predicate isBarrierOut(DataFlow::Node node) { this.isSanitizerOut(node) }
/**
* Holds if taint propagation out of `node` is prohibited when the flow state is
* `state`.
*/
predicate isSanitizerOut(DataFlow::Node node, DataFlow::FlowState state) { none() }
final override predicate isBarrierOut(DataFlow::Node node, DataFlow::FlowState state) {
this.isSanitizerOut(node, state)
}
/** Holds if taint propagation through nodes guarded by `guard` is prohibited. */
predicate isSanitizerGuard(DataFlow::BarrierGuard guard) { none() }
@@ -123,6 +143,16 @@ abstract class Configuration extends DataFlow::Configuration {
this.isSanitizerGuard(guard) or defaultTaintSanitizerGuard(guard)
}
/**
* Holds if taint propagation through nodes guarded by `guard` is prohibited
* when the flow state is `state`.
*/
predicate isSanitizerGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) { none() }
final override predicate isBarrierGuard(DataFlow::BarrierGuard guard, DataFlow::FlowState state) {
this.isSanitizerGuard(guard, state)
}
/**
* Holds if the additional taint propagation step from `node1` to `node2`
* must be taken into account in the analysis.

View File

@@ -14,24 +14,12 @@
import csharp
import semmle.code.csharp.commons.StructuralComparison
class DoubleCheckedLock extends StructuralComparisonConfiguration {
DoubleCheckedLock() { this = "double checked lock" }
override predicate candidate(ControlFlowElement x, ControlFlowElement y) {
exists(IfStmt unlockedIf, IfStmt lockedIf, LockStmt lock |
x = unlockedIf.getCondition() and
y = lockedIf.getCondition() and
lock = unlockedIf.getThen().stripSingletonBlocks() and
lockedIf.getParent*() = lock.getBlock()
)
}
}
predicate doubleCheckedLock(Field field, IfStmt ifs) {
exists(DoubleCheckedLock config, LockStmt lock, Expr eq1, Expr eq2 | ifs.getCondition() = eq1 |
lock = ifs.getThen().stripSingletonBlocks() and
config.same(eq1, eq2) and
field.getAnAccess() = eq1.getAChildExpr*()
predicate doubleCheckedLock(Field field, IfStmt unlockedIf) {
exists(LockStmt lock, IfStmt lockedIf |
lock = unlockedIf.getThen().stripSingletonBlocks() and
lockedIf.getParent*() = lock.getBlock() and
sameGvn(unlockedIf.getCondition(), lockedIf.getCondition()) and
field.getAnAccess() = unlockedIf.getCondition().getAChildExpr*()
)
}

View File

@@ -12,25 +12,8 @@
import csharp
import semmle.code.csharp.commons.StructuralComparison
class StructuralComparisonConfig extends StructuralComparisonConfiguration {
StructuralComparisonConfig() { this = "MissedTernaryOpportunity" }
override predicate candidate(ControlFlowElement x, ControlFlowElement y) {
exists(IfStmt is, AssignExpr ae1 |
ae1 = is.getThen().stripSingletonBlocks().(ExprStmt).getExpr()
|
x = ae1.getLValue() and
exists(AssignExpr ae2 | ae2 = is.getElse().stripSingletonBlocks().(ExprStmt).getExpr() |
y = ae2.getLValue()
)
)
}
IfStmt getIfStmt() {
exists(AssignExpr ae | ae = result.getThen().stripSingletonBlocks().(ExprStmt).getExpr() |
same(ae.getLValue(), _)
)
}
private Expr getAssignedExpr(Stmt stmt) {
result = stmt.stripSingletonBlocks().(ExprStmt).getExpr().(AssignExpr).getLValue()
}
from IfStmt is, string what
@@ -40,10 +23,8 @@ where
is.getElse().stripSingletonBlocks() instanceof ReturnStmt and
what = "return"
or
exists(StructuralComparisonConfig c |
is = c.getIfStmt() and
what = "write to the same variable"
)
sameGvn(getAssignedExpr(is.getThen()), getAssignedExpr(is.getElse())) and
what = "write to the same variable"
) and
not exists(IfStmt other | is = other.getElse())
select is,

View File

@@ -13,35 +13,26 @@
import csharp
import semmle.code.csharp.commons.StructuralComparison
class StructuralComparisonConfig extends StructuralComparisonConfiguration {
StructuralComparisonConfig() { this = "UselessIsBeforeAs" }
private predicate candidate(AsExpr ae, IsExpr ie) {
exists(IfStmt is, TypeAccessPatternExpr tape |
ie = is.getCondition().getAChild*() and
tape = ie.getPattern() and
ae.getTargetType() = tape.getTarget()
|
ae = is.getThen().getAChild*()
or
ae = is.getElse().getAChild*()
)
}
override predicate candidate(ControlFlowElement x, ControlFlowElement y) {
exists(IfStmt is, AsExpr ae, IsExpr ie, TypeAccessPatternExpr tape |
ie = is.getCondition().getAChild*() and
tape = ie.getPattern() and
ae.getTargetType() = tape.getTarget() and
x = ie.getExpr() and
y = ae.getExpr()
|
ae = is.getThen().getAChild*()
or
ae = is.getElse().getAChild*()
)
}
predicate uselessIsBeforeAs(AsExpr ae, IsExpr ie) {
exists(Expr x, Expr y |
same(x, y) and
ie.getExpr() = x and
ae.getExpr() = y
)
}
private predicate uselessIsBeforeAs(AsExpr ae, IsExpr ie) {
candidate(ae, ie) and
sameGvn(ie.getExpr(), ae.getExpr())
}
from AsExpr ae, IsExpr ie
where
exists(StructuralComparisonConfig c | c.uselessIsBeforeAs(ae, ie)) and
uselessIsBeforeAs(ae, ie) and
not exists(MethodCall mc | ae = mc.getAnArgument().getAChildExpr*())
select ae,
"This 'as' expression performs a type test - it should be directly compared against null, rendering the 'is' $@ potentially redundant.",

View File

@@ -14,24 +14,22 @@
import csharp
import semmle.code.csharp.commons.StructuralComparison
class StructuralComparisonConfig extends StructuralComparisonConfiguration {
StructuralComparisonConfig() { this = "UselessNullCoalescingExpression" }
override predicate candidate(ControlFlowElement x, ControlFlowElement y) {
exists(NullCoalescingExpr nce |
x.(Access) = nce.getLeftOperand() and
y.(Access) = nce.getRightOperand().getAChildExpr*()
)
}
NullCoalescingExpr getUselessNullCoalescingExpr() {
exists(AssignableAccess x |
result.getLeftOperand() = x and
forex(AssignableAccess y | same(x, y) | y instanceof AssignableRead and not y.isRefArgument())
)
}
pragma[noinline]
private predicate same(AssignableAccess x, AssignableAccess y) {
exists(NullCoalescingExpr nce |
x = nce.getLeftOperand() and
y = nce.getRightOperand().getAChildExpr*()
) and
sameGvn(x, y)
}
from StructuralComparisonConfig c, NullCoalescingExpr nce
where nce = c.getUselessNullCoalescingExpr()
private predicate uselessNullCoalescingExpr(NullCoalescingExpr nce) {
exists(AssignableAccess x |
nce.getLeftOperand() = x and
forex(AssignableAccess y | same(x, y) | y instanceof AssignableRead and not y.isRefArgument())
)
}
from NullCoalescingExpr nce
where uselessNullCoalescingExpr(nce)
select nce, "Both operands of this null-coalescing expression access the same variable or property."

Some files were not shown because too many files have changed in this diff Show More