Compare commits

..

911 Commits

Author SHA1 Message Date
github-actions[bot]
b1c4f1610b Post-release preparation 2021-12-02 00:22:43 +00:00
Andrew Eisenberg
ddd4ccbb4b Merge pull request #7274 from github/aeisenberg/add-version-policy
Add a version policy
2021-11-30 14:51:30 -08:00
Andrew Eisenberg
ff030534ff Add a version policy
Handles the post release process.
2021-11-30 14:47:48 -08:00
Dave Bartolomeo
b42295801b Merge pull request #7271 from github/release-prep/2.7.3
Release preparation for version 2.7.3
2021-11-30 17:29:46 -05:00
github-actions[bot]
337ce65fe5 Release preparation for version 2.7.3 2021-11-30 20:39:35 +00:00
Dave Bartolomeo
9f6c0991cf Catch up with recent change notes 2021-11-29 16:41:18 -05:00
Dave Bartolomeo
5ed9029143 Move change notes to correct directories 2021-11-29 16:31:11 -05:00
Dave Bartolomeo
75fb47c76f Ruby change notes 2021-11-29 16:17:19 -05:00
Dave Bartolomeo
cd8a10d0a5 Python change notes 2021-11-29 16:17:05 -05:00
Dave Bartolomeo
96deddf053 JavaScript change notes 2021-11-29 16:16:30 -05:00
Dave Bartolomeo
452685bb66 Fix change note path 2021-11-29 16:11:34 -05:00
Dave Bartolomeo
310ef79fbd C++ change notes 2021-11-29 16:10:33 -05:00
Dave Bartolomeo
d0dac03bad Manually bump versions 2021-11-29 14:21:08 -05:00
Dave Bartolomeo
2dfcd1dd9c Add groups property
Also removed versions from test packs
2021-11-29 14:15:53 -05:00
Chris Smowton
27f40e08e5 Merge pull request #7007 from JLLeitschuh/feat/JLL/improve_ratpack_support
Java: Ratpack HTTP Framework Additional Modeling
2021-11-29 16:20:53 +00:00
Rasmus Wriedt Larsen
d557f6fd2e Merge pull request #7101 from RasmusWL/python-ids
Python: Fix some query-ids
2021-11-29 16:12:57 +01:00
yoff
41b7922c7d Merge pull request #7089 from RasmusWL/redos-cwe-1333
Python/C#: Add CWE-1333 to redos queries
2021-11-29 16:09:39 +01:00
yoff
19802ccb73 Merge pull request #7046 from RasmusWL/django-own-json-response
Python: Add test with custom django json response (FP)
2021-11-29 16:05:20 +01:00
yoff
e63f9141e5 Merge pull request #7233 from RasmusWL/fix-cleartext-logging-cwes
JS/Py: Fix cleartext logging CWEs
2021-11-29 15:58:10 +01:00
Michael Nebel
e476cde985 Merge pull request #7255 from michaelnebel/csharp-effecpublic-flowsummary
C#: Only include effectively public declarations in flow summaries
2021-11-29 12:52:26 +01:00
Michael Nebel
e1539889ef C#: Update flow summaries tests 2021-11-29 11:35:02 +01:00
Michael Nebel
e24b15bbe7 C#: Only create flow summaries for declarations that are effectively public 2021-11-29 11:34:21 +01:00
Michael Nebel
9239d4042e Merge pull request #7230 from michaelnebel/csharp-update-netcoreapp-stub
C#: Update the Microsoft.NETCore.App stub
2021-11-29 10:08:59 +01:00
Tom Hvitved
fdc94365b4 Merge pull request #7178 from michaelnebel/csharp-flowsummary-pp-csv
C#: Initial implementation of csv printing in FlowSummaries test
2021-11-29 09:59:33 +01:00
Michael Nebel
d4f3a6d4bb C#: Review comments. Keep the TContent type pribate 2021-11-26 15:38:33 +01:00
Anders Schack-Mulligen
00ee34c0a0 Merge pull request #7237 from hvitved/dataflow/consistency-config
Data flow: Introduce `ConsistencyConfiguration` class
2021-11-26 12:49:25 +01:00
Anders Schack-Mulligen
57fd397cb3 Merge pull request #7239 from smowton/smowton/fix/useless-comparison-surrogates
Range analysis and useless-comparison query: don't treat all unicode surrogates as if they are U+FFFD
2021-11-26 09:00:36 +01:00
Chris Smowton
d3a4dadc7d Merge pull request #7240 from smowton/smowton/admin/derecognise-xxe-secure-processing
Note that FEATURE_SECURE_PROCESSING isn't a sufficient defence against XXE
2021-11-25 19:31:06 +00:00
Henry Mercer
aa9a8a0e22 Merge pull request #7244 from github/henrymercer/atm-specify-ml-models-globs
JS: [Internal only] Add ML models specification to ATM query pack definition
2021-11-25 18:20:45 +00:00
Chris Smowton
36bb84d97f Copyedit change note 2021-11-25 12:55:55 -05:00
Jonathan Leitschuh
1ddf5fb133 Java: Ratpack HTTP Framework Additional Modeling
Adds models for `ratpack.func.Pair`, and `ratpack.exec.Result`.
Improve moels for `ratpack.exec.Promise`.

Signed-off-by: Jonathan Leitschuh <Jonathan.Leitschuh@gmail.com>
2021-11-25 12:55:32 -05:00
Henry Mercer
29eb66d772 JS: Add ML models to .gitignore 2021-11-25 17:06:37 +00:00
Henry Mercer
2af509595b JS: Add ML models specification to ATM query pack definition
This will allow us to resolve the ATM machine learning models that will
be distributed within this pack.
2021-11-25 16:42:38 +00:00
Chris Smowton
7ac5791c49 Update charLiterals.expected 2021-11-25 16:13:06 +00:00
Chris Smowton
ce63549425 Apply review comments 2021-11-25 15:20:35 +00:00
Chris Smowton
db39c0b8be CharacterLiteral.getCodePointValue: fix handling of surrogates 2021-11-25 14:07:21 +00:00
Anders Schack-Mulligen
a06642944f Merge pull request #7232 from aschackmull/dataflow/perf
Data flow: Performance tuning
2021-11-25 15:01:01 +01:00
Tom Hvitved
dc0b0445ed Merge pull request #7185 from hvitved/csharp/ssa/consistency-queries
C#: Enable SSA consistency queries
2021-11-25 14:04:01 +01:00
Chris Smowton
9540beeda9 Update java/ql/test/query-tests/security/CWE-611/DocumentBuilderTests.java
Co-authored-by: intrigus-lgtm <60750685+intrigus-lgtm@users.noreply.github.com>
2021-11-25 12:52:08 +00:00
Chris Smowton
9eb9eb606e Note that FEATURE_SECURE_PROCESSING isn't a sufficient defence against XXE 2021-11-25 12:22:48 +00:00
Anders Schack-Mulligen
609d6011a2 Merge pull request #7229 from smowton/smowton/admin/document-xxe-sanitisation-policy
Document XXE sanitisation policy
2021-11-25 10:55:25 +01:00
Tom Hvitved
6cb00992e8 Data flow: Introduce ConsistencyConfiguration class 2021-11-25 10:01:47 +01:00
CodeQL CI
d3da790191 Merge pull request #6873 from erik-krogh/explicit-this
Approved by esbena
2021-11-24 15:23:35 -08:00
Chris Smowton
3c8f6e3c07 Merge pull request #6717 from luchua-bc/java/thread-resource-abuse
Java: CWE-400 - Query to detect uncontrolled thread resource consumption
2021-11-24 18:59:41 +00:00
Arthur Baars
4b3b1d2a8b Merge pull request #7222 from aibaars/ruby-ci-fix
Ruby: fix CI jobs after removal of `.codeql-manifest.json`
2021-11-24 17:16:52 +01:00
Erik Krogh Kristensen
1e752f305d apply the explicit this patch to new code 2021-11-24 15:26:19 +01:00
Erik Krogh Kristensen
08ce03cd93 Merge branch 'main' into explicit-this 2021-11-24 15:24:58 +01:00
Erik Krogh Kristensen
3bab8c6d1d Merge pull request #7173 from erik-krogh/getRubyInSync
JS/PY/RB: get ReDoSUtil in sync for ruby
2021-11-24 15:20:23 +01:00
Rasmus Wriedt Larsen
651a76c9ce Python: Add CWE-532 to CleartextLogging
Relevant for this query:

CWE-532: Insertion of Sensitive Information into Log File

> While logging all information may be helpful during development
> stages, it is important that logging levels be set appropriately
> before a product ships so that sensitive user data and system
> information are not accidentally exposed to potential attackers.

See https://cwe.mitre.org/data/definitions/532.html

JS also did this recently: https://github.com/github/codeql/pull/7103
2021-11-24 14:59:52 +01:00
Rasmus Wriedt Larsen
c05ffd4d00 JS/PY: Remove CWE-315 form CleartextLogging
Since it is not relevant for this query:

CWE-315: Cleartext Storage of Sensitive Information in a Cookie

See https://cwe.mitre.org/data/definitions/315.html
2021-11-24 14:59:18 +01:00
Anders Schack-Mulligen
7ca3407c86 Dataflow: Sync. 2021-11-24 14:43:00 +01:00
Anders Schack-Mulligen
a7ec0fa900 Dataflow: Remove more disjunction-induced tuple duplication. 2021-11-24 14:39:49 +01:00
Michael Nebel
b9d0a60ce7 C#: Addressed review comments from hvitved 2021-11-24 14:35:52 +01:00
luchua-bc
b0031a0d85 Add local input test case and update qldoc 2021-11-24 13:30:50 +00:00
Tom Hvitved
1d1780b30f C#: Fix bug in getEnclosingCallable 2021-11-24 14:24:01 +01:00
Rasmus Wriedt Larsen
7dde52ced2 Merge pull request #7131 from RasmusWL/wsgiref.simple_server
Python: Model `wsgiref.simple_server` applications
2021-11-24 14:22:23 +01:00
Anders Schack-Mulligen
4efdcc22a2 Dataflow: Improve barrier handling. 2021-11-24 14:17:05 +01:00
Tom Hvitved
f85fa87f69 C#: Add test that illustrates problem with getEnclosingCallable 2021-11-24 13:59:29 +01:00
Rasmus Wriedt Larsen
2a5e0a3b77 Merge pull request #7145 from RasmusWL/remove-owasp-tags
Python/Ruby: Remove owasp tags
2021-11-24 13:56:48 +01:00
Rasmus Wriedt Larsen
e2652591a5 Python: Change perf fix PoorMansFunctionResolution
Thanks @yoff, this leaves us with the following evaluation, which looks
very close to the one in the other fix (but with cleaner implementation)
-- both at 688k max tuples (although numbers are not exactly the same).

```
[2021-11-24 13:48:40] (14s) Tuple counts for PoorMansFunctionResolution::getSimpleMethodReferenceWithinClass#ff/2@e5f05asv after 74ms:
                      47493  ~3%     {3} r1 = JOIN Class::Class::getAMethod_dispred#ff WITH py_Classes ON FIRST 1 OUTPUT Lhs.1, 0, Lhs.0
                      47335  ~0%     {2} r2 = JOIN r1 WITH AstGenerated::Function_::getArg_dispred#fff ON FIRST 2 OUTPUT Rhs.2, Lhs.2
                      46683  ~0%     {2} r3 = JOIN r2 WITH DataFlowPublic::ParameterNode::getParameter_dispred#fb_10#join_rhs ON FIRST 1 OUTPUT Rhs.1, Lhs.1
                      259968 ~4%     {2} r4 = JOIN r3 WITH LocalSources::Cached::hasLocalSource#ff_10#join_rhs ON FIRST 1 OUTPUT Rhs.1, Lhs.1
                      161985 ~0%     {3} r5 = JOIN r4 WITH Attributes::AttrRef::accesses_dispred#bff_102#join_rhs ON FIRST 1 OUTPUT Rhs.1 'result', Lhs.1, Rhs.2
                      161985 ~2%     {3} r6 = JOIN r5 WITH Attributes::AttrRead#class#f ON FIRST 1 OUTPUT Lhs.2, Lhs.1, Lhs.0 'result'
                      688766 ~0%     {3} r7 = JOIN r6 WITH Function::Function::getName_dispred#ff_10#join_rhs ON FIRST 1 OUTPUT Lhs.1, Rhs.1 'func', Lhs.2 'result'
                      20928  ~0%     {2} r8 = JOIN r7 WITH Class::Class::getAMethod_dispred#ff ON FIRST 2 OUTPUT Lhs.1 'func', Lhs.2 'result'
                                     return r8
```
2021-11-24 13:52:05 +01:00
Tom Hvitved
1d654d1eac C#: Restrict refReadBeforeWrite 2021-11-24 13:43:14 +01:00
Tom Hvitved
1739673202 C#: Enable SSA consistency queries 2021-11-24 13:43:14 +01:00
Chris Smowton
c74eac4930 Remove needless casts 2021-11-24 12:18:05 +00:00
Chris Smowton
cec91c4831 Update ThreadResourceAbuse.qhelp 2021-11-24 12:15:48 +00:00
Chris Smowton
5101a8e9f3 Fix qhelp test 2021-11-24 12:12:56 +00:00
Chris Smowton
136ecaf49a Abbreviate qhelp example 2021-11-24 12:12:22 +00:00
Michael Nebel
c3996b00d5 C#: Update the Microsoft.NETCore.App stub 2021-11-24 13:09:06 +01:00
Chris Smowton
120f2045cd Document XXE sanitisation policy 2021-11-24 12:03:28 +00:00
Mathias Vorreiter Pedersen
6d9cea90cb Merge pull request #7226 from MathiasVP/shorter-ir-dataflow-paths
C++: Hide some IR dataflow nodes
2021-11-24 11:13:52 +00:00
Michael Nebel
a3ca9ad27d C#: Sync flow summary implementation files and implement specific parts for ruby and java 2021-11-24 12:09:20 +01:00
Michael Nebel
e153a65216 C#: Update flow summaries test for EntityFramework to print results in CSV syntax 2021-11-24 12:09:20 +01:00
Michael Nebel
914d3d86af C#: Update flow summaries test to print results in CSV syntax 2021-11-24 12:09:20 +01:00
Michael Nebel
3a7d51d2ee C#: Don't throw away ReturnKind information, when printing flow summaries. Note that any non NormalReturnKind printed summary will not be in the flow summary CSV language 2021-11-24 12:09:20 +01:00
Michael Nebel
e607c51292 C#: Initial implementation of csv printing in FlowSummaries test 2021-11-24 12:09:20 +01:00
Rasmus Wriedt Larsen
47448d9efc Python: Apply suggestions from code review
Co-authored-by: yoff <lerchedahl@gmail.com>
2021-11-24 12:02:12 +01:00
Mathias Vorreiter Pedersen
6c7a01d3d5 C++: Add some comments to the two 'flowThrough' predicates. 2021-11-24 10:50:44 +00:00
yoff
f9729bccef Merge pull request #7143 from RasmusWL/path-improvements
Python: Model `posixpath` and `os.stat`
2021-11-24 11:36:06 +01:00
Anders Schack-Mulligen
a3b263ee6e Merge pull request #7181 from bmuskalla/coverageAsDiagnostics
Java: Add diagnostic query for framework coverage
2021-11-24 10:57:50 +01:00
Rasmus Wriedt Larsen
b2611fe198 Merge branch 'main' into redos-cwe-1333 2021-11-24 10:42:43 +01:00
Mathias Vorreiter Pedersen
2e7ddb479e C++: Accept test changes. 2021-11-24 09:41:00 +00:00
Mathias Vorreiter Pedersen
4cbfc306ac C++: Hide dataflow nodes if they're just used for flow-through for read steps or store steps. 2021-11-24 08:01:44 +00:00
Arthur Baars
133ec2e4af Fix CI jobs 2021-11-23 22:03:01 +01:00
Erik Krogh Kristensen
87a1ccd428 Merge branch 'main' into getRubyInSync 2021-11-23 20:20:37 +01:00
luchua-bc
e56737e007 Use value step to optimize the taint step and add a test case for Apache file upload listener 2021-11-23 17:15:28 +00:00
Mathias Vorreiter Pedersen
8c9e817c0d Merge pull request #7188 from github/redsun82/fix-operand-location
C++: take IR Operand locations from definitions
2021-11-23 16:32:06 +00:00
Nick Rolfe
bb38c4d6fd Merge pull request #6978 from github/nickrolfe/regex_injection
Ruby: add regex injection query
2021-11-23 16:22:35 +00:00
Nick Rolfe
1a90b388a9 Merge remote-tracking branch 'origin/main' into nickrolfe/regex_injection 2021-11-23 15:42:05 +00:00
Paolo Tranquilli
055017de49 fix how non existing locations are accounted for 2021-11-23 15:28:16 +00:00
Paolo Tranquilli
9538ac73e4 account for non-existing locations 2021-11-23 15:28:16 +00:00
Paolo Tranquilli
d626745ab1 fix ThisArgumentOperand location
The correct check to do to choose between using `getAnyDef` and `getUse`
is to check whether the location is an instance of UknonwnLocation.
2021-11-23 15:28:16 +00:00
Paolo Tranquilli
e99a040884 implement review suggestions 2021-11-23 15:28:16 +00:00
Paolo Tranquilli
8b44d5c39e sync files 2021-11-23 15:28:15 +00:00
Paolo Tranquilli
30805d964c add ThisArgumentOperand special case 2021-11-23 15:28:15 +00:00
Paolo Tranquilli
9b818a04f2 sync 2021-11-23 15:28:15 +00:00
Paolo Tranquilli
0bb11fa371 fix PrintAST test run
The refactored shouldDumpFunction was now rejecting functions without a
location. This is fixed now.
2021-11-23 15:28:15 +00:00
Paolo Tranquilli
0547e4ccf2 update further test with new locations 2021-11-23 15:28:15 +00:00
Paolo Tranquilli
d4e80c664e replace shouldDump -> shouldDumpLocation 2021-11-23 15:28:15 +00:00
Paolo Tranquilli
4498657384 Apply suggestions from code review
Co-authored-by: Mathias Vorreiter Pedersen <mathiasvp@github.com>
2021-11-23 15:28:15 +00:00
Paolo Tranquilli
28806fe5f4 update test results after operand location changes 2021-11-23 15:28:15 +00:00
Paolo Tranquilli
6072ccd81d auto-format 2021-11-23 15:28:15 +00:00
Paolo Tranquilli
0ff9520575 ...and syncing files again 2021-11-23 15:28:15 +00:00
Paolo Tranquilli
b5165e3692 C++: more fine-grained Operand location change
Only RegisterOperands need the change, with the notable exception of
ThisArgumentOperand.
2021-11-23 15:28:15 +00:00
Paolo Tranquilli
5202f963dd C++: sync Operand source 2021-11-23 15:28:15 +00:00
Paolo Tranquilli
74c0197544 C++: take IR Operand locations from definitions
Previously Operand's getLocation would take it from the Operand use.
This lead to slightly confusing query results, where for example an
issue related to a call argument would highlight the function part of
the call instead of the parameter.
2021-11-23 15:28:15 +00:00
Tom Hvitved
83d204d7a8 Merge pull request #7218 from hvitved/ssa/fix-consistency-tests
Ruby: Fix SSA consistency tests + CFG bug
2021-11-23 16:24:41 +01:00
Tom Hvitved
4d918b5e5f Ruby: Fix CFG splitting logic for ensure blocks with loops 2021-11-23 15:21:43 +01:00
Anders Schack-Mulligen
822890f2bd Dataflow: Remove disjunction-induced tuple duplication. 2021-11-23 15:05:24 +01:00
Geoffrey White
3e1164f82e Merge pull request #7109 from MathiasVP/remove-reference-to-as-load
C++: Don't interpret 'ReferenceToInstruction' as a load
2021-11-23 13:56:22 +00:00
Alex Ford
055641e684 Merge pull request #7062 from github/ruby/rails-csrf
Ruby: Add `rb/csrf-protection-disabled` query
2021-11-23 13:46:42 +00:00
Anders Schack-Mulligen
f5f67dd11a Dataflow: Pull ccc.matchesCall(call) from the recursive loop. 2021-11-23 14:35:33 +01:00
Taus
8cccee6eba Merge pull request #6972 from yoff/python/promote-redos
Python: Promote ReDoS queries
2021-11-23 14:02:09 +01:00
Tom Hvitved
0bd587b395 Shared SSA: Sync files 2021-11-23 13:30:37 +01:00
Tom Hvitved
e185e9080c Shared SSA: Fix consistency tests 2021-11-23 13:30:23 +01:00
Erik Krogh Kristensen
b2e40ac603 fix typo in test
Co-authored-by: Nick Rolfe <nickrolfe@github.com>
2021-11-23 13:09:22 +01:00
Nick Rolfe
e5f473052d Ruby: add Regexp.{compile,quote} to regex injection test 2021-11-23 11:05:41 +00:00
Anders Schack-Mulligen
e711ba9d18 Dataflow: Remove negation materialization. 2021-11-23 11:35:57 +01:00
Tom Hvitved
9d072a12ed Merge pull request #7098 from github/ruby/desugar-for-1
Ruby: Desugar `for` loops as calls to `each`
2021-11-23 11:35:49 +01:00
Mathias Vorreiter Pedersen
672485ae38 Merge branch 'main' into remove-reference-to-as-load 2021-11-23 10:24:17 +00:00
James Fletcher
21aff99637 Merge pull request #7215 from github/jf205-patch-1
Fix link formatting
2021-11-23 10:03:40 +00:00
Tom Hvitved
dcca5d28bb Merge pull request #7172 from hvitved/ruby/ensure-split-cp
Ruby: Remove CP in `EnsureSplitImpl::exit/3`
2021-11-23 11:02:23 +01:00
Benjamin Muskalla
50518b5622 Fix sum of rows 2021-11-23 10:42:24 +01:00
James Fletcher
b8e8ddf9ae fix link 2021-11-23 08:38:39 +00:00
Anders Schack-Mulligen
a68b55b099 Merge pull request #7208 from hvitved/ruby/restrict-use-use
Ruby: Restrict use-use flow
2021-11-23 09:33:43 +01:00
luchua-bc
ed78d39d61 Move duplicate code to the shared library and update qldoc 2021-11-23 03:06:26 +00:00
Henry Mercer
245edd41ff Merge pull request #7186 from github/henrymercer/rename-available-models-predicate
JS: [Internal only] Rename the available ML models external predicate
2021-11-22 18:26:46 +00:00
Nick Rolfe
13459c8afc Ruby: add Regexp.compile as sink for regexp injection query 2021-11-22 17:43:55 +00:00
Nick Rolfe
4b42c4447b Ruby: handle Regexp.quote wherever we handle Regexp.escape 2021-11-22 17:12:01 +00:00
Nick Rolfe
5b11cfe006 Ruby: fix up import path 2021-11-22 17:10:46 +00:00
Nick Rolfe
752b126862 Merge remote-tracking branch 'origin/main' into nickrolfe/regex_injection 2021-11-22 17:05:27 +00:00
Rasmus Wriedt Larsen
eaed870b31 Python: Fix performance problem in PoorMansFunctionResolution
Before these changes:

[2021-11-22 12:02:50] (8s) Tuple counts for PoorMansFunctionResolution::getSimpleMethodReferenceWithinClass#ff/2@cbddf257 after 8.6s:
                      387565   ~0%     {3} r1 = JOIN Attributes::AttrRead#class#f WITH Attributes::AttrRef::accesses_dispred#bff ON FIRST 1 OUTPUT Rhs.2, Lhs.0 'result', Rhs.1
                      6548632  ~0%     {3} r2 = JOIN r1 WITH Function::Function::getName_dispred#ff_10#join_rhs ON FIRST 1 OUTPUT Rhs.1 'func', Lhs.1 'result', Lhs.2
                      5640480  ~0%     {4} r3 = JOIN r2 WITH Class::Class::getAMethod_dispred#ff_10#join_rhs ON FIRST 1 OUTPUT Rhs.1, Lhs.1 'result', Lhs.2, Lhs.0 'func'
                      55660458 ~0%     {5} r4 = JOIN r3 WITH Class::Class::getAMethod_dispred#ff ON FIRST 1 OUTPUT Rhs.1, 0, Lhs.1 'result', Lhs.2, Lhs.3 'func'
                      55621412 ~0%     {4} r5 = JOIN r4 WITH AstGenerated::Function_::getArg_dispred#fff ON FIRST 2 OUTPUT Rhs.2, Lhs.2 'result', Lhs.3, Lhs.4 'func'
                      54467144 ~0%     {4} r6 = JOIN r5 WITH DataFlowPublic::ParameterNode::getParameter_dispred#fb_10#join_rhs ON FIRST 1 OUTPUT Lhs.2, Rhs.1, Lhs.1 'result', Lhs.3 'func'
                      20928    ~0%     {2} r7 = JOIN r6 WITH LocalSources::Cached::hasLocalSource#ff ON FIRST 2 OUTPUT Lhs.3 'func', Lhs.2 'result'
                                       return r7

With these changes:

[2021-11-22 11:54:25] (415s) Tuple counts for PoorMansFunctionResolution::getSimpleMethodReferenceWithinClass_helper#fff/3@14db70a8 after 75ms:
                      388306 ~0%     {2} r1 = JOIN Attributes::AttrRead#class#f WITH Attributes::AttrRef::getObject_dispred#bf ON FIRST 1 OUTPUT Rhs.1, Lhs.0 'read'
                      379420 ~4%     {2} r2 = JOIN r1 WITH LocalSources::Cached::hasLocalSource#ff ON FIRST 1 OUTPUT Rhs.1, Lhs.1 'read'
                      175082 ~0%     {2} r3 = JOIN r2 WITH DataFlowPublic::ParameterNode#class#fff ON FIRST 1 OUTPUT Rhs.2, Lhs.1 'read'
                      175082 ~2%     {3} r4 = JOIN r3 WITH Essa::ParameterDefinition::getParameter_dispred#ff ON FIRST 1 OUTPUT 0, Rhs.1, Lhs.1 'read'
                      166798 ~0%     {2} r5 = JOIN r4 WITH AstGenerated::Function_::getArg_dispred#fff_120#join_rhs ON FIRST 2 OUTPUT Rhs.2 'func', Lhs.2 'read'
                      162096 ~0%     {3} r6 = JOIN r5 WITH Class::Class::getAMethod_dispred#ff_10#join_rhs ON FIRST 1 OUTPUT Lhs.0 'func', Rhs.1 'cls', Lhs.1 'read'
                                     return r6

[2021-11-22 11:54:25] (415s) Tuple counts for PoorMansFunctionResolution::getSimpleMethodReferenceWithinClass_helper2#ffff/4@2b60f0s9 after 63ms:
                      162046 ~0%     {3} r1 = SCAN PoorMansFunctionResolution::getSimpleMethodReferenceWithinClass_helper#fff OUTPUT In.2 'read', In.0 'func', In.1 'cls'
                      162046 ~0%     {3} r2 = JOIN r1 WITH Attributes::AttrRead#class#f ON FIRST 1 OUTPUT Lhs.1 'func', Lhs.2 'cls', Lhs.0 'read'
                      162046 ~1%     {3} r3 = JOIN r2 WITH py_Functions ON FIRST 1 OUTPUT Lhs.1 'cls', Lhs.2 'read', Lhs.0 'func'
                      162046 ~0%     {3} r4 = JOIN r3 WITH py_Classes ON FIRST 1 OUTPUT Lhs.1 'read', Lhs.2 'func', Lhs.0 'cls'
                      161935 ~5%     {4} r5 = JOIN r4 WITH Attributes::AttrRef::getAttributeName_dispred#bf ON FIRST 1 OUTPUT Rhs.1, Lhs.0 'read', Lhs.1 'func', Lhs.2 'cls'
                      688526 ~1%     {4} r6 = JOIN r5 WITH Function::Function::getName_dispred#ff_10#join_rhs ON FIRST 1 OUTPUT Lhs.2 'func', Lhs.3 'cls', Lhs.1 'read', Rhs.1 'readFunction'
                                     return r6

[2021-11-22 11:54:25] (415s) Tuple counts for PoorMansFunctionResolution::getSimpleMethodReferenceWithinClass#ff/2@f73ae6dq after 58ms:
                      688526 ~0%     {4} r1 = SCAN PoorMansFunctionResolution::getSimpleMethodReferenceWithinClass_helper2#ffff OUTPUT In.1, In.0, In.3 'func', In.2 'result'
                      688526 ~0%     {3} r2 = JOIN r1 WITH Class::Class::getAMethod_dispred#ff ON FIRST 2 OUTPUT Rhs.0, Lhs.2 'func', Lhs.3 'result'
                      20913  ~0%     {2} r3 = JOIN r2 WITH Class::Class::getAMethod_dispred#ff ON FIRST 2 OUTPUT Lhs.1 'func', Lhs.2 'result'
                                     return r3

We need the `pragma[only_bind_into]` in getSimpleMethodReferenceWithinClass_helper2, otherwise the tuple counts would look like, which is needlessly big.

[2021-11-22 17:14:34] (2s) Tuple counts for PoorMansFunctionResolution::getSimpleMethodReferenceWithinClass_helper2#ffff/4@5f0505h7 after 711ms:
                      13570510 ~3%     {2} r1 = JOIN Function::Function::getName_dispred#ff_10#join_rhs WITH Attributes::AttrRef::getAttributeName_dispred#ff_10#join_rhs ON FIRST 1 OUTPUT Rhs.1 'read', Lhs.1 'readFunction'
                      688526   ~1%     {4} r2 = JOIN r1 WITH PoorMansFunctionResolution::getSimpleMethodReferenceWithinClass_helper#fff_201#join_rhs ON FIRST 1 OUTPUT Rhs.1 'func', Rhs.2 'cls', Lhs.0 'read', Lhs.1 'readFunction'
                                       return r2
2021-11-22 17:22:39 +01:00
Arthur Baars
f6baab6399 Merge pull request #7211 from dbartol/dbartol/ruby-workspace
Merge Ruby workspace into root workspace
2021-11-22 16:22:12 +01:00
Alex Ford
68c3c16ab3 Ruby: enable forgery protection checks for development environments 2021-11-22 15:00:32 +00:00
Dave Bartolomeo
186e3755c0 Remove unnecessary path options 2021-11-22 09:50:01 -05:00
Tom Hvitved
da39f15a9d Ruby: Move localFlowStepCommon into LocalFlow and make localSsaFlowStep private 2021-11-22 15:24:24 +01:00
Dave Bartolomeo
522074940d Merge Ruby workspace into root workspace 2021-11-22 09:10:59 -05:00
AlonaHlobina
b60fef88b5 Merge pull request #7206 from github/AlonaHlobina-patch-2
Update query-metadata-style-guide.md
2021-11-22 14:48:46 +01:00
Mathias Vorreiter Pedersen
21167f4b67 C++: Accept test changes. 2021-11-22 13:04:23 +00:00
Mathias Vorreiter Pedersen
f308be7382 C++: Restore the missing flow. This has a couple of side-effects: First, it gives us some new good flow (yay). Second, it causes some duplication of results that uses 'argv' as a taint source. The duplication isn't very bad, though. And since it is only for paths that start at 'argv', I think we can live with it for now. 2021-11-22 13:04:07 +00:00
Mathias Vorreiter Pedersen
74221f4aba Merge pull request #7209 from geoffw0/experimental-tests
C++: Move experimental test.
2021-11-22 13:01:52 +00:00
Harry Maclean
6f22867af9 Merge pull request #7015 from github/hmac/ssrf
Ruby: Add Server-Side Request Forgery query
2021-11-22 12:41:39 +00:00
CodeQL CI
ddeb700fd6 Merge pull request #7207 from github/asgerf/document-template-language-extensions
Approved by esbena
2021-11-22 04:16:19 -08:00
Tom Hvitved
fc64faefcf Ruby: Restrict use-use flow 2021-11-22 13:05:17 +01:00
Geoffrey White
6f2b528a32 C++: Move experimental test. 2021-11-22 11:02:06 +00:00
Asger F
8322a44379 JS: Mention .hbs, .ejs, and .njk file extensions
Also fixes a typo `.xhm` -> `.xhtm`
2021-11-22 11:53:55 +01:00
Rasmus Wriedt Larsen
f09f1c4c50 Python: Minor refactor in PoorMansFunctionResolution 2021-11-22 11:11:29 +01:00
Tom Hvitved
39e3254fe0 Merge pull request #7182 from hvitved/csharp/self-assignment-bad-magic
C#: Fix bad magic `Element::fromSource` in context of `SelfAssignment.ql`
2021-11-22 10:57:48 +01:00
AlonaHlobina
0de6511dff Update query-metadata-style-guide.md 2021-11-22 10:17:57 +01:00
Erik Krogh Kristensen
9f08acab7e Merge pull request #7170 from erik-krogh/qldocStyle
Ruby: use A/An/The to start qlDoc for classes
2021-11-19 17:34:35 +01:00
Anders Schack-Mulligen
344f7bca5b Merge pull request #7187 from aschackmull/java/dont-clear-in-summary-store
Java: Don't clear content in store steps in summaries.
2021-11-19 16:12:37 +01:00
Harry Maclean
06000781e9 Ruby: Document PairCfgNode::getKey/getValue 2021-11-19 14:54:06 +00:00
Anders Schack-Mulligen
fc43220864 Java: bugfix 2021-11-19 15:01:29 +01:00
Anders Schack-Mulligen
2b1f34ed9b Java: Don't clear content in store steps in summaries. 2021-11-19 14:22:28 +01:00
Henry Mercer
8ba864e897 JS: Rename the available ML models external predicate 2021-11-19 12:56:03 +00:00
Tom Hvitved
47fd64fc44 Merge pull request #7130 from hvitved/cfg/dead-end-consistency
Shared CFG: Add "dead end" consistency query
2021-11-19 13:49:53 +01:00
Tom Hvitved
2b2ff7717e Merge pull request #7179 from hvitved/ruby/shared-ssa-consistency
Ruby: Move SSA consistency queries into shared SSA library
2021-11-19 13:49:25 +01:00
Erik Krogh Kristensen
75586b0cf6 Apply suggestions from code review
Co-authored-by: Nick Rolfe <nickrolfe@github.com>
2021-11-19 13:23:01 +01:00
Tom Hvitved
a393bff6cb C#: Fix bad magic Element::getLocation in context of SelfAssignment.ql 2021-11-19 12:44:07 +01:00
Harry Maclean
90a9688310 Ruby: update CFG fixture 2021-11-19 11:31:14 +00:00
Benjamin Muskalla
cd39d15b40 Simplify diagnostic query 2021-11-19 12:28:24 +01:00
Harry Maclean
8fc7e4be43 Ruby: Increase precision of SSRF query 2021-11-19 11:28:09 +00:00
Harry Maclean
c297a68acf Model more of the RestClient API
We now handle this form:

    RestClient::Request.execute(url: "http://example.com")
2021-11-19 11:28:09 +00:00
Harry Maclean
e2ef780c55 Add base_uri note to HTTParty modelling 2021-11-19 11:28:09 +00:00
Harry Maclean
38ff584307 Model more Faraday behaviour
You can instantiate a Faraday connection by passing a URL as an keyword
argument:

    conn = Faraday.new(url: "http://example.com")
2021-11-19 11:28:09 +00:00
Harry Maclean
f933d24031 Fix comment 2021-11-19 11:28:09 +00:00
Harry Maclean
70efadac77 Add change note for Ruby SSRF query 2021-11-19 11:28:09 +00:00
Harry Maclean
e87a4531d8 Remove redundant imports 2021-11-19 11:28:08 +00:00
Harry Maclean
ac20eafecc Add qhelp for Ruby SSRF 2021-11-19 11:28:08 +00:00
Harry Maclean
2bba31eb02 Update metadata of Ruby SSRF query 2021-11-19 11:28:08 +00:00
Harry Maclean
dc464879a2 Add a query for server-side request forgery 2021-11-19 11:28:08 +00:00
Harry Maclean
cd33e4d394 Make string interpolation sanitizer reusable 2021-11-19 11:28:08 +00:00
Harry Maclean
b6ce37b241 Add getURL to HTTP::Client::Request
This member predicate gets dataflow nodes which contribute to the URL of
the request.

Also consolidate the identical tests for each HTTP client.
2021-11-19 11:28:08 +00:00
Harry Maclean
8fd8c9b04d Fix CallExprCfgNode.getKeywordArgument
This predicate now produces results.
2021-11-19 11:28:08 +00:00
Harry Maclean
0caea17118 Add a test for CallCfgNodes
This test shows that `CallCfgNode.getKeywordArgument(string keyword)`
doesn't return any results.
2021-11-19 11:28:07 +00:00
Tom Hvitved
34feafd4fa C#: Do not pass in TSourceVariable IPA type into shared SSA library 2021-11-19 11:53:25 +01:00
Anders Schack-Mulligen
1f3f7e9ccc Merge pull request #7169 from erik-krogh/useMatches
use matches instead of regexpMatch/prefix/suffix
2021-11-19 11:42:47 +01:00
Tom Hvitved
4068cc9c3a Shared SSA: Sync files 2021-11-19 11:31:28 +01:00
Tom Hvitved
bc80c9b013 Ruby: Move SSA consistency queries into shared SSA library 2021-11-19 11:31:28 +01:00
Benjamin Muskalla
fb9b16325d Add diagnostic query for framework coverage 2021-11-19 10:30:59 +01:00
Tom Hvitved
fd0e318eb1 C#: Document inconsistency in one test 2021-11-19 09:43:51 +01:00
Tom Hvitved
923ca134e8 Shared CFG: Add "dead end" consistency query 2021-11-19 09:14:38 +01:00
luchua-bc
b6a6ed5ba3 Add a recommendation category query for local user input and check Apache file upload 2021-11-19 04:23:19 +00:00
Erik Krogh Kristensen
62730e7a4b Merge pull request #7174 from erik-krogh/fixCSharpImport
C#: move Linq/Helpers.qll to the lib folder
2021-11-18 19:40:53 +01:00
Tom Hvitved
a4538de3a3 Shared CFG: Rename TNode to TCfgNode
This is in order to avoid name clash with the often so-named IPA type for data-
flow nodes. The name clash is not problematic because they are both in scope,
but because (cached) IPA types with overlapping names are known to sometimes
result in re-evaluation of cached stages, when one of the IPA types gets an
internal `#2` suffix in one query run, and the other IPA type gets the suffix
in another run.
2021-11-18 19:15:36 +01:00
Tom Hvitved
2f7250a0b3 Merge pull request #7160 from hvitved/csharp/cfg/static-scope
C#: Extend `(Annotated)ExitNode` to also cover static fields
2021-11-18 19:15:06 +01:00
Erik Krogh Kristensen
63ecae5426 update imports 2021-11-18 17:31:17 +01:00
Erik Krogh Kristensen
2d78cce7a5 move Linq/Helpers to the lib folder 2021-11-18 16:59:34 +01:00
Erik Krogh Kristensen
ee858d840e get ReDoSUtil in sync for ruby 2021-11-18 16:49:34 +01:00
Tom Hvitved
2218516685 Ruby: Remove CP in EnsureSplitImpl::exit/3 2021-11-18 16:05:09 +01:00
Henry Mercer
46958e5bff Merge pull request #7168 from erik-krogh/useMinInsteadofRank1
ATM: use min() instead of rank[1]
2021-11-18 14:56:49 +00:00
Erik Krogh Kristensen
af55f172ae use A/An/The to start qlDoc for classes 2021-11-18 15:42:45 +01:00
Erik Krogh Kristensen
011fc20963 use matches instead of regexpMatch 2021-11-18 15:41:25 +01:00
Anders Schack-Mulligen
6815a13a00 Merge pull request #6931 from hvitved/dataflow/restrict-derived-summaries
Data flow: Restrict derived flow summaries
2021-11-18 15:31:55 +01:00
Erik Krogh Kristensen
2af7817691 use min() instead of rank[1] 2021-11-18 14:26:55 +01:00
Geoffrey White
6c2713dd8b Merge pull request #7159 from MathiasVP/pointers-are-always-iterators
C++: Always recognize pointers as iterators
2021-11-18 11:14:44 +00:00
Tony Torralba
9d22ec88fd Merge pull request #7165 from github/workflow/coverage/update
Update CSV framework coverage reports
2021-11-18 10:37:34 +01:00
Erik Krogh Kristensen
1cca377e7d Merge pull request #6561 from erik-krogh/htmlReg
JS/Py/Ruby: add a bad-tag-filter query
2021-11-18 09:39:13 +01:00
github-actions[bot]
ecdaeb0c10 Add changed framework coverage reports 2021-11-18 00:09:24 +00:00
Tom Hvitved
a89be2e3f8 C#: Extend (Annotated)ExitNode to also cover static fields 2021-11-17 20:50:38 +01:00
Mathias Vorreiter Pedersen
c998370c84 C++: Accept more test changes. 2021-11-17 15:22:17 +00:00
Mathias Vorreiter Pedersen
36585a7469 C++: Accept test changes. 2021-11-17 14:41:30 +00:00
Mathias Vorreiter Pedersen
6dc6a78293 C++: Add a 'IteratorByPointer' class so pointers are always iterators. 2021-11-17 14:41:19 +00:00
Alex Ford
08b6a17097 Merge pull request #7151 from github/ruby/methodcallnode
Ruby: add `getMethodName` predicate to `DataFlow::CallNode` class
2021-11-17 14:40:07 +00:00
Anders Schack-Mulligen
22ebe68b1b Merge pull request #7132 from aschackmull/java/overrides
Java: Fix overrides to not be transitive.
2021-11-17 15:38:11 +01:00
Anders Schack-Mulligen
1645fcf79c Merge pull request #7088 from aschackmull/java/parameterized-subtyping
Java: Improve algorithm for subtyping of parameterized types.
2021-11-17 15:28:28 +01:00
Tom Hvitved
de72a765e0 Ruby: Update expected CFG test output (reordering) 2021-11-17 13:44:55 +01:00
Tom Hvitved
9ff63b00d6 Ruby: Remove CFG dependency from AST stage
Commit 028ef6f27f had the unintended side-effect
that the AST and CFG stages got merged, because the AST stage's `isCapturedAccess`
now depends on `getCfgScopeImpl`, which belongs to the CFG stage.

The fix is to remove `getCfgScopeImpl` from the CFG stage, and instead let it
be part of the AST stage.
2021-11-17 13:15:55 +01:00
Arthur Baars
5ddfb37f29 Merge pull request #7155 from aibaars/ruby-qualified-import
Ruby: QL generator: use qualified imports
2021-11-17 12:40:14 +01:00
Arthur Baars
6f24947ec6 Merge pull request #7156 from aibaars/ruby-prepare-db-upgrade-fix
Ruby: Fix scripts/prepare-db-upgrade.sh
2021-11-17 12:39:55 +01:00
Benjamin Muskalla
3c3a65243f Merge pull request #6664 from bmuskalla/bmuskalla/modelGenerator
Java: Initial CSV model generator
2021-11-17 12:30:45 +01:00
Arthur Baars
fbb3e8d780 Fix scripts/prepare-db-upgrade.sh 2021-11-17 12:11:20 +01:00
Geoffrey White
d232283647 Merge pull request #7149 from geoffw0/non-https-url2
C++: Minor improvements to 'Failure to use HTTPS URLs' query
2021-11-17 10:05:30 +00:00
Tom Hvitved
4eacbd1cbe Ruby: Sync files 2021-11-17 10:49:51 +01:00
Tom Hvitved
6d58dd2823 Java: Update expected test output 2021-11-17 10:49:51 +01:00
Tom Hvitved
3da73b9001 C#: Update expected test output 2021-11-17 10:49:49 +01:00
Tom Hvitved
58dd75881c C#: Update flow summary to avoid negative recursion 2021-11-17 10:39:13 +01:00
Tom Hvitved
ac41451798 Data flow: Sync files 2021-11-17 10:39:12 +01:00
Tom Hvitved
0c1285f5d9 Data flow: Restrict derived flow summaries 2021-11-17 10:39:12 +01:00
Arthur Baars
7c2841f058 Ruby: QL generator: use qualified imports 2021-11-17 10:37:44 +01:00
Erik Krogh Kristensen
474c808373 Merge pull request #7137 from erik-krogh/functionExport
JS: recognize library inputs when the library exports "through" a function
2021-11-17 09:49:02 +01:00
Tom Hvitved
08c778241d Ruby: Adopt to changes after rebase 2021-11-17 09:17:32 +01:00
Anders Schack-Mulligen
69671ce90d Java: cache overrides 2021-11-17 09:16:58 +01:00
Tom Hvitved
413375992d Ruby: Flatten nested statements inside desugared for loops 2021-11-17 09:05:37 +01:00
Tom Hvitved
9125b85ff0 Ruby: Add missing QL doc 2021-11-17 09:05:37 +01:00
Tom Hvitved
92453bd2c5 Ruby: Rewrite break_ensure.rb CFG test to use while loops instead of for loops 2021-11-17 09:05:37 +01:00
Tom Hvitved
945bb7459a Ruby: Update expected test output 2021-11-17 09:05:37 +01:00
Tom Hvitved
a62ad5000b Ruby: Make isCapturedAccess work with synthesized scopes 2021-11-17 09:05:37 +01:00
Tom Hvitved
135ee0d0c1 Ruby: Add implicit writes for synthesized parameters 2021-11-17 09:05:37 +01:00
Tom Hvitved
028ef6f27f Ruby: Handle synthesized scopes 2021-11-17 09:05:37 +01:00
Tom Hvitved
48e6bdb117 Ruby: Remove EmptinessCompletion 2021-11-17 09:05:36 +01:00
Tom Hvitved
db6f843641 Ruby: Hide SynthBlock from the public API 2021-11-17 09:05:36 +01:00
Alex Ford
8603609698 Update test output to account for for-loop -> each desugaring 2021-11-17 09:05:36 +01:00
Alex Ford
e468434b82 ruby: drop special handling of for-in loops in the CFG 2021-11-17 09:05:33 +01:00
Alex Ford
ddfcfc9b67 Desugar for loops as each calls 2021-11-17 09:04:29 +01:00
Alex Ford
f6d99dc00d Define getBlockImpl for synthesized method calls 2021-11-17 09:04:29 +01:00
Alex Ford
a743067dc8 Support synthesis of blocks (without a new variable scope) 2021-11-17 09:04:29 +01:00
Alex Ford
04df56d1c0 Support synthesis of SimpleParameters 2021-11-17 09:04:29 +01:00
Tom Hvitved
7cfc696d62 Merge pull request #7141 from hvitved/ruby/synthesis-realnode-recursion
Ruby: Eliminate unnecessary recursion through `RealNode`
2021-11-17 09:03:30 +01:00
Pierre
f846915b58 Merge pull request #7069 from github/turbo-apple-silicon-requirements-1
Add requirements for Apple Silicon
2021-11-17 00:04:06 +01:00
Alex Ford
c8cdbfa352 ruby: push getMethodName into DataFlow::CallNode 2021-11-16 17:11:26 +00:00
Benjamin Muskalla
b4eadefb92 Fix test 2021-11-16 17:28:01 +01:00
Benjamin Muskalla
063c8286c8 Merge pull request #7150 from bmuskalla/removeClassFile
Java: Remove class file
2021-11-16 17:27:31 +01:00
Benjamin Muskalla
55cdb7d755 Exclude .class files from git 2021-11-16 16:41:23 +01:00
Alex Ford
286c894f34 ruby: add DataFlow::MethodCallNode class 2021-11-16 15:39:47 +00:00
Benjamin Muskalla
3dbaa087d4 Remove class file 2021-11-16 16:36:27 +01:00
Paolo Tranquilli
2ce5b85db4 Merge pull request #7112 from github/redsun82/frontend-update
c++: update ir tests after frontend update
2021-11-16 16:30:34 +01:00
Chris Smowton
188915e597 Fix typos 2021-11-16 15:30:00 +00:00
Anders Schack-Mulligen
76606b5995 Java: Add more comments. 2021-11-16 16:11:14 +01:00
Taus
eed98bd76a Merge pull request #5588 from jorgectf/jorgectf/python/jwt-queries
Python: Add JWT security-related queries
2021-11-16 15:40:45 +01:00
Geoffrey White
ea9640a39d C++: Autoformat. 2021-11-16 14:26:42 +00:00
Chris Smowton
8d22db8089 Merge pull request #7140 from smowton/smowton/admin/merge-lgtm-com-cherry-pick
Merge lgtm.com into main
2021-11-16 14:13:27 +00:00
jorgectf
9ad8a85f4d Delete redundant checks in verifiesSignature() 2021-11-16 15:08:18 +01:00
Anders Schack-Mulligen
c70d384d28 Merge pull request #7045 from aschackmull/dataflow/hidden-ret-subpaths
Data flow: Support hidden return nodes in subpaths predicate
2021-11-16 15:04:51 +01:00
jorgectf
3fe2a08376 Update .expected file 2021-11-16 15:03:49 +01:00
Jorge
a722631278 Apply suggestions from code review
Co-authored-by: Taus <tausbn@github.com>
2021-11-16 15:02:06 +01:00
Paolo Tranquilli
8d3cf7f5aa C++: update ir tests after frontend update
After updating the frontend new intermediate objects appear in the AST
and raw dumps.
2021-11-16 13:25:32 +00:00
Anders Schack-Mulligen
d408105fad Java: Fix bad join-order. 2021-11-16 14:25:19 +01:00
Geoffrey White
5ef71e6ef3 C++: Add a few more sinks. 2021-11-16 13:02:56 +00:00
Tom Hvitved
a65f5725d3 Merge pull request #7146 from hvitved/ruby/remove-ci-check
Ruby: Remove `Compile with previous CodeQL versions` CI check
2021-11-16 13:44:24 +01:00
Erik Krogh Kristensen
a7cd097ca2 Merge pull request #6756 from erik-krogh/extractBigReg
JS: extract regexp literals for string concatenations
2021-11-16 13:33:21 +01:00
Tom Hvitved
075c9d89b3 Ruby: Remove Compile with previous CodeQL versions CI check 2021-11-16 13:30:32 +01:00
Tom Hvitved
9e8e2e2b48 Ruby: Update CFG test output (some nodes have been reordered) 2021-11-16 12:45:24 +01:00
Tom Hvitved
e7b091086d Ruby: Eliminate unnecessary recursion through RealNode 2021-11-16 12:24:17 +01:00
Geoffrey White
aafa5762ad C++: Add a CWE tag associated with OWASP A8. 2021-11-16 11:21:25 +00:00
Rasmus Wriedt Larsen
98e6fc8a88 Python/Ruby: Remove owasp tags
These are no longer correct, since the A1 category changed from 2017 to
2021, see https://owasp.org/Top10/#whats-changed-in-the-top-10-for-2021

Since only a very few queries had these tags, I think we're much better
off having them removed.
2021-11-16 12:03:50 +01:00
Tom Hvitved
3a8e2db3ab Merge pull request #7121 from hvitved/ruby/lookup-const-anti-join 2021-11-16 11:32:55 +01:00
Geoffrey White
ed3e5395d1 Merge pull request #7063 from MathiasVP/use-range-analysis-in-buffer-write
C++: Use `SimpleRangeAnalysis` in `Printf.qll`
2021-11-16 10:24:47 +00:00
Benjamin Muskalla
0e6bb28016 Only consider store steps 2021-11-16 10:46:24 +01:00
Rasmus Wriedt Larsen
a980f26fda Python: Model os.stat (and friends) 2021-11-16 10:45:32 +01:00
Rasmus Wriedt Larsen
9f4107d211 Python: Model posixpath, ntpath, and genericpath modules 2021-11-16 10:45:14 +01:00
Mathias Vorreiter Pedersen
71c279f537 Merge branch 'main' into use-range-analysis-in-buffer-write 2021-11-16 09:14:02 +00:00
Erik Krogh Kristensen
b9ea4a8709 recognize library inputs when the library exports "through" a function 2021-11-15 22:43:38 +01:00
Erik Krogh Kristensen
1a98079100 Merge pull request #7139 from erik-krogh/gotGet
JS: improve the got model
2021-11-15 22:42:03 +01:00
Erik Krogh Kristensen
12c24c07df improve the got model 2021-11-15 21:52:12 +01:00
Tom Hvitved
f01b9005b1 Merge pull request #7122 from hvitved/csharp/expose-repr-perf
C#: Replace `localFlow` with `localFlowStep` in recursive predicate
2021-11-15 21:11:21 +01:00
Tom Hvitved
6599eca9fb Merge pull request #7138 from hvitved/ruby/forward-param-cfg
Ruby: Add missing CFG entry for `ForwardParameter`
2021-11-15 19:28:31 +01:00
Chris Smowton
708e059e7f Merge branch 'lgtm.com' of github.com:github/codeql into smowton/admin/merge-lgtm-com-cherry-pick 2021-11-15 18:18:28 +00:00
Tony Torralba
d97b130bdd Merge pull request #7092 from atorralba/atorralba/android-asynctask-jumpstep
Java: Add AsyncTask additional value step
2021-11-15 16:59:56 +01:00
Benjamin Muskalla
fd9199c0c0 Simplify handling of tainting fields 2021-11-15 16:40:09 +01:00
Benjamin Muskalla
d7ed325b3f Refactor content flow into predicate 2021-11-15 16:30:55 +01:00
Benjamin Muskalla
f4310898b3 Capture sources flowing into parameters 2021-11-15 16:28:28 +01:00
Tom Hvitved
03ae58830a Ruby: Add missing CFG entry for ForwardParameter 2021-11-15 16:28:17 +01:00
Tom Hvitved
3ce41015bb Ruby: Add CFG test for forward parameters 2021-11-15 16:25:06 +01:00
Tony Torralba
87ebcea913 Add AsyncTask value step 2021-11-15 16:13:36 +01:00
Anders Schack-Mulligen
a40a393b38 Merge pull request #7134 from aschackmull/java/additionalvaluestep
Java: Add support for adding additional value steps.
2021-11-15 16:07:30 +01:00
Anders Schack-Mulligen
1cd42ea668 Java: Fix test and some references. 2021-11-15 16:03:04 +01:00
Rasmus Wriedt Larsen
6b7abacc5f Merge pull request #7135 from RasmusWL/b32hexencode
Python: Model `b32hexencode`/`b32hexdecode`
2021-11-15 15:51:46 +01:00
Benjamin Muskalla
8040d9cfcf Only consider true return statements as sinks 2021-11-15 15:29:01 +01:00
Rasmus Wriedt Larsen
95dbe1383b Merge pull request #7133 from RasmusWL/minor-3.10-fix
Python: Minor additions for 3.10
2021-11-15 15:25:34 +01:00
Rasmus Wriedt Larsen
39927fa613 Python: Model b32hexencode/b32hexdecode
New in Python 3.10

See
- https://devdocs.io/python~3.10/library/base64#base64.b32hexencode
- https://devdocs.io/python~3.10/library/base64#base64.b32hexdecode
2021-11-15 15:23:49 +01:00
Benjamin Muskalla
e6e52a3b32 190 2021-11-15 15:18:03 +01:00
Anders Schack-Mulligen
2fe6880d70 Java: Add support for adding additional value steps. 2021-11-15 15:05:48 +01:00
Rasmus Wriedt Larsen
cfdfcaa3e8 Python: Support Path.hardlink_to (new in 3.10)
See https://docs.python.org/3.10/library/pathlib.html#pathlib.Path.hardlink_to
2021-11-15 14:57:59 +01:00
Rasmus Wriedt Larsen
5d60975f65 Python: Support aiter and anext (new in 3.10)
See
- https://docs.python.org/3/whatsnew/3.10.html#other-language-changes
- https://docs.python.org/3.10/library/functions.html#aiter
- https://docs.python.org/3.10/library/functions.html#anext
2021-11-15 14:55:34 +01:00
Mathias Vorreiter Pedersen
3f0bfe1d75 C++: Remove the implicit assumption about the existence of a lower bound implying the existence of an upper bound (and vice veraa). 2021-11-15 13:39:15 +00:00
Mathias Vorreiter Pedersen
63f50a9eb7 C++: Cleanup the case for possibly-negative unsigned values. 2021-11-15 13:31:51 +00:00
Mathias Vorreiter Pedersen
9a9f7943aa C++: Fix bug for exact powers of 10 and accept test changes. 2021-11-15 13:20:45 +00:00
Mathias Vorreiter Pedersen
53884915a5 C++: Add more tests (which demonstrate a couple of bugs in the implementation). 2021-11-15 13:18:30 +00:00
Anders Schack-Mulligen
c616f5784d Java: Fix overrides to not be transitive. 2021-11-15 13:54:53 +01:00
Rasmus Wriedt Larsen
7c3b68b7f8 Merge pull request #7091 from RasmusWL/port-request-without-validation
Python: Port `py/request-without-cert-validation` to use API graphs
2021-11-15 13:51:57 +01:00
Erik Krogh Kristensen
0023b885f5 update expected output 2021-11-15 13:50:12 +01:00
Erik Krogh Kristensen
2163648b39 fix location off-by-ones with regexp parsing 2021-11-15 13:43:39 +01:00
Rasmus Wriedt Larsen
9e097f5430 Python: Improve PoorMansFunctionResolution 2021-11-15 13:40:19 +01:00
Rasmus Wriedt Larsen
0d4cb1e6ce Python: Add test of PoorMansFunctionResolution 2021-11-15 13:34:39 +01:00
Rasmus Wriedt Larsen
6eb4525ab2 Python: Model wsgiref.simple_server applications 2021-11-15 13:34:39 +01:00
Rasmus Wriedt Larsen
e812029c03 Python: Add test for wsgiref.simple_server 2021-11-15 13:34:38 +01:00
Tom Hvitved
4bbfa514c9 Merge pull request #6535 from hvitved/csharp/consistency-queries
C#: Add consistency queries
2021-11-15 13:15:58 +01:00
CodeQL CI
c8b8a2874f Merge pull request #7119 from github/max-schaefer/api-graphs-property-copies
Approved by asgerf
2021-11-15 04:09:16 -08:00
Benjamin Muskalla
dc022430ee Remove superflous instanceof 2021-11-15 13:07:02 +01:00
Benjamin Muskalla
412bd32f45 Move more predicates into configuration 2021-11-15 13:04:23 +01:00
Benjamin Muskalla
b84c03672d Prefer types to TargetAPI 2021-11-15 12:43:46 +01:00
Benjamin Muskalla
bca6cecd1c Remove basic support for lambda flow 2021-11-15 12:38:30 +01:00
Taus
c17560f948 Merge pull request #7096 from tausbn/python-fix-more-bad-joins
Python: Fix a bunch of performance issues
2021-11-15 12:10:27 +01:00
Benjamin Muskalla
78e3906ea7 Exclude more JDK internals 2021-11-15 11:58:10 +01:00
Tom Hvitved
723ac818d9 Shared CFG: Update breakInvariant4 consistency test 2021-11-15 11:43:49 +01:00
Mathias Vorreiter Pedersen
c2e057def9 Merge pull request #7094 from geoffw0/non-https-url
C++: New query 'Failure to use HTTPS URLs'
2021-11-15 10:00:19 +00:00
Tom Hvitved
d323b3b17d Merge pull request #7123 from hvitved/ruby/definitions-perf
Ruby: Fix performance problem in `Definitions.ql`
2021-11-15 10:58:03 +01:00
Benjamin Muskalla
cce3780481 Restrict param2return value features 2021-11-15 09:57:23 +01:00
Erik Krogh Kristensen
f0c5a80d1a apply the explicit this patch to new code 2021-11-13 21:03:54 +01:00
Erik Krogh Kristensen
0ff36cd083 Merge branch 'main' into explicit-this 2021-11-13 21:01:25 +01:00
Tom Hvitved
b5d37ae0fe C#: Update CFG consistency checks 2021-11-12 17:07:37 +01:00
Tom Hvitved
d1a09b62d3 Address review comments 2021-11-12 16:31:00 +01:00
Erik Krogh Kristensen
eef7709982 Merge pull request #7057 from erik-krogh/cwe598
JS: add js/sensitive-get-query query
2021-11-12 16:03:21 +01:00
yoff
5beb681580 Merge pull request #7087 from RasmusWL/path-injection-fp
Python: Add interesting path-injection FP
2021-11-12 15:20:19 +01:00
Tom Hvitved
3471e757f2 Ruby: Fix performance problem in Definitions.ql 2021-11-12 14:35:16 +01:00
yoff
9f614b1d98 Merge pull request #7016 from RasmusWL/django-rest-framework
Python: Model Django REST framework
2021-11-12 14:27:56 +01:00
Rasmus Wriedt Larsen
b11d11c0c9 Python: Add change-note 2021-11-12 14:27:01 +01:00
Tom Hvitved
19e6da517b Ruby: Fix bad join-order in resolveConstant
```
[2021-11-09 11:35:47] (99s) Starting to evaluate predicate Module::Cached::resolveConstant#ff#antijoin_rhs/3@f6dcd6
[2021-11-09 11:35:58] (111s) Tuple counts for Module::Cached::resolveConstant#ff#antijoin_rhs/3@f6dcd6 after 11.5s:
                      165960683 ~0%     {4} r1 = JOIN Module::Cached::resolveConstant#ff#shared WITH Module::constantDefinition0#ff_10#join_rhs ON FIRST 1 OUTPUT Rhs.1, Lhs.1 'arg1', Lhs.0 'arg0', Lhs.2 'arg2'

                      0         ~0%     {3} r2 = JOIN r1 WITH Module::ClassDeclaration::getSuperclassExpr_dispred#ff ON FIRST 2 OUTPUT Lhs.2 'arg0', Lhs.1 'arg1', Lhs.3 'arg2'

                      0         ~0%     {3} r3 = JOIN r1 WITH Constant::ConstantAccess::getScopeExpr_dispred#ff ON FIRST 2 OUTPUT Lhs.2 'arg0', Lhs.1 'arg1', Lhs.3 'arg2'

                      0         ~0%     {3} r4 = r2 UNION r3
                                        return r4
```
2021-11-12 14:08:11 +01:00
Tom Hvitved
9ee1c49bac C#: Replace localFlow with localFlowStep in recursive predicate 2021-11-12 14:04:38 +01:00
Rasmus Wriedt Larsen
491f72bb2a Python: Adjust generated code to be more familiar 2021-11-12 13:30:03 +01:00
Rasmus Wriedt Larsen
de69e4c645 Python: Expand on SubclassFinder implementation note 2021-11-12 13:29:03 +01:00
Rasmus Wriedt Larsen
f7b53321b9 Python: Remove copy-pasted comment 2021-11-12 13:19:20 +01:00
Tom Hvitved
67ebebbaeb C#: Add consistency queries 2021-11-12 13:10:46 +01:00
Taus
55ea715ce9 Merge pull request #7033 from RasmusWL/flask-admin 2021-11-12 12:18:56 +01:00
Nick Rolfe
9034d74663 Ruby: add file-level qldoc 2021-11-12 11:12:27 +00:00
Rasmus Wriedt Larsen
860b1a5cc3 Python: Other minor QLDoc adjustment 2021-11-12 11:46:45 +01:00
Erik Krogh Kristensen
80919e39a2 Merge branch 'main' into extractBigReg 2021-11-12 11:45:49 +01:00
Rasmus Wriedt Larsen
99081ea7e0 Python: Minor adjustment in QLDoc 2021-11-12 11:42:36 +01:00
Rasmus Wriedt Larsen
5e4b866f2b Python: Model rest_framework.exceptions.APIException 2021-11-12 11:37:54 +01:00
Rasmus Wriedt Larsen
62e58b534c Python: SubclassFinder: reorder + comment 2021-11-12 11:11:13 +01:00
Rasmus Wriedt Larsen
f48ecb1dc8 Python: Apply suggestions from code review
Co-authored-by: yoff <lerchedahl@gmail.com>
2021-11-12 10:57:56 +01:00
Benjamin Muskalla
a0b7f267ff Only capture taint from own fields
Also exclude `Charset` as relevant taint-carrying type. This is generally
what we want to lets us avoid tracking arguments that lead to FP.
2021-11-12 10:15:15 +01:00
Benjamin Muskalla
0234e77d2f Let sink node be pluggable in any call context 2021-11-12 09:43:05 +01:00
Benjamin Muskalla
b8809a20d8 Support propagating taint of inner object 2021-11-12 09:39:59 +01:00
Tom Hvitved
b5cf4c2f82 Merge pull request #7111 from michaelnebel/csharp-move-printast
Csharp move PrintAst query to test directory.
2021-11-12 09:19:13 +01:00
Rasmus Wriedt Larsen
06cae3dac2 Merge pull request #7104 from yoff/python/model-aiomysql
Python: model aiomysql
2021-11-11 16:58:01 +01:00
Tom Hvitved
004144bbef Merge pull request #7028 from hvitved/ruby/api-graphs-prune
Ruby: Prune nodes before computing `trackUseNode`
2021-11-11 15:57:21 +01:00
Michael Nebel
9ea320c53c Update all PrintAst.qlref to point to new location of PrintAst.ql 2021-11-11 15:19:15 +01:00
Mathias Vorreiter Pedersen
982de28b89 Update cpp/ql/lib/semmle/code/cpp/commons/Printf.qll
Co-authored-by: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
2021-11-11 13:19:13 +00:00
Erik Krogh Kristensen
e09c12430d Merge pull request #7105 from erik-krogh/flagJqueryUI
JS: have the aliasPropertyPresenceStep step over extend calls
2021-11-11 14:05:11 +01:00
Erik Krogh Kristensen
b639a8d183 update ruby example
Co-authored-by: Nick Rolfe <nickrolfe@github.com>
2021-11-11 14:04:38 +01:00
CodeQL CI
34cc61e51f Merge pull request #7083 from asgerf/js/type-track-object-literals-with-methods
Approved by erik-krogh
2021-11-11 04:35:55 -08:00
Michael Nebel
5a4557f588 Move PrintAst.ql and update import statement 2021-11-11 13:27:12 +01:00
Rasmus Lerchedahl Petersen
e2a2a42d59 Python: Fix api references 2021-11-11 13:20:57 +01:00
Geoffrey White
ea580cd9c0 C++: Add explanatory comments. 2021-11-11 11:49:51 +00:00
Erik Krogh Kristensen
b513033e0f Merge pull request #7021 from erik-krogh/cwe326
JS: Add insufficient key size query
2021-11-11 12:17:04 +01:00
Erik Krogh Kristensen
891694b50a Merge pull request #5908 from erik-krogh/protoLib
JS: Add library input as source to js/prototype-polluting-assignment
2021-11-11 12:04:05 +01:00
Erik Krogh Kristensen
140a70f9df Merge pull request #7029 from erik-krogh/cwe384
JS: add js/session-fixation query
2021-11-11 11:59:52 +01:00
Erik Krogh Kristensen
0bf055fbec Merge pull request #7103 from erik-krogh/add-cwe532-to-cleartextlogging
JS: add CWE-532 to the js/clear-text-logging query
2021-11-11 11:59:16 +01:00
Erik Krogh Kristensen
9a11c13e11 update expected output 2021-11-11 11:56:30 +01:00
Mathias Vorreiter Pedersen
dbcd4d6d5d C++: Remove 'ReferenceToInstruction' from the list of instructions we interpret as a load. This makes use lose a bunch of flow, and we'll restore this flow in the next commit. 2021-11-11 10:38:52 +00:00
Anders Schack-Mulligen
7ffd9b4f9e Dataflow: Include read/store steps when finding non-hidden return. 2021-11-11 11:26:21 +01:00
Asger F
7d8284a41c Apply suggestions from code review
Co-authored-by: Erik Krogh Kristensen <erik-krogh@github.com>
2021-11-11 10:42:49 +01:00
Geoffrey White
901919f7ff C++: Add tests expanding on the issue with (global) variables. 2021-11-11 09:40:03 +00:00
Geoffrey White
43ff3b1c80 C++: Address review comment. 2021-11-11 09:39:59 +00:00
Mathias Vorreiter Pedersen
bf9b8cfff0 Merge pull request #6947 from ihsinme/ihsinme-patch-077
CPP: Add query for CWE-377 Insecure Temporary File
2021-11-11 09:02:04 +00:00
Geoffrey White
9a1b98e1d9 C++: Fix qhelp example link. 2021-11-10 17:54:05 +00:00
Erik Krogh Kristensen
5d901ef728 move extend aliasing to getAnAliasedSourceNode 2021-11-10 18:08:50 +01:00
Geoffrey White
c29011a5cf C++: Add more sinks. 2021-11-10 16:43:28 +00:00
Benjamin Muskalla
2d4176bec0 Ignore Number-derived types 2021-11-10 16:30:27 +01:00
Benjamin Muskalla
dbd393b77a Support flow into field of referenced objects 2021-11-10 16:30:27 +01:00
Benjamin Muskalla
974c7b0898 Avoid cross-class flow for field writes 2021-11-10 16:30:26 +01:00
Benjamin Muskalla
74ac234f1c Restrict field access to same type 2021-11-10 16:30:26 +01:00
Benjamin Muskalla
8740e879b4 Fix docs 2021-11-10 16:30:26 +01:00
Benjamin Muskalla
a546b38ee0 Restrict field access to corresponding type 2021-11-10 16:30:26 +01:00
Benjamin Muskalla
6960a7b97e Remove extraneous last column 2021-11-10 16:30:25 +01:00
Benjamin Muskalla
ef972159a6 Fix bug when generating output in a subfolder 2021-11-10 16:30:25 +01:00
Benjamin Muskalla
4cfd978bfe Support generating in respective folders 2021-11-10 16:30:25 +01:00
Benjamin Muskalla
b92758883b Auto-format generated qll files 2021-11-10 16:30:25 +01:00
Benjamin Muskalla
e2bd792fc2 Consider bulk-like data for argument accessors 2021-11-10 16:30:25 +01:00
Benjamin Muskalla
739fe75194 Support flow for factory and strategy pattern
* Support models for factories that create
new instances of an object while tainting it with incoming data
* Support models to infer super types for
private implementations to expose the models
at the right level
2021-11-10 16:30:24 +01:00
Benjamin Muskalla
58de6d143f Add docs to explain the models captured by the predicates 2021-11-10 16:30:24 +01:00
Benjamin Muskalla
747ab122c3 Restrict fluent api models to same type access 2021-11-10 16:30:24 +01:00
Benjamin Muskalla
8564c9001a Fix naming for source nodes 2021-11-10 16:30:24 +01:00
Benjamin Muskalla
9500c9c8bc Support lambda flow for source models
Also rely on public API to detect the source node
2021-11-10 16:30:24 +01:00
Benjamin Muskalla
35baa1c3df Support bulkdata for boxed types as well 2021-11-10 16:30:23 +01:00
Benjamin Muskalla
83b4070f31 Fix bug to accept bulk data for char/byte arrays 2021-11-10 16:30:23 +01:00
Benjamin Muskalla
281f25403d Match enclosing unit without casting to specific nodes 2021-11-10 16:30:23 +01:00
Benjamin Muskalla
bc10fd94cb Support generating only specific models 2021-11-10 16:30:23 +01:00
Benjamin Muskalla
0e9fcc6c39 Only generate models for local supertypes
Avoid generating models for classes
implementing external SPI (e.g. `FileFilter`).
Keep `toString` models intact as they're
commonly used as taint-propagation method
(e.g. see `Joiner`).
2021-11-10 16:30:23 +01:00
Benjamin Muskalla
157f56f48a Capture model for defining interface
Instead of modeling individual implementations, take a more general
approach of reuse dataflows for interfaces defined by a library. This allows
tracking flows across all implementations and aligns better with how we
manually model frameworks. This may have some FPs given all possible flows
are modeled for a specific interface but also covers more scenarios where
we don't know which implementation of an interface is used.
2021-11-10 16:30:22 +01:00
Benjamin Muskalla
f36bb8baaf Exclude models for simpler types
Avoid generating models for types that can't really propagate taint
in a valuable way (e.g. primitivies, BigInt, ..). Keep tracking
bulk-like data (e.g. char[] or byte[]).
2021-11-10 16:30:22 +01:00
Benjamin Muskalla
842f617bc1 Order sinks and sources first 2021-11-10 16:30:22 +01:00
Benjamin Muskalla
be150f269b Formatting 2021-11-10 16:30:22 +01:00
Benjamin Muskalla
2654e27123 Exclude known internal APIs from being modeled 2021-11-10 16:30:22 +01:00
Benjamin Muskalla
6b2460d4a1 Formatting 2021-11-10 16:30:21 +01:00
Benjamin Muskalla
060862ab3b Avoid certain test sources in models 2021-11-10 16:30:21 +01:00
Benjamin Muskalla
e607953b9c Simplify query 2021-11-10 16:30:21 +01:00
Benjamin Muskalla
9a859334d4 Formatting 2021-11-10 16:30:21 +01:00
Benjamin Muskalla
6c59333716 Remove workaround that accounted for missing flow 2021-11-10 16:30:21 +01:00
Benjamin Muskalla
7dae6122d9 Support CharSequence#toString
Given CharSequence is often used as an
alias for String, ensure taint through toString is flowing
2021-11-10 16:30:20 +01:00
Benjamin Muskalla
ca9d5439f0 Restrict source configuration to return nodes 2021-11-10 16:30:20 +01:00
Benjamin Muskalla
7a7ec06819 Simplify sink configuration 2021-11-10 16:30:20 +01:00
Benjamin Muskalla
1a4fd7bc7d Allow camelcase names 2021-11-10 16:30:20 +01:00
Benjamin Muskalla
2b2ac82fb7 Fix bug in sink detection 2021-11-10 16:30:20 +01:00
Benjamin Muskalla
c616eb1473 Fix finding more sources 2021-11-10 16:30:19 +01:00
Benjamin Muskalla
38579ef25b Add proper metadata to queries 2021-11-10 16:30:19 +01:00
Benjamin Muskalla
a80d50cbc0 Simplify field flow 2021-11-10 16:30:19 +01:00
Benjamin Muskalla
a1d8dfb524 Initial support for source models 2021-11-10 16:30:19 +01:00
Benjamin Muskalla
c844f5382f Add script to generate flow models 2021-11-10 16:30:19 +01:00
Benjamin Muskalla
f9fea15a52 Initial support for capturing sink models 2021-11-10 16:30:18 +01:00
Benjamin Muskalla
364de55b8d Support parameter->parameter flow 2021-11-10 16:30:18 +01:00
Benjamin Muskalla
cd11ef3bf6 Support outgoing taint flow from fields 2021-11-10 16:30:18 +01:00
Benjamin Muskalla
c3462be2c9 Capture argument->return value flows 2021-11-10 16:30:18 +01:00
Benjamin Muskalla
4ca006ba3d Only expose visible innner classes 2021-11-10 16:30:18 +01:00
Benjamin Muskalla
88032afdc3 Add test for final class 2021-11-10 16:30:17 +01:00
Benjamin Muskalla
ec772fb6b2 Add support for qualifier flow 2021-11-10 16:30:17 +01:00
Benjamin Muskalla
32ef40c77b Add scaffolding for summary model generator 2021-11-10 16:30:17 +01:00
Erik Krogh Kristensen
2d907f825e have the aliasPropertyPresenceStep step over extend calls 2021-11-10 16:26:00 +01:00
Geoffrey White
ae622bd482 C++: Use hasGlobalOrStdName. 2021-11-10 14:57:07 +00:00
Tom Hvitved
198b321158 Java: Hide parameters of summarized callables 2021-11-10 15:13:32 +01:00
Tom Hvitved
34fdf11b4b Ruby: Update expected test output 2021-11-10 15:11:13 +01:00
Tom Hvitved
82abab1510 C#: Hide parameters of summarized callables 2021-11-10 15:11:13 +01:00
Anders Schack-Mulligen
6d9fb3ca43 Dataflow: Sync. 2021-11-10 15:11:13 +01:00
Anders Schack-Mulligen
678a21e532 Dataflow: Support hidden return nodes in subpaths. 2021-11-10 15:11:13 +01:00
Mathias Vorreiter Pedersen
e0b876d2f6 Merge pull request #7102 from MathiasVP/fix-map-test
C++: Fix a testcase
2021-11-10 13:51:10 +00:00
yoff
d23a920ed4 Merge branch 'main' into python/model-aiomysql 2021-11-10 14:32:36 +01:00
Rasmus Lerchedahl Petersen
57e7bfbdba Python: model aiomysql 2021-11-10 14:29:39 +01:00
Rasmus Lerchedahl Petersen
047cff0749 Python: test aiomysql 2021-11-10 14:24:45 +01:00
Mathias Vorreiter Pedersen
ccdaf49464 C++: Fix the same bug in the test for ordered maps. 2021-11-10 13:24:27 +00:00
Erik Krogh Kristensen
55434653f5 add CWE-532 to the clear-text-logging query 2021-11-10 14:15:49 +01:00
Erik Krogh Kristensen
98da532c46 dont extract regular expressions from strings that are leaves in a string concat 2021-11-10 14:11:48 +01:00
Mathias Vorreiter Pedersen
86d78b34aa C++: Use the correct variable in the 'test'. 2021-11-10 13:04:48 +00:00
Rasmus Wriedt Larsen
de926dc2a1 Merge pull request #7085 from yoff/python/model-aiopg
Python: model aiopg
2021-11-10 13:10:30 +01:00
Rasmus Wriedt Larsen
1f90dcadf1 Python: Use backtracker for verify arg 2021-11-10 12:54:23 +01:00
Geoffrey White
2f39c64cc2 C++: Fix character in qhelp. 2021-11-10 11:23:57 +00:00
Benjamin Muskalla
0f086056a1 Merge pull request #7100 from bmuskalla/bmuskalla/ioAsFile
Java: Extract Commons IO into seperate file
2021-11-10 12:04:12 +01:00
Max Schaefer
a8c4455b20 Factor out an auxiliary predicate. 2021-11-10 10:17:59 +00:00
Rasmus Lerchedahl Petersen
92a7114b72 Python: Add API references 2021-11-10 11:06:58 +01:00
Rasmus Lerchedahl Petersen
c6d285dd2a Python: Fix test 2021-11-10 11:06:45 +01:00
yoff
a856395d56 Apply suggestions from code review
Co-authored-by: Rasmus Wriedt Larsen <rasmuswriedtlarsen@gmail.com>
2021-11-10 10:51:40 +01:00
Rasmus Wriedt Larsen
77099fe9d0 Python: Always use @id py/
The two queries in CWE-020 are used for manual evaluation (is my
understanding), and the two IDE queries should work based on their tags,
and not on the query-id.
2021-11-10 10:40:17 +01:00
Benjamin Muskalla
f9fa22c14d Removed unused import 2021-11-10 10:21:54 +01:00
Benjamin Muskalla
1a751608de Extract Commons IO into seperate file 2021-11-10 10:15:27 +01:00
Mathias Vorreiter Pedersen
e2ab1c8c5e Merge branch 'main' into use-range-analysis-in-buffer-write 2021-11-10 08:28:43 +00:00
Tony Torralba
4da1dce811 Merge pull request #7099 from github/workflow/coverage/update
Update CSV framework coverage reports
2021-11-10 08:54:11 +01:00
Erik Krogh Kristensen
ab5d9459c7 Update javascript/ql/src/Security/CWE-384/SessionFixation.qhelp
Co-authored-by: Ethan Palm <56270045+ethanpalm@users.noreply.github.com>
2021-11-10 08:24:46 +01:00
ihsinme
a0448240aa Update InsecureTemporaryFile.expected 2021-11-10 09:23:51 +03:00
ihsinme
7514fe2b45 Update test.cpp 2021-11-10 09:22:58 +03:00
ihsinme
289d58745a Update InsecureTemporaryFile.ql 2021-11-10 09:22:03 +03:00
github-actions[bot]
f5426336c3 Add changed framework coverage reports 2021-11-10 00:09:06 +00:00
Taus
33135e909a Python: Add magic to named_argument_transfer
This predicate was materialised as a _big_, _cached_ relation:

```
(169s) Tuple counts for PointsTo::InterProceduralPointsTo::named_argument_transfer#ffff#join_rhs/4@38ce07 after 53.4s:
25212     ~4%     {3} r1 = SCAN Function::Function::getArgByName_dispred#fff OUTPUT In.1, In.0 'arg1', In.2 'arg2'
159751200 ~0%     {4} r2 = JOIN r1 WITH Flow::CallNode::getArgByName_dispred#fff_102#join_rhs ON FIRST 1 OUTPUT Rhs.1 'arg0', Lhs.1 'arg1', Lhs.2 'arg2', Rhs.2 'arg3'
                  return r2
```

... However it's only used in a single place (where it is immediately
joined with the points-to relation to relate the caller and argument),
none of these joins were ever larger than 2000 tuples. This made it
pretty clear that we could gain something by pushing in that points-to
join as a bit of manual magic.

However, doing so didn't actually fix anything, since the join-orderer
then decided to join `func.getArgByName(name)` with
`call.getArgByName(name)` on `name` as the first thing (which caused a
join of the same size as above).

Unbinding didn't work, since `name` would then be an unbound `string`,
so instead I factored out relating the function, parameter, and name
thereof into its own predicate. (I could also have done this with the
call, but I would expect there to be more calls than function
definitions in general.)

Overall, this resulted in going from

```
(709s)
Definitions.ql-7:PointsTo::InterProceduralPointsTo::named_argument_transfer#ffff#join_rhs ......... 53.5s
Definitions.ql-7:Instances::InstanceObject::initializer_dispred#fbf ............................... 35.3s (456 evaluations with max 136ms in Instances::InstanceObject::initializer_dispred#fbf/3@i110#0508e8)
Definitions.ql-10:DefinitionTracking::jump_to_defn_attribute#fbf .................................. 27s (100 evaluations with max 12.8s in DefinitionTracking::jump_to_defn_attribute#fbf/3@i1#fc1f7x)
Definitions.ql-7:PointsTo::PointsToInternal::pointsTo#ffff ........................................ 16.1s (681 evaluations with max 2.5s in PointsTo::PointsToInternal::pointsTo#ffff/4@i4#0508eg)
Definitions.ql-7:Constants::ConstantObjectInternal::attribute#ffff ................................ 13.4s (505 evaluations with max 50ms in Constants::ConstantObjectInternal::attribute#ffff/4@i153#0508e5)
Definitions.ql-10:DefinitionTracking::assignment_jump_to_defn_attribute#fbf ....................... 12.4s (99 evaluations with max 11.8s in DefinitionTracking::assignment_jump_to_defn_attribute#fbf/3@i2#fc1f
7z)
...
```

to

```
(668s)
Definitions.ql-7:Instances::InstanceObject::initializer_dispred#fbf ................... 35.4s (456 evaluations with max 140ms in Instances::InstanceObject::initializer_dispred#fbf/3@i110#bf4328)
Definitions.ql-10:DefinitionTracking::jump_to_defn_attribute#fbf ...................... 27.4s (100 evaluations with max 13.3s in DefinitionTracking::jump_to_defn_attribute#fbf/3@i1#679d7x)
Definitions.ql-7:PointsTo::PointsToInternal::pointsTo#ffff ............................ 16.1s (681 evaluations with max 2.5s in PointsTo::PointsToInternal::pointsTo#ffff/4@i4#bf432g)
Definitions.ql-7:Constants::ConstantObjectInternal::attribute#ffff .................... 14.4s (505 evaluations with max 51ms in Constants::ConstantObjectInternal::attribute#ffff/4@i140#bf4325)
Definitions.ql-10:DefinitionTracking::assignment_jump_to_defn_attribute#fbf ........... 12.3s (99 evaluations with max 11.7s in DefinitionTracking::assignment_jump_to_defn_attribute#fbf/3@i2#679d
7z)
...
```
2021-11-09 21:39:32 +00:00
Taus
e2f79d8516 Python: Fix several bad getScope joins
It seems the optimiser has started getting the wrong end of the stick
whenever we write `foo.getScope() = bar.getScope()` for some expressions
`foo` and `bar`.

This lead to things like

```
(196s) Tuple counts for Definitions::ModuleVariable::global_variable_callnode#ff/2@5ab278 after 2m33s:
2952757013 ~0%     {2} r1 = JOIN Definitions::ModuleVariable::global_variable_callnode#ff#shared WITH Variables::Variable::getScope_dispred#ff_10#join_rhs ON FIRST 1 OUTPUT Rhs.1 'this', Lhs.1 'result'
495693     ~0%     {2} r2 = JOIN r1 WITH Variables::GlobalVariable#class#f ON FIRST 1 OUTPUT Lhs.0 'this', Lhs.1 'result'
453589     ~0%     {2} r3 = JOIN r2 WITH Definitions::ModuleVariable#f ON FIRST 1 OUTPUT Lhs.0 'this', Lhs.1 'result'
                   return r3
```

and

```
(315s) Tuple counts for Definitions::SsaSourceVariable::getAUse_dispred#ff/2@a39328 after 1m57s:
...
1785275    ~3%       {2} r24 = Definitions::ModuleVariable::global_variable_callnode#ff#shared UNION Definitions::SsaSourceVariable::getAUse_dispred#ff#shared
3008614987 ~0%       {2} r25 = JOIN r24 WITH Variables::Variable::getScope_dispred#ff_10#join_rhs ON FIRST 1 OUTPUT Rhs.1 'this', Lhs.1 'result'
127        ~1%       {2} r26 = JOIN r25 WITH Definitions::NonLocalVariable#class#f ON FIRST 1 OUTPUT Lhs.0 'this', Lhs.1 'result'
127        ~1%       {2} r27 = JOIN r26 WITH Variables::LocalVariable#f ON FIRST 1 OUTPUT Lhs.0 'this', Lhs.1 'result'
...
```

(Note the timings: 2m33s and 1m57s.)

Now we have the much more reasonable

```
(38s) Tuple counts for Definitions::ModuleVariable::global_variable_callnode#ff/2@c53031 after 42ms:
453589 ~0%     {2} r1 = JOIN Definitions::ModuleVariable::global_variable_callnode#ff#shared WITH Definitions::ModuleVariable::scope_as_global_variable#ff_10#join_rhs ON FIRST 1 OUTPUT Rhs.1 'this', Lhs.1 'result'
               return r1
```

and

```
(46s) Tuple counts for Definitions::SsaSourceVariable::getAUse_dispred#ff/2@4b19de after 375ms:
...
```
2021-11-09 20:54:41 +00:00
Taus
24000a50e6 Python: Fix bad join in py/redundant-assignment
A minor thing, but still best avoided:
```
Tuple counts for RedundantAssignment::pyflakes_commented_line#bb/2@0477c7 after 14.2s:
160826   ~0%     {2} r1 = SCAN py_comments OUTPUT In.2, In.1
160826   ~0%     {3} r2 = JOIN r1 WITH project#Files::Location::hasLocationInfo_dispred#bfffff ON FIRST 1 OUTPUT Rhs.1, Lhs.1, Rhs.2 'result'
160826   ~3%     {3} r3 = JOIN r2 WITH files_10#join_rhs ON FIRST 1 OUTPUT Lhs.2 'result', Lhs.1, Rhs.1 'file'
46672419 ~4%     {4} r4 = JOIN r3 WITH Files::Location::getStartLine_dispred#bf_10#join_rhs ON FIRST 1 OUTPUT Rhs.1, Lhs.2 'file', Lhs.1, Lhs.0 'result'
3951     ~0%     {4} r5 = JOIN r4 WITH Files::Location::getFile_dispred#bf ON FIRST 2 OUTPUT Lhs.2, Lhs.3 'result', Lhs.1 'file', toLower(Lhs.2)
0        ~0%     {4} r6 = SELECT r5 ON In.3 contains "pyflakes"
0        ~0%     {2} r7 = SCAN r6 OUTPUT In.2 'file', In.1 'result'
                return r7
```
2021-11-09 20:31:44 +00:00
Geoffrey White
26e9adcc34 C++: Change note. 2021-11-09 19:39:21 +00:00
Geoffrey White
ef21d1b512 C++: Add a model for curl as well. 2021-11-09 19:32:43 +00:00
Geoffrey White
6388ac5f1d C++: Add tests. 2021-11-09 18:41:57 +00:00
Geoffrey White
d2b18d952d C++: Add qhelp. 2021-11-09 18:41:56 +00:00
Geoffrey White
bd1e708c5d C++: First version of cpp/non-https-url. 2021-11-09 18:33:49 +00:00
Rasmus Wriedt Larsen
985cd1ebdb Python: Port py/request-without-cert-validation to use API graphs 2021-11-09 16:37:50 +01:00
Rasmus Wriedt Larsen
59581690fd Python: Add py/request-without-cert-validation tests 2021-11-09 16:29:57 +01:00
Rasmus Wriedt Larsen
9710aeecbf Python/C#: Add CWE-1333 to redos queries
As is already done in JS and Ruby.
2021-11-09 16:10:38 +01:00
Anders Schack-Mulligen
1efe1e0d10 Java: Improve algorithm for subtyping of parameterized types. 2021-11-09 15:49:17 +01:00
Tom Hvitved
7178a98e45 Ruby: Rename pruneUseNode{Fwd,Rev} 2021-11-09 15:16:36 +01:00
Tom Hvitved
30251740e3 Ruby: Prune nodes before computing trackUseNode 2021-11-09 15:16:36 +01:00
Tom Hvitved
8195ebf4b3 Merge pull request #7059 from hvitved/ruby/basic-store-step-postupdate
Ruby: Fix `basicStoreStep`
2021-11-09 15:16:07 +01:00
Alex Ford
556cdbaa21 ruby: QL format 2021-11-09 14:09:11 +00:00
Alex Ford
37775407a9 ruby: drop a redundant bit of documentation 2021-11-09 14:07:00 +00:00
Alex Ford
340897f262 ruby: drop unnecessary variable 2021-11-09 14:06:21 +00:00
Alex Ford
a23750a9c7 ruby: inline some predicates 2021-11-09 14:06:21 +00:00
Benjamin Muskalla
40e47c0ea3 Merge pull request #7082 from bmuskalla/filterOutputStream
Java: Model taint for `FilterOutputStream`
2021-11-09 15:06:15 +01:00
Alex Ford
c65d1d9a50 ruby: CSRFProtectionDisabled.qhelp fixes
Co-authored-by: Harry Maclean <hmac@github.com>
2021-11-09 14:05:41 +00:00
Rasmus Wriedt Larsen
f70e4fea55 Python: Add interesting path-injection FP 2021-11-09 14:53:32 +01:00
Mathias Vorreiter Pedersen
10bca3544c C++: Change 'annotate_path_to_sink' so that you now annotate a ir-path with the previous node (instead of its source). This gives a better overview of the path. 2021-11-09 13:49:12 +00:00
Benjamin Muskalla
bfe2e2e0b9 Model taint for FilterOutputStream 2021-11-09 14:21:50 +01:00
Rasmus Wriedt Larsen
1e31416049 Merge pull request #7031 from yoff/python/taint-through-with
Python: Taint through `async with`
2021-11-09 14:08:07 +01:00
Alex Ford
c708b6b76f Merge pull request #7077 from github/ruby/downgrade-hardcoded-credentials
Ruby: Downgrade `rb/hardcoded-credentials` precision from high to medium
2021-11-09 12:08:10 +00:00
Rasmus Lerchedahl Petersen
ac5a46f24f Python: split test as suggested in review 2021-11-09 13:04:52 +01:00
yoff
5f4aad40c1 Update python/ql/test/experimental/meta/InlineTaintTest.qll
Co-authored-by: Rasmus Wriedt Larsen <rasmuswriedtlarsen@gmail.com>
2021-11-09 13:00:35 +01:00
Rasmus Lerchedahl Petersen
aa1541a5c3 Python: add changenote 2021-11-09 12:57:36 +01:00
Rasmus Lerchedahl Petersen
a58c47b07b Python: model aiopg.sa 2021-11-09 12:49:57 +01:00
Rasmus Lerchedahl Petersen
f53314019a Python: test aiopg.sa 2021-11-09 12:42:03 +01:00
CodeQL CI
d9d304fc13 Merge pull request #7076 from asgerf/js/tainted-path-regexp-guard2
Approved by erik-krogh
2021-11-09 03:40:37 -08:00
Rasmus Lerchedahl Petersen
cd332a75fc Python: model aiopg 2021-11-09 12:32:21 +01:00
Erik Krogh Kristensen
56a7c8b163 fix typo in change note
Co-authored-by: Asger F <asgerf@github.com>
2021-11-09 12:06:29 +01:00
Asger F
4b82840e9d Revert "JS: Skip files with unsupported file encoding" 2021-11-09 10:57:01 +00:00
Rasmus Lerchedahl Petersen
cb8f1b4593 Python: Add tests for aiopg 2021-11-09 11:49:31 +01:00
Geoffrey White
d9e02e83fe Merge pull request #6825 from MathiasVP/use-shared-ssa-in-ir-dataflow
C++: Redesign IR dataflow using the shared SSA library
2021-11-09 10:19:50 +00:00
James Fletcher
1bacce487e Merge pull request #7056 from jf205/sarif-query-help
Add new option to database analyze tutorial
2021-11-09 10:19:29 +00:00
CodeQL CI
954fd8d6f7 Merge pull request #7081 from github/revert-6924-js/skip-files-with-unsupported-encoding
Approved by esbena
2021-11-09 02:18:16 -08:00
Erik Krogh Kristensen
8727060ca7 add comment about modes of operation
Co-authored-by: Rasmus Wriedt Larsen <rasmuswriedtlarsen@gmail.com>
2021-11-09 11:15:12 +01:00
Asger Feldthaus
87aa39cef2 JS: Limited tracking of object literals with methods 2021-11-09 11:06:41 +01:00
Asger F
0c6680b2c0 Revert "JS: Skip files with unsupported file encoding" 2021-11-09 09:07:54 +00:00
ihsinme
55fe01018f Update InsecureTemporaryFile.ql 2021-11-09 09:33:33 +03:00
Asger Feldthaus
f14f9449ee JS: Use getAMatchedString instead of getConstantString 2021-11-08 15:35:35 +01:00
Asger Feldthaus
b3e64f1669 JS: Add test 2021-11-08 15:32:43 +01:00
Erik Krogh Kristensen
330c2c42b5 Merge pull request #7075 from erik-krogh/cwe297
JS: add cwe-297 to `js/disabling-certificate-validation`
2021-11-08 14:35:58 +01:00
Erik Krogh Kristensen
5cafb86c88 Merge pull request #7074 from erik-krogh/cwe942
JS: add cwe-942 to `js/cors-misconfiguration-for-credentials`
2021-11-08 14:35:53 +01:00
Rasmus Lerchedahl Petersen
3f4c2ba24e Python: Support debugging inline taint tests
The module `Conf` is created so that it can be imported
without importing the query predicates from the same file.
2021-11-08 14:08:11 +01:00
Anders Schack-Mulligen
1e0eb2f6e4 Merge pull request #7072 from aschackmull/java/nomagic-synchsetunsynchget
Java: Fix bad magic in SynchSetUnsynchGet.
2021-11-08 13:48:22 +01:00
Alex Ford
2581efc18a ruby: downgrade rb/hardcoded-credentials precision from high to medium 2021-11-08 12:32:38 +00:00
Erik Krogh Kristensen
a2175a3207 add cwe-297 to js/disabling-certificate-validation 2021-11-08 13:26:53 +01:00
Erik Krogh Kristensen
507c8addb2 add cwe-942 to js/cors-misconfiguration-for-credentials 2021-11-08 13:12:19 +01:00
Cornelius Riemenschneider
76d2665132 Merge pull request #7071 from github/criemen/simplify-csharp-tracing-config
C#: Remove macos compatibility stanzas from tracing config.
2021-11-08 13:11:44 +01:00
james
96ff2f5125 use correct type of link 2021-11-08 12:06:20 +00:00
james
dfe77f844f fix errors in debugging-data-flow-queries-using-partial-flow.rst 2021-11-08 11:59:53 +00:00
Erik Krogh Kristensen
0ab510f543 add test that requires flowToExpr 2021-11-08 12:25:45 +01:00
james
c94bfc306a improve links 2021-11-08 11:18:41 +00:00
Erik Krogh Kristensen
3d6a5263e0 improve qhelp
Co-authored-by: Esben Sparre Andreasen <esbena@github.com>
2021-11-08 12:02:39 +01:00
Mathias Vorreiter Pedersen
8e496f7121 C++: Pull in the latest changes to 'SsaImplCommon'. 2021-11-08 10:46:54 +00:00
Mathias Vorreiter Pedersen
fff5d293ff Merge branch 'main' into use-shared-ssa-in-ir-dataflow 2021-11-08 10:44:36 +00:00
Anders Schack-Mulligen
92fb7f555c Java: Fix bad magic in SynchSetUnsynchGet. 2021-11-08 11:42:20 +01:00
Cornelius Riemenschneider
03ff2c622a Remove macos compatibility stanzas from tracing config. 2021-11-08 11:30:31 +01:00
Anders Schack-Mulligen
613e971987 Merge pull request #7039 from github/turbo-js-java-lib-modeling-ghes-3-3-p-1
Add updated framework support for JS/Java
2021-11-08 11:08:34 +01:00
CodeQL CI
6f80387ac1 Merge pull request #6993 from asgerf/js/tainted-path-regexp-contains-check
Approved by erik-krogh
2021-11-08 01:52:28 -08:00
CodeQL CI
618d135b0a Merge pull request #7060 from RasmusWL/hashlib-new-type-tracker
Approved by yoff
2021-11-08 01:31:40 -08:00
Tom Hvitved
77aca0a365 Merge pull request #7041 from hvitved/csharp/consistent-ids
C#: Use `cs/` prefix in all query IDs
2021-11-08 09:55:11 +01:00
Anders Schack-Mulligen
85fdbda16f Merge pull request #7002 from aschackmull/java/field-node
Java: Add FieldValueNode to break up cartesian step relation.
2021-11-08 09:31:42 +01:00
Mathias Vorreiter Pedersen
021d9415b8 Merge branch 'main' into use-range-analysis-in-buffer-write 2021-11-08 08:22:49 +00:00
Anders Schack-Mulligen
e0b121cd90 Merge pull request #7047 from hvitved/csharp/ssa/dominance-frontier
Shared SSA: Improved dominance frontier calculation
2021-11-08 08:50:46 +01:00
Pierre
4af3775b72 Add requirements for Apple Silicon 2021-11-08 01:37:31 +01:00
Chris Smowton
b639e82d79 Merge pull request #7064 from github/workflow/coverage/update
Update CSV framework coverage reports
2021-11-05 09:27:25 +00:00
ihsinme
cedc5fd743 Update InsecureTemporaryFile.ql 2021-11-05 09:42:06 +03:00
github-actions[bot]
d7bfaec0f5 Add changed framework coverage reports 2021-11-05 00:09:28 +00:00
Mathias Vorreiter Pedersen
34aa4981be Merge pull request #7018 from geoffw0/nullterm3
C++: Further performance improvement for the null termination queries
2021-11-04 21:37:58 +00:00
Mathias Vorreiter Pedersen
a9b7fed537 C++: Accept test changes. 2021-11-04 21:25:37 +00:00
Mathias Vorreiter Pedersen
ac90259906 C++: Teach 'getMaxConvertedLength' to use 'SimpleRangeAnalysis'. 2021-11-04 21:25:28 +00:00
Mathias Vorreiter Pedersen
693baae1ba C++: Add test cases with false positives due to missing range analysis in 'cpp/overrunning-write'. 2021-11-04 21:13:28 +00:00
Alex Ford
5f78bbbf52 add missing documentation 2021-11-04 21:07:54 +00:00
Ethan Palm
f1ac23eff5 Merge pull request #7040 from ethanpalm/extractor-options-docs
New docs for extractor options
2021-11-04 13:53:22 -07:00
Ethan P
fab3479f68 Fix numbered lists 2021-11-04 13:41:59 -07:00
Ethan P
457ece152a Fix list formatting 2021-11-04 13:31:52 -07:00
Ethan P
5bfe0fff89 Test using dash for LIs 2021-11-04 13:20:00 -07:00
Ethan P
10e5a8b3e5 Adjust spacing 2021-11-04 13:18:37 -07:00
Alex Ford
543bd28b03 add a change note for rb/csrf-protection-disabled 2021-11-04 20:14:54 +00:00
Ethan P
ad2b068429 fix list formatting 2021-11-04 13:05:22 -07:00
Alex Ford
d324f9397c qhelp for rb/csrf-protection-disabled 2021-11-04 19:56:56 +00:00
Alex Ford
25da904314 test cases for rb/csrf-protection-disabled 2021-11-04 19:56:56 +00:00
Alex Ford
4666024419 model some ways to configure Rails 2021-11-04 19:56:56 +00:00
Alex Ford
91f99ed2a1 model skip_forgery_protection calls in ActionController classes 2021-11-04 19:56:56 +00:00
Alex Ford
fad7e9489b Add a query to detect instances of CSRF protection being disabled 2021-11-04 19:56:55 +00:00
Ethan P
f3fda42b83 Fix link 2021-11-04 12:53:03 -07:00
Ethan Palm
f41c4702c3 Apply suggestions from code review
Co-authored-by: Sarita Iyer <66540150+saritai@users.noreply.github.com>
2021-11-04 12:41:07 -07:00
Alex Ford
8a412dc5fd Add CSRFProtectionSetting concept 2021-11-04 18:18:29 +00:00
Rasmus Lerchedahl Petersen
624b794980 Python: separate taint sources in with 2021-11-04 17:06:36 +01:00
james
5ea93d6447 further imrpovements 2021-11-04 14:54:30 +00:00
Rasmus Wriedt Larsen
9e2bc41648 Python: Improve hashlib.new modeling
By using a backwards type-tracker to find possible hashing algorithm
names.
2021-11-04 15:36:32 +01:00
Rasmus Wriedt Larsen
9e91f3a341 Python: Highlight shortcomings of hashlib.new modeling 2021-11-04 15:29:40 +01:00
Ian Wright
95f21b5308 Merge pull request #7027 from github/z80coder/faster-callee-api-name-feature
more efficient implementation of calleeApiName
2021-11-04 14:23:13 +00:00
Tom Hvitved
3544c85445 Ruby: Make the target of basicStoreStep the post-update node 2021-11-04 14:21:22 +01:00
Tom Hvitved
1101b1054d Ruby: Make target of basicStoreStep a normal data flow node 2021-11-04 14:20:07 +01:00
Tom Hvitved
a56a5e4e7d Ruby: Add type tracker tests 2021-11-04 14:19:16 +01:00
james
7236f3b4b6 improve description of new option 2021-11-04 12:41:30 +00:00
james
af0f32fdb6 further changes for query help in sarif 2021-11-04 12:36:27 +00:00
Ian Wright
b8d7f52d3e format code 2021-11-04 12:28:08 +00:00
Erik Krogh Kristensen
a19627c72f optionally ignore everything after a dash 2021-11-04 13:19:44 +01:00
Erik Krogh Kristensen
02f500b9c2 Merge branch 'main' into htmlReg 2021-11-04 12:58:42 +01:00
Erik Krogh Kristensen
99f5f70345 Merge branch 'main' into protoLib 2021-11-04 12:53:53 +01:00
Erik Krogh Kristensen
bf5e36e9d4 fix docstring
Co-authored-by: Asger F <asgerf@github.com>
2021-11-04 12:46:24 +01:00
Mathias Vorreiter Pedersen
58f6058a63 Merge pull request #7051 from MathiasVP/better-paths-in-tests
C++: Better `InlineExpectation` tests for path-explanations
2021-11-04 11:35:10 +00:00
Erik Krogh Kristensen
4ba5ae09b0 add js/sensitive-get-query query 2021-11-04 12:30:44 +01:00
Arthur Baars
061fc16730 Merge pull request #7038 from aibaars/aibaars/merge-3.3-main
Merge rc/3.3 into main
2021-11-04 12:23:23 +01:00
Mathias Vorreiter Pedersen
0d1ff4d2ee C++: Respond to review comments and accept test changes. 2021-11-04 11:13:23 +00:00
Arthur Baars
27bbddf035 Merge pull request #6995 from aibaars/aibaars/pr-qhelp-check
Rewrite qhelp-pr-preview.yml
2021-11-04 11:51:14 +01:00
CodeQL CI
2895428d5b Merge pull request #6714 from valeria-meli/javascript/ssrf
Approved by asgerf
2021-11-04 03:10:27 -07:00
james
3bfa868105 add new option to database analyze tutorial 2021-11-04 09:53:32 +00:00
CodeQL CI
5515256e53 Merge pull request #7044 from asgerf/js/proto-pollution-fps
Approved by erik-krogh
2021-11-04 02:45:46 -07:00
Tony Torralba
f4704f1325 Merge pull request #6397 from atorralba/atorralba/android-intent-redirect-query
Java: Create new Android Intent Redirection query
2021-11-04 10:42:59 +01:00
Tony Torralba
fd92c4e435 Apply suggestions from code review
Co-authored-by: Anders Schack-Mulligen <aschackmull@users.noreply.github.com>
2021-11-04 10:08:53 +01:00
Mathias Vorreiter Pedersen
ae4b6c54bc C++: Change the structure of the 'annotate_path_to_sink' tests to better test path-explanations. 2021-11-03 20:32:05 +00:00
Mathias Vorreiter Pedersen
e9b114630a Merge pull request #6948 from ihsinme/ihsinme-patch-076
CPP: Add query for CWE-243 Creation of chroot Jail Without Changing Working Directory
2021-11-03 18:50:13 +00:00
ihsinme
aef0275b3c Update IncorrectChangingWorkingDirectory.expected 2021-11-03 20:45:38 +03:00
Arthur Baars
7b4460edb7 Apply suggestions from code review
Co-authored-by: Aditya Sharad <6874315+adityasharad@users.noreply.github.com>
2021-11-03 18:42:49 +01:00
Tom Hvitved
d00196f6be Merge pull request #7048 from hvitved/ruby/remove-node-predicates
Ruby: Remove `Node::getEnclosingCallable` and `ParameterNode::isParameterOf`
2021-11-03 17:46:16 +01:00
Ethan P
0894e81ce4 add missing backtick 2021-11-03 09:21:24 -07:00
ihsinme
a9dd868348 Update IncorrectChangingWorkingDirectory.qhelp 2021-11-03 18:38:30 +03:00
ihsinme
c94b64cbca Update IncorrectChangingWorkingDirectory.qhelp 2021-11-03 18:28:57 +03:00
Tom Hvitved
16d96d2ad3 Ruby: Remove Node::getEnclosingCallable and ParameterNode::isParameterOf 2021-11-03 15:59:29 +01:00
Arthur Baars
b9bf597044 Address comments 2021-11-03 15:15:36 +01:00
Erik Krogh Kristensen
523c15cd72 don't include mode-of-operation into the algorithm names 2021-11-03 14:54:50 +01:00
luciaromeroML
e50938588e formatting qll file 2021-11-03 10:30:35 -03:00
Mathias Vorreiter Pedersen
4095c2012e C++: Add comments on why 'ReferenceToInstruction' is interpreted like a 'LoadInstruction' at certain places. 2021-11-03 13:27:26 +00:00
Tom Hvitved
df6962143d Shared SSA: Sync files 2021-11-03 14:21:50 +01:00
Tom Hvitved
5539b7ffed Shared SSA: Improved dominance frontier calculation 2021-11-03 14:21:39 +01:00
Erik Krogh Kristensen
3638892d35 Merge pull request #6881 from erik-krogh/add-missing-noinline
JS: add pragma[noinline] to predicates where the qldoc mentions join-order
2021-11-03 14:21:27 +01:00
Mathias Vorreiter Pedersen
43a4795272 C++: Remove redundant conjunct. 2021-11-03 13:19:43 +00:00
Erik Krogh Kristensen
f01ee5914b add a docstring, and rename rawString -> foldedString 2021-11-03 14:19:31 +01:00
Rasmus Wriedt Larsen
84b38b6c32 Python: Add test with custom django json response (FP) 2021-11-03 14:17:08 +01:00
Erik Krogh Kristensen
7b0ebd3f1a use the context to determine whether or not a node is an operand of a binop 2021-11-03 14:09:44 +01:00
Arthur Baars
ddc9ad3187 Merge remote-tracking branch 'upstream/rc/3.3' into main 2021-11-03 14:01:51 +01:00
Arthur Baars
1327d7c8d5 Merge pull request #7043 from aibaars/fix-ql-tests-3.3
Ruby: Fix QL tests and Rust compilation error
2021-11-03 13:59:29 +01:00
Asger Feldthaus
712614a03c JS: Block prototype pollution flow into this 2021-11-03 13:33:50 +01:00
Erik Krogh Kristensen
737c747dbb early exit if string becomes too big 2021-11-03 13:28:03 +01:00
Erik Krogh Kristensen
1ba6f448cd compute concatenated string and offset at the same time 2021-11-03 13:26:19 +01:00
Erik Krogh Kristensen
be46c1f679 remove unused import 2021-11-03 13:25:09 +01:00
Asger Feldthaus
08bc80ffdb JS: Block prototype pollution assignment flows through .replace() 2021-11-03 13:24:29 +01:00
Mathias Vorreiter Pedersen
1f89b4987b C++: Rename 'valueFlow' to 'conversionFlow' and add a QLDoc that explains its purpose. 2021-11-03 12:22:27 +00:00
Asger Feldthaus
76e841830f JS: Check for labeled barriers in reachableFromInput 2021-11-03 13:10:20 +01:00
Erik Krogh Kristensen
9cf34f19bb Merge branch 'main' into extractBigReg 2021-11-03 13:08:51 +01:00
Erik Krogh Kristensen
264f4ab5ab add js/session-fixation query 2021-11-03 13:04:41 +01:00
Nick Rolfe
dd17271ec8 Merge remote-tracking branch 'origin/main' into nickrolfe/regex_injection 2021-11-03 11:55:42 +00:00
Arthur Baars
aab8c64973 Ruby: fix compilation error 2021-11-03 12:32:45 +01:00
Arthur Baars
2c5d5ecdd8 Ruby: QLTest: fix pack search path for upgrades 2021-11-03 12:14:58 +01:00
Arthur Baars
32765e9bc1 Ruby: trigger jobs on workflow change 2021-11-03 12:14:58 +01:00
Mathias Vorreiter Pedersen
dfbfbe4953 Merge branch 'main' into use-shared-ssa-in-ir-dataflow 2021-11-03 10:39:22 +00:00
Mathias Vorreiter Pedersen
ad5619ff07 Revert "C++: Don't count write operations as uses."
This reverts commit 092beb8b73.
2021-11-03 10:37:32 +00:00
Tom Hvitved
ab37ae6613 Merge pull request #7036 from hvitved/ruby/truncate-get-value-text
Ruby: Truncate concatenated strings in `getValueText`
2021-11-03 10:57:43 +01:00
Rasmus Lerchedahl Petersen
05aa314ac9 Python: Add tests for non-async constructs 2021-11-03 10:54:36 +01:00
ihsinme
c175f0aa9d Update IncorrectChangingWorkingDirectory.ql 2021-11-03 12:25:30 +03:00
Tom Hvitved
51f4f57617 C#: Use cs/ prefix in all query IDs 2021-11-03 10:25:21 +01:00
Anders Schack-Mulligen
e6145f04d2 Merge pull request #6966 from atorralba/atorralba/android-explicit-intent-sanitizer
Android: Add ExplicitIntentSanitizer and allowIntentExtrasImplicitRead
2021-11-03 10:20:09 +01:00
Erik Krogh Kristensen
ab4780c505 Merge pull request #7032 from erik-krogh/cwe497
JS: add CWE-497 to js/stack-trace-exposure
2021-11-03 08:55:49 +01:00
Ethan P
b9eb278380 Add new file to index 2021-11-02 21:55:25 -07:00
Ethan P
98eb848e22 add link to new article 2021-11-02 21:35:39 -07:00
Ethan P
06cacfdd83 Create extractor-options.rst 2021-11-02 21:21:31 -07:00
Pierre
cf5b317eb1 Add updated framework support for JS/Java
Release: https://github.com/github/releases/issues/1724
2021-11-02 22:02:05 +01:00
Mathias Vorreiter Pedersen
4a2894a707 Merge pull request #7025 from MathiasVP/nomagic-parameterCand
Dataflow: Replace a 'noinline' pragma with a 'nomagic' pragma
2021-11-02 20:40:44 +00:00
Arthur Baars
eb645ba963 Merge remote-tracking branch 'origin/rc/3.3' into 'main' 2021-11-02 21:10:41 +01:00
Tom Hvitved
8b287a7846 Ruby: Truncate concatenated strings in getValueText 2021-11-02 18:19:49 +01:00
Erik Krogh Kristensen
9d99ce12c4 add CWE-497 to js/stack-trace-exposure 2021-11-02 15:43:55 +01:00
Rasmus Wriedt Larsen
8cd9fdebf9 Python: Model flask_admin 2021-11-02 15:43:13 +01:00
Rasmus Wriedt Larsen
ab88d945e2 Python: Add flask_admin tests 2021-11-02 15:41:57 +01:00
Rasmus Wriedt Larsen
c2632cff3d Python: Add RequestHandler meta query 2021-11-02 15:41:57 +01:00
Rasmus Lerchedahl Petersen
768932d7b3 Python: Add tainttracking step that was removed
when the correpsonding datadlow step was removed.
2021-11-02 15:01:47 +01:00
Rasmus Lerchedahl Petersen
07d5086b07 Python: support user defined taint source 2021-11-02 15:00:23 +01:00
Dave Bartolomeo
d828ab7fd2 Merge pull request #6955 from github/codeql-ruby-3.3
RC 3.3: merge codeql-ruby repository into github/codeql
2021-11-02 09:57:49 -04:00
Erik Krogh Kristensen
5975e19f53 sync identical files 2021-11-02 14:45:33 +01:00
Erik Krogh Kristensen
2a8807efe4 add change note 2021-11-02 14:45:33 +01:00
Erik Krogh Kristensen
076a3dca1f add qhelp 2021-11-02 14:45:33 +01:00
Erik Krogh Kristensen
d9a214767b add support for node-rsa 2021-11-02 14:45:33 +01:00
Erik Krogh Kristensen
49ea53f32b move ExpressJwt that was inside the Hasha module 2021-11-02 14:45:33 +01:00
Erik Krogh Kristensen
2c013214f7 add Diffie-Hellman from the crypto library 2021-11-02 14:45:33 +01:00
Erik Krogh Kristensen
1df8ec2cae add insufficient key size model for node-forge 2021-11-02 14:45:33 +01:00
Erik Krogh Kristensen
62039b866c add cryptographic key model to the crypto-js library 2021-11-02 14:45:33 +01:00
Erik Krogh Kristensen
028799deb6 implement a simple InsufficientKeySize query 2021-11-02 14:45:30 +01:00
Erik Krogh Kristensen
7a9315f146 use set literal 2021-11-02 14:45:14 +01:00
yoff
97625d7c2c Merge pull request #7023 from RasmusWL/toml
Python: Add modeling of `toml`
2021-11-02 14:42:06 +01:00
Rasmus Wriedt Larsen
cb6bcada4c Merge branch 'main' into django-rest-framework 2021-11-02 14:33:16 +01:00
ihsinme
62b3c3c9a0 Update IncorrectChangingWorkingDirectory.ql 2021-11-02 16:16:17 +03:00
yoff
0240631510 Merge pull request #6782 from RasmusWL/fastapi
Python: Model FastAPI
2021-11-02 14:16:12 +01:00
ihsinme
738354b8e7 Update cpp/ql/src/experimental/Security/CWE/CWE-243/IncorrectChangingWorkingDirectory.ql
Co-authored-by: Mathias Vorreiter Pedersen <mathiasvp@github.com>
2021-11-02 16:13:34 +03:00
Asger Feldthaus
971f032b5f JS: Autoformat 2021-11-02 14:12:05 +01:00
Asger Feldthaus
46bd3e58a3 JS: Switch to instanceof base type 2021-11-02 14:12:05 +01:00
Asger Feldthaus
5f4c1dd19b JS: Support regexp-based path traversal check 2021-11-02 14:12:05 +01:00
Asger Feldthaus
83edcf515b JS: Add test for regexp-based sanitizer 2021-11-02 14:12:04 +01:00
Mathias Vorreiter Pedersen
3e6ac74d73 C++: Add 'InheritanceConversionInstruction' to the list of instructions that set 'certain = false' in 'explicitWrite'. 2021-11-02 13:02:46 +00:00
Mathias Vorreiter Pedersen
56cabb8f46 C++: Add comments to some of the disjuncts in 'addressFlow'. 2021-11-02 12:52:11 +00:00
Rasmus Wriedt Larsen
c52e453342 Python: Minor rewrite 2021-11-02 13:37:50 +01:00
Erik Krogh Kristensen
54fba2d6a1 Merge pull request #6781 from erik-krogh/ldap
JS: Move LDAP injection out of experimental
2021-11-02 13:35:32 +01:00
Anders Schack-Mulligen
7d0152f3c0 Merge pull request #6932 from aschackmull/dataflow/flow-features
Dataflow: Add support for call context restrictions on sources/sinks.
2021-11-02 13:24:17 +01:00
Ian Wright
6fa9413f8b more efficient implementation of calleeApiName 2021-11-02 12:05:33 +00:00
Nick Rolfe
6dd5dad4a9 Merge pull request #7026 from github/nickrolfe/rb-prefix
Ruby: use the `rb/` prefix in all query ids
2021-11-02 12:04:50 +00:00
Arthur Baars
18a47227b3 Remove redundant permissions block 2021-11-02 13:04:45 +01:00
Erik Krogh Kristensen
f7f315adbb Merge pull request #7022 from erik-krogh/cwe319
JS: add cwe-319 to js/clear-text-cookie
2021-11-02 12:47:53 +01:00
Erik Krogh Kristensen
7a96b8e9e1 Merge branch 'main' into ldap 2021-11-02 12:47:28 +01:00
Nick Rolfe
898f5ec596 Ruby: use the rb/ prefix in all query ids 2021-11-02 11:42:02 +00:00
Mathias Vorreiter Pedersen
6f4107ff23 Dataflow: Replace a 'noinline' pragma with a 'nomagic' pragma. 2021-11-02 11:37:40 +00:00
Arthur Baars
53b03152f3 Use 'gh' command to download artifacts 2021-11-02 12:01:14 +01:00
Arthur Baars
501ff12abb Use NUL character as separator 2021-11-02 12:01:13 +01:00
Arthur Baars
d1852af7b6 Add error messages 2021-11-02 12:00:11 +01:00
Mathias Vorreiter Pedersen
092beb8b73 C++: Don't count write operations as uses. 2021-11-02 10:59:34 +00:00
Rasmus Wriedt Larsen
8ee804a8c2 Python: Add toml modeling 2021-11-02 11:57:15 +01:00
Rasmus Wriedt Larsen
14bc297946 Python: Add toml encode/decode test 2021-11-02 11:57:06 +01:00
Geoffrey White
c1de4165a9 Update cpp/ql/lib/semmle/code/cpp/commons/NullTermination.qll
Co-authored-by: Mathias Vorreiter Pedersen <mathiasvp@github.com>
2021-11-02 10:51:35 +00:00
Erik Krogh Kristensen
41e7dea943 add cwe-319 "Cleartext Transmission of Sensitive Information" to js/clear-text-cookie 2021-11-02 11:11:38 +01:00
Rasmus Wriedt Larsen
83389be8e2 Python: Add some missing QLDocs 2021-11-02 11:02:51 +01:00
Rasmus Wriedt Larsen
5c2734c643 Python: Fix experimental Django.qll 2021-11-02 10:55:44 +01:00
Rasmus Wriedt Larsen
fd12b144bc Python: Add change-note 2021-11-02 10:55:44 +01:00
Rasmus Wriedt Larsen
a7e4e5ef83 Python: Add rest_framework Response modeling 2021-11-02 10:55:44 +01:00
Rasmus Wriedt Larsen
13815fe728 Python: Model known APIView subclasses
Added internal helper `.qll` file as well
2021-11-02 10:55:44 +01:00
Rasmus Wriedt Larsen
62d30630aa Python: Add rest_framework Request taint modeling 2021-11-02 10:55:44 +01:00
Rasmus Wriedt Larsen
5d77e62f3a Python: Add basic rest_framework Request modeling 2021-11-02 10:55:44 +01:00
Rasmus Wriedt Larsen
57e13c6066 Python: rest_framework.decorators.api_view handling
Had to expose even more things, and had to make the `DjangoRouteHandler`
modeling more flexible so I could extend the char-pred in a different
file.
2021-11-02 10:55:44 +01:00
Rasmus Wriedt Larsen
222db37c0d Python: Add initial rest_framework modeling
I had to make the Django and PrivateDjango modeling non-private :O
2021-11-02 10:55:44 +01:00
Rasmus Wriedt Larsen
a64e939d71 Python: Add note about .method 2021-11-02 10:55:44 +01:00
Rasmus Wriedt Larsen
75e2555a8a Python: Add rest_framework taint tests 2021-11-02 10:55:44 +01:00
Rasmus Wriedt Larsen
095f896f95 Python: Add examples of class/function based views 2021-11-02 10:55:44 +01:00
Rasmus Wriedt Larsen
9bbf08ddcf Python: Add simple Django REST framework code 2021-11-02 10:55:44 +01:00
Rasmus Wriedt Larsen
9d843153d4 Python: Set up test for Django REST framework
this is just pure Django project for now, (and very much a copy of the
one in `django-v2-v3`), to make it easier to see the changes needed to
set up Django REST framework.
2021-11-02 10:55:44 +01:00
Rasmus Wriedt Larsen
f1307b772a Python: Add RequestHandler meta query 2021-11-02 10:55:44 +01:00
Rasmus Wriedt Larsen
b7b9120724 Python: Better handling of Pydantic models 2021-11-02 10:29:17 +01:00
Rasmus Wriedt Larsen
c207580ed9 Python: Add extra FastAPI taint tests 2021-11-02 10:20:09 +01:00
Rasmus Wriedt Larsen
17da28118a Python: Small refactor to use extends .. instanceof 2021-11-02 10:06:11 +01:00
ihsinme
9b8b916199 Update IncorrectChangingWorkingDirectory.ql 2021-11-02 11:33:29 +03:00
Geoffrey White
dec7f93097 C++: Eliminate mutual recursion. 2021-11-01 17:32:38 +00:00
Geoffrey White
d6a714cf69 C++: Improve comments. 2021-11-01 17:32:37 +00:00
Erik Krogh Kristensen
db40ccae81 add explicit this to all member calls 2021-11-01 09:51:15 +01:00
ihsinme
3161d112d1 Update IncorrectChangingWorkingDirectory.ql 2021-10-30 13:47:22 +03:00
Mathias Vorreiter Pedersen
d34e731f1d C++: Add a small QLDoc novel above the IPA type for 'TIRDataFlowNode'. 2021-10-30 11:29:07 +01:00
Mathias Vorreiter Pedersen
d624259eab C++: Add QLDoc to 'flowOutOfAddressStep'. 2021-10-30 10:46:39 +01:00
Mathias Vorreiter Pedersen
a75f195df3 C++: Several readability fixes:
1. Added lots of QLDoc explanation about the role of StoreNodeOperand.
  2. Renamed '{StoreNode,ReadNode}.getAPredecessor' to 'getInner' and
     '{StoreNode,ReadNode}.getASuccessor' to 'getOuter'.
  3. Be more explicit about which type of 'StoreNode' is used in various
     places.
2021-10-30 10:24:06 +01:00
Mathias Vorreiter Pedersen
f334201fce Update cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/DataFlowUtil.qll
Co-authored-by: Jonas Jensen <jbj@github.com>
2021-10-30 10:04:17 +01:00
Mathias Vorreiter Pedersen
cb4f10c609 C++: Move the union field check to the IPA branch of 'TFieldContent'. 2021-10-30 10:04:17 +01:00
Arthur Baars
9604cd5595 Revert "Don't use local actions"
This reverts commit b128c7ca00.
2021-10-29 18:22:45 +02:00
Arthur Baars
a0903c377d Use pull_request + workflow_run instead of pull_request_target 2021-10-29 18:18:06 +02:00
Mathias Vorreiter Pedersen
8a569da370 C++: Fix comments. 2021-10-29 14:05:34 +01:00
Anders Schack-Mulligen
35b6cbe549 Java: Fix compilation error. 2021-10-29 14:26:36 +02:00
Anders Schack-Mulligen
e51a10a816 Java: Fix tests. 2021-10-29 14:25:43 +02:00
Rasmus Wriedt Larsen
7e7c363e43 Python: Apply suggestions from code review
Co-authored-by: yoff <lerchedahl@gmail.com>
2021-10-29 13:59:36 +02:00
Anders Schack-Mulligen
abf508eeeb Java: Add FieldValueNode to break up cartesian step relation. 2021-10-29 13:45:56 +02:00
Nick Rolfe
fed0a06353 Ruby: add change note for rb/regexp-injection 2021-10-29 11:28:34 +01:00
Max Schaefer
bc91f664ac JavaScript: Teach API graphs to handle some forms of property copying.
In particular, copied promises are now handled better.
2021-10-29 11:19:54 +01:00
ihsinme
635a668670 Update IncorrectChangingWorkingDirectory.ql 2021-10-29 10:08:41 +03:00
ihsinme
c8a4a8b965 Update InsecureTemporaryFile.ql 2021-10-29 09:44:43 +03:00
Ethan P
5f73fb21b8 Add new article to ref page 2021-10-28 10:55:44 -07:00
Mathias Vorreiter Pedersen
490156d7db C++: Remove the 'isIndirection' predicate on 'SourceVariable' and move the rootdef of 'getIRVariable' into the two subclasses. 2021-10-28 17:26:28 +01:00
Mathias Vorreiter Pedersen
05900cda87 C++: Rename 'Ssa' to 'SsaInternals' and move definitions from 'SSaImplSpecific' to 'SsaInternals'. Now we can avoid cyclic imports. 2021-10-28 17:10:48 +01:00
jorgectf
47b14f1adc Polish Concepts.qll qldocs 2021-10-28 17:55:34 +02:00
jorgectf
b3ec82cd36 Merge branch 'jorgectf/python/jwt-queries' of https://github.com/jorgectf/codeql into jorgectf/python/jwt-queries 2021-10-28 17:40:33 +02:00
jorgectf
a6c285ad32 Apply getItem(_) and extend verifiesSignature readability 2021-10-28 17:40:27 +02:00
Jorge
f4d63cc5e7 Apply suggestions from code review
Co-authored-by: Taus <tausbn@github.com>
2021-10-28 17:34:11 +02:00
jorgectf
ef4a27ff8c Apply code review suggestions 2021-10-28 17:31:52 +02:00
Mathias Vorreiter Pedersen
675e284c0e C++: A 'LoadInstruction' in a store chain always sets 'certain = false'. 2021-10-28 14:52:57 +01:00
Mathias Vorreiter Pedersen
ee2541c3bc C++: Fix QLDoc on 'getDestinationAddress'. 2021-10-28 14:12:22 +01:00
Mathias Vorreiter Pedersen
cde80ccf83 Replace 'hasLocationInfo' with 'getLocation'. 2021-10-28 14:09:26 +01:00
Mathias Vorreiter Pedersen
387c96d1e2 Rename 'SourceVariable.getVariable' to 'SourceVariable.getIRVariable' and replace 'Def.getVariable' to 'Def.getSourceVariable'. 2021-10-28 14:00:50 +01:00
Rasmus Lerchedahl Petersen
7201b3e116 Python: add changenote 2021-10-28 14:48:48 +02:00
Rasmus Lerchedahl Petersen
8536f5f5a2 Python: remember to update refs... 2021-10-28 14:32:53 +02:00
Erik Krogh Kristensen
4f6e5c903b filter out writes to number indexes 2021-10-28 14:27:07 +02:00
Mathias Vorreiter Pedersen
12e0185b0d C++: Sync identical files. 2021-10-28 12:36:36 +01:00
Mathias Vorreiter Pedersen
7197216185 Add a copy of SsaImplCommon to the identical-files script. 2021-10-28 12:36:36 +01:00
Mathias Vorreiter Pedersen
fc3ff41d65 Merge branch 'main' into use-shared-ssa-in-ir-dataflow 2021-10-28 12:36:36 +01:00
Mathias Vorreiter Pedersen
2cd23e5ee0 Accept test changes. 2021-10-28 12:36:36 +01:00
Mathias Vorreiter Pedersen
8135dcefdd Merge branch 'main' into use-shared-ssa-in-ir-dataflow 2021-10-28 12:36:25 +01:00
Mathias Vorreiter Pedersen
521d863429 C++: Autoformat. 2021-10-28 12:35:01 +01:00
Mathias Vorreiter Pedersen
2547a8d746 C++: Fix join orders in 'DataFlowDispatch.qll' and Ssa.qll. 2021-10-28 12:35:01 +01:00
Mathias Vorreiter Pedersen
21a1ee7758 C++: Add annoying case in SSA.qll related to 'NewExpr' and accept test changes. 2021-10-28 12:35:01 +01:00
Mathias Vorreiter Pedersen
3efe60fdd2 C++: Accept test changes. 2021-10-28 12:35:01 +01:00
Mathias Vorreiter Pedersen
5dbaea8b52 C++: Add a special dataflow step from InitializeIndirection instructions. 2021-10-28 12:35:01 +01:00
Mathias Vorreiter Pedersen
b1ea00fa85 C++: Remove the taintflow edges that gives performance problems. 2021-10-28 12:35:01 +01:00
Mathias Vorreiter Pedersen
710d0cfc3d C++: Since we now no longer have flow from exact memory operands to LoadInstructions, we no longer have flow from PhiInstructions to LoadInstructions. We could allow flow in this particular case, but we might as well use the shared SSA library's phi edges. 2021-10-28 12:35:00 +01:00
Mathias Vorreiter Pedersen
8caff41138 C++: Throw away most of the usage of IR-computed def-use information. Instead, we rely on the shared SSA library's use-use edges. 2021-10-28 12:35:00 +01:00
Mathias Vorreiter Pedersen
3a488574e5 C++: Rewrite the PartialDefinitionNode classes to match the new StoreNodes. 2021-10-28 12:35:00 +01:00
Mathias Vorreiter Pedersen
8bef79502f C++: Similarly to the previous commit, we throw away the old memory-edges based way of doing read steps. Instead, we use the shared SSA library to transfer flow into a new ReadNode IPA branch, perform the necessary read steps, and then use the shared SSA library to transfer flow out of the ReadNode again. 2021-10-28 12:35:00 +01:00
Mathias Vorreiter Pedersen
5ebefe2d30 C++: Throw away the old way of doing store steps using memory edges. Instead, we introduce a StoreNode IPA branch that does store steps and instead use the shared SSA library to transfer flow into these nodes before a store step, and out of them following a sequence of store steps. 2021-10-28 12:35:00 +01:00
jorgectf
3dec222922 Merge remote-tracking branch 'origin/main' into jorgectf/python/jwt-queries 2021-10-28 13:11:46 +02:00
jorgectf
7069f45864 Polish documentation 2021-10-28 13:09:28 +02:00
Mathias Vorreiter Pedersen
1842fed7a2 C++: Add shared SSA library and instantiate it with the IR. 2021-10-28 10:52:09 +01:00
Mathias Vorreiter Pedersen
13ce2569d7 C++/C#: Sync identical IR files· 2021-10-28 10:52:00 +01:00
Mathias Vorreiter Pedersen
bccd4e9e93 C++: Add 'getReturnAddress' and 'getReturnAddressOperand' predicates to 'ReturnValueInstruction'. 2021-10-28 10:51:49 +01:00
Nick Rolfe
bd92403b42 Ruby: fix qhelp 2021-10-28 10:42:56 +01:00
Rasmus Wriedt Larsen
3fa66519f5 Merge branch 'main' into fastapi 2021-10-28 11:37:40 +02:00
Erik Krogh Kristensen
12305aae42 extract regexp literals from string concatenations 2021-10-28 10:44:33 +02:00
Arthur Baars
3fb0139430 Protect against flag injection 2021-10-28 09:58:10 +02:00
ihsinme
2574aa8980 Update InsecureTemporaryFile.ql 2021-10-28 10:51:48 +03:00
ihsinme
432fc74455 Apply suggestions from code review
Co-authored-by: Mathias Vorreiter Pedersen <mathiasvp@github.com>
2021-10-28 10:37:01 +03:00
ihsinme
235a3ec232 Update InsecureTemporaryFile.qhelp 2021-10-28 10:34:42 +03:00
ihsinme
0addb2d1ea Update IncorrectChangingWorkingDirectory.ql 2021-10-28 10:17:48 +03:00
ihsinme
c3b1d7e5c8 Apply suggestions from code review
Co-authored-by: Mathias Vorreiter Pedersen <mathiasvp@github.com>
2021-10-28 10:17:13 +03:00
Erik Krogh Kristensen
96b6f670d9 filter away paths that start with libary inputs and end with a fixed-property write 2021-10-27 21:01:11 +02:00
Erik Krogh Kristensen
78371894f4 update import after rebasing on main 2021-10-27 20:47:06 +02:00
Erik Krogh Kristensen
a9a9e34265 recognize delete expresssions as a sink for js/prototype-polluting-assignment 2021-10-27 20:37:42 +02:00
Erik Krogh Kristensen
1243c736dd use ConcatenationNode::isCoercion 2021-10-27 20:37:42 +02:00
Erik Krogh Kristensen
2dedfb302a remove paths without unmatched returns from js/prototype-polluting-assignment 2021-10-27 20:37:42 +02:00
Erik Krogh Kristensen
0c9c9bbde7 detect library input when the arguments object is converted to an array 2021-10-27 20:37:41 +02:00
Erik Krogh Kristensen
fa9e9dd847 split out predicates in ClassifyFiles to avoid unnecessary computations 2021-10-27 20:35:38 +02:00
Erik Krogh Kristensen
3d124cf95e add change-note 2021-10-27 20:35:38 +02:00
Erik Krogh Kristensen
d1238dfd8b update alert message to distinguish between library input and remote flow 2021-10-27 20:35:38 +02:00
Erik Krogh Kristensen
6e183af383 ignore test files for the `prototypeLessObject' predicate 2021-10-27 20:35:37 +02:00
Erik Krogh Kristensen
e94b0f5913 recognize inclusion based sanitizers for js/prototype-polluting-assignment 2021-10-27 20:35:37 +02:00
Erik Krogh Kristensen
2a808b2cd6 track taint through string coercions for js/prototype-polluting-assignment 2021-10-27 20:35:37 +02:00
Erik Krogh Kristensen
2d65aa17db recognize exported functions that use the arguments object 2021-10-27 20:35:37 +02:00
Erik Krogh Kristensen
78774233c7 add library input as source to js/prototype-polluting-assignment 2021-10-27 20:35:36 +02:00
Arthur Baars
5e2cab4fb1 Split workflow into separate jobs 2021-10-27 19:06:22 +02:00
Erik Krogh Kristensen
71cca6d644 Merge branch 'main' into ldap 2021-10-27 19:06:06 +02:00
Erik Krogh Kristensen
2e912ee28e rename LDAP to Ldap 2021-10-27 19:05:56 +02:00
Erik Krogh Kristensen
c1ab49fe8a rename LDapFilterStep to TaintPreservingLDapFilterStep 2021-10-27 19:05:00 +02:00
jorgectf
350cbb4c5d Polish qhelp and libraries 2021-10-27 18:47:19 +02:00
Nick Rolfe
11154a9409 Ruby: add regex injection query 2021-10-27 15:58:12 +01:00
Arthur Baars
aeedfd9987 Filter out non-qhelp files 2021-10-27 16:00:19 +02:00
Arthur Baars
b128c7ca00 Don't use local actions 2021-10-27 15:57:54 +02:00
Arthur Baars
19e010e6fe fetch-codeql action: unzip in runner.temp 2021-10-27 15:57:54 +02:00
Anders Schack-Mulligen
6eabb610b4 Dataflow: Sync Ruby 2021-10-27 13:58:30 +02:00
Anders Schack-Mulligen
699630af54 Dataflow: Sync. 2021-10-27 13:57:44 +02:00
Anders Schack-Mulligen
92e4a1ed17 Dataflow: Review fixes. 2021-10-27 13:57:44 +02:00
Anders Schack-Mulligen
034c7f3538 Dataflow: Sync. 2021-10-27 13:57:44 +02:00
Anders Schack-Mulligen
51cebdce83 Dataflow: Add support for call context restrictions on sources/sinks. 2021-10-27 13:57:44 +02:00
Arthur Baars
ce3a19458d Set persist-credentials: false 2021-10-27 13:30:22 +02:00
Arthur Baars
54e946918a QHelp preview: run if paths.txt is non-empty 2021-10-27 12:47:51 +02:00
Arthur Baars
8077a49109 Switch qhelp-pr-preview.yml to pull_request_target 2021-10-27 12:38:52 +02:00
Rasmus Lerchedahl Petersen
fed6a97eb8 Python: Promote ReDoS queries 2021-10-27 11:03:57 +02:00
Tony Torralba
6f7d0b62d7 Add ExplicitIntentSanitizer and allowIntentExtrasImplicitRead 2021-10-26 17:11:27 +02:00
Erik Krogh Kristensen
8a4b043cb1 fix imports 2021-10-26 15:39:45 +02:00
Rasmus Wriedt Larsen
29e3abc977 Python: FastAPI: Add HTTP header taint example 2021-10-26 15:34:16 +02:00
Erik Krogh Kristensen
62e729501c make the RegExpEscape::getUnescaped predicate public in python 2021-10-26 15:25:14 +02:00
Erik Krogh Kristensen
97264b5dda add the bad tag filter query to ruby 2021-10-26 15:25:12 +02:00
Erik Krogh Kristensen
c15ddf6e92 update ReDoSUtil in ruby 2021-10-26 15:03:09 +02:00
Erik Krogh Kristensen
2ddf445caf move ruby files to match file structure from js/py 2021-10-26 14:54:12 +02:00
Erik Krogh Kristensen
44afa34e37 Merge branch 'main' of github.com:github/codeql into htmlReg 2021-10-26 14:46:27 +02:00
Arthur Baars
b79f8f1890 Fix CI jobs 2021-10-25 17:01:50 +02:00
shati-patel
8cd86ae8f5 Move queries.xml to src 2021-10-25 17:01:50 +02:00
shati-patel
b23b3c33f6 Add a queries.xml file (for CWE coverage) docs 2021-10-25 17:01:50 +02:00
Arthur Baars
de38570424 Merge identical-files.json 2021-10-25 17:01:44 +02:00
Arthur Baars
1bf4542c89 Remove github/codeql submodule 2021-10-25 16:42:45 +02:00
Arthur Baars
ddbba403f8 Update CodeSpaces configuration 2021-10-25 16:42:45 +02:00
Arthur Baars
aeb9ace694 Add ruby to CODEOWNERS 2021-10-25 16:42:45 +02:00
Arthur Baars
7741a72cc5 Merge remote-tracking branch 'codeql-ruby/rc/3.3' into codeql/rc/3.3 2021-10-25 16:41:36 +02:00
Arthur Baars
8ce7b287d1 Update dependabot config 2021-10-25 16:13:37 +02:00
Arthur Baars
3554e8d105 Drop LICENSE and CODE_OF_CONDUCT.md 2021-10-25 16:13:37 +02:00
Arthur Baars
2de757335f Update Ruby workflows 2021-10-25 16:13:35 +02:00
Arthur Baars
068beeff56 Move create-extractor-pack Action 2021-10-25 16:12:08 +02:00
Arthur Baars
d2ea732539 Remove CodeSpaces configuration 2021-10-25 16:12:08 +02:00
Arthur Baars
ba32c54038 Move files to ruby subfolder 2021-10-25 16:11:59 +02:00
Rasmus Wriedt Larsen
7619d0fc33 Python: FastAPI: Model WebSocket usage 2021-10-25 15:23:33 +02:00
Rasmus Wriedt Larsen
b69977b37a Python: FastAPI: Ignore scheme as tainted
reasoning highlighted in the comment
2021-10-25 15:23:33 +02:00
Rasmus Wriedt Larsen
bd8eec8475 Python: FastAPI: Add websocket test 2021-10-25 15:23:33 +02:00
Rasmus Wriedt Larsen
54ab5d4bc8 Python: Fix date for FastAPI change-note 2021-10-25 15:23:33 +02:00
Rasmus Wriedt Larsen
7e7a6464ec Python: FastAPI: Model extra-taint for pydantic models
It feels a bit strange to add it to `frameworks.rst` since we only
support a little bit of it, but if I don't do it now, we will most
likely forget to do it later on (since it has already been added to
`frameworks.qll`).
2021-10-25 15:22:50 +02:00
ihsinme
5d5d6bcc69 Add files via upload 2021-10-25 14:34:10 +03:00
ihsinme
baec186359 Add files via upload 2021-10-25 14:33:01 +03:00
ihsinme
3f3988ce1c Add files via upload 2021-10-25 14:24:35 +03:00
ihsinme
8e8a324fa6 Add files via upload 2021-10-25 14:23:19 +03:00
Rasmus Wriedt Larsen
f5464b79e4 Merge branch 'main' into fastapi 2021-10-25 09:49:42 +02:00
Tony Torralba
a5749a5eb1 Add ComponentName tests to existing Intent tests 2021-10-18 15:23:52 +02:00
Tony Torralba
392e2eebeb Add intent creation from a URI as a taint step 2021-10-18 12:18:07 +02:00
Tony Torralba
d1d2d61d7e Add more sinks
Also, fix things after rebase
2021-10-18 12:00:07 +02:00
Tony Torralba
28ae4c211f Update java/ql/src/Security/CWE/CWE-940/AndroidIntentRedirection.qhelp
Co-authored-by: Ethan Palm <56270045+ethanpalm@users.noreply.github.com>
2021-10-18 11:10:23 +02:00
Tony Torralba
e7983fb269 Add test and check for another edge case 2021-10-18 11:10:23 +02:00
Tony Torralba
bc6c13be69 Refactor to actually build the full flows from src to sink
Add more tests for edge cases
2021-10-18 11:10:22 +02:00
Tony Torralba
4dd9e7d6a0 Remove unnecessary import
Add comment
2021-10-18 11:10:22 +02:00
Tony Torralba
14963103aa Add full path reconstruction from RemoteFlowSource to sink 2021-10-18 11:10:21 +02:00
Tony Torralba
445da1e71e Move files to new location 2021-10-18 11:10:21 +02:00
Tony Torralba
8263524d70 Add tests for Intent and ComponentName summaries 2021-10-18 11:10:17 +02:00
Tony Torralba
2ab7a55545 Improve intermediate flow to add more potential sources 2021-10-18 11:09:52 +02:00
Tony Torralba
28369d1822 Apply suggestions from code review
Co-authored-by: Steve Guntrip <12534592+stevecat@users.noreply.github.com>
2021-10-18 11:09:31 +02:00
Tony Torralba
aa2cdb7a53 Add intermediate dataflow
Make sure that source intents are obtained from another intent's extras
2021-10-18 11:09:30 +02:00
Tony Torralba
f90220436f Move sinks to security library 2021-10-18 11:09:28 +02:00
Tony Torralba
9a537f9c23 Add guard sanitizer for component name checks 2021-10-18 11:08:14 +02:00
Tony Torralba
21b70a009e Use CSV models 2021-10-18 11:07:58 +02:00
Tony Torralba
9604f88ae0 Undo autoformatting 2021-10-18 11:07:28 +02:00
Tony Torralba
d7973592da Update java/ql/src/semmle/code/java/security/AndroidIntentRedirection.qll
Co-authored-by: Marcono1234 <Marcono1234@users.noreply.github.com>
2021-10-18 11:07:03 +02:00
Tony Torralba
5f0ce4d232 Add suggestions from code review 2021-10-18 11:07:01 +02:00
Tony Torralba
a6f2ebe820 Fix stubs 2021-10-18 11:06:43 +02:00
Tony Torralba
9eb4cda1af Fix qhelp and formatting 2021-10-18 11:06:08 +02:00
Tony Torralba
031fa2199c Fix stubs and tests 2021-10-18 11:06:06 +02:00
Tony Torralba
529a3d9d61 Added change note 2021-10-18 11:04:35 +02:00
Tony Torralba
5dfb0d4d64 Fix Android tests affected by changes in stubs 2021-10-18 11:04:33 +02:00
Tony Torralba
ef30ca211a Fix stubs 2021-10-18 11:03:13 +02:00
Tony Torralba
7b949e8db2 QLDoc 2021-10-18 11:02:35 +02:00
Tony Torralba
fd8a128693 Renamed to AndroidIntentRedirection
Added qhelp
2021-10-18 11:02:34 +02:00
Tony Torralba
09d96e65b8 Added QLDoc 2021-10-18 11:02:32 +02:00
Tony Torralba
8c400d9b1b Added tests and stubs 2021-10-18 11:02:10 +02:00
Tony Torralba
d006db9d20 First version of the query 2021-10-18 10:58:09 +02:00
Erik Krogh Kristensen
047aee313c add pragma[noinline] to predicates where the qldoc mentions join-order 2021-10-14 12:34:25 +02:00
Erik Krogh Kristensen
8d6cac76cc apply suggestions from asgerf 2021-10-04 12:45:02 +02:00
Erik Krogh Kristensen
5a1eb1995c add change note 2021-10-01 11:13:41 +02:00
Erik Krogh Kristensen
694016dcbe add missing qldoc 2021-10-01 09:01:57 +02:00
Erik Krogh Kristensen
6a9277b5ce recognize string sanitizers for ldap-injection 2021-10-01 09:01:29 +02:00
Erik Krogh Kristensen
51b56a9e28 add cwe 090 (ldap injection) and cwe 943 (Improper Neutralization of Special Elements in Data Query Logic) to SqlInjection.ql 2021-10-01 09:01:29 +02:00
Erik Krogh Kristensen
2062afc868 add calls to parseDN as sinks for ldap-injection 2021-10-01 09:01:28 +02:00
Erik Krogh Kristensen
d4de5e3248 refactoring and renamings in the ldap model 2021-10-01 09:01:14 +02:00
Erik Krogh Kristensen
bcf4626fd0 remove ldap examples from experimental folder 2021-10-01 09:00:10 +02:00
Erik Krogh Kristensen
c55b7bcd85 model ldap filters as taint steps 2021-10-01 09:00:10 +02:00
Erik Krogh Kristensen
9b5ff66b68 naively port tests from ldap examples 2021-10-01 09:00:10 +02:00
Erik Krogh Kristensen
2b286a856c naively move ldap into the SQL injection query 2021-10-01 09:00:10 +02:00
Erik Krogh Kristensen
94e2676c0f naive conversion of ldapjs model to API node 2021-10-01 09:00:10 +02:00
Rasmus Wriedt Larsen
2d5c6e2723 Python: FastAPI: Add taint test 2021-09-30 19:14:15 +02:00
Rasmus Wriedt Larsen
c839f35485 Python: FastAPI: Proper modeling of implicit returns 2021-09-30 19:14:15 +02:00
Rasmus Wriedt Larsen
50147708bf Python: FastAPI: Model response classes
Figuring out how to do the `media_type` tracking was quite difficult.
2021-09-30 19:14:15 +02:00
Rasmus Wriedt Larsen
eef946a0c8 Python: FastAPI: Add test for custom response annotation
It really is rather contrived, but it also _does_ work.
2021-09-30 19:14:15 +02:00
Rasmus Wriedt Larsen
c9895b54fe Python: FastAPI: Add tests for direct response construction 2021-09-30 19:14:14 +02:00
Rasmus Wriedt Larsen
c50c805f5f Python: FastAPI: Model Cookie Writes 2021-09-30 19:14:14 +02:00
Rasmus Wriedt Larsen
d34c5fd72f Python: FastAPI: Add tests with response parameter 2021-09-30 19:14:14 +02:00
Rasmus Wriedt Larsen
285de2b4c8 Python: FastAPI: Add support for APIRouter 2021-09-30 19:14:14 +02:00
Rasmus Wriedt Larsen
b1f8b5352b Python: FastAPI: Add support for api_route
Note that `route` did not actually work (that also comes from the
underlying web framework library Starlette)
2021-09-30 19:14:14 +02:00
Rasmus Wriedt Larsen
3661ff3bd8 Python: Add basic FastAPI support 2021-09-30 19:14:14 +02:00
Erik Krogh Kristensen
aafae24ef2 update qhelp 2021-09-28 23:11:02 +02:00
Erik Krogh Kristensen
8d556ed1e1 Update python/ql/lib/semmle/python/security/BadTagFilterQuery.qll
Co-authored-by: Rasmus Wriedt Larsen <rasmuswriedtlarsen@gmail.com>
2021-09-28 23:04:28 +02:00
luciaromeroML
1fc58e51a3 adding suggestion that removes sanitizer for unknown base urls 2021-09-27 17:37:36 -03:00
luciaromeroML
1f2618b893 new test case for unknown base url 2021-09-27 17:37:11 -03:00
luchua-bc
378db7de87 Remove local user input and use fluent model 2021-09-27 17:33:04 +00:00
luchua-bc
5264936fc3 Correct the run method and add Math.min check 2021-09-24 21:00:53 +00:00
luchua-bc
272e4f6cf9 Update the query 2021-09-24 01:48:11 +00:00
luchua-bc
2dc38aee54 Update qldoc 2021-09-23 20:31:24 +00:00
Erik Krogh Kristensen
99ed4a1a89 add a bad-tag-filter query for Python and JavaScript 2021-09-21 15:04:03 +02:00
Erik Krogh Kristensen
fd64ff9ef1 don't give group numbers to non-capturing groups 2021-09-21 12:15:27 +02:00
Erik Krogh Kristensen
c40ffab093 make isStartState public in ReDoSUtil 2021-09-21 12:14:21 +02:00
Erik Krogh Kristensen
672e4a3d72 cache TopLevel::isMinified 2021-09-21 12:13:37 +02:00
Erik Krogh Kristensen
60993214d5 cache isInterpretedAsRegExp 2021-09-21 12:13:37 +02:00
Erik Krogh Kristensen
01e345c2cc implement RegExpWordBoundary in RegexTreeView 2021-09-21 12:13:37 +02:00
Erik Krogh Kristensen
8535e6f281 use toUnicode in RegexTreeView 2021-09-21 12:13:37 +02:00
luchua-bc
8170f01b66 Query to detect uncontrolled thread resource consumption 2021-09-20 02:12:47 +00:00
luciaromeroML
f348a5ce47 adding comments to some functions 2021-09-17 18:25:14 -03:00
luciaromeroML
25065bc986 simplifying sentence 2021-09-17 18:07:04 -03:00
luciaromeroML
0b0ac8317c format ql code 2021-09-17 18:05:52 -03:00
valeria-meli
054218a381 Merge branch 'main' into javascript/ssrf 2021-09-17 17:08:52 -03:00
Nati Pesaresi
629efb85fb ternary operator 2021-09-02 17:55:09 -03:00
valeria-meli
0b5c8909dd tests 2021-08-03 18:00:49 -03:00
valeria-meli
595ea6c383 files for qhelp 2021-08-03 18:00:29 -03:00
valeria-meli
57ac944319 rename folders 2021-08-03 17:39:48 -03:00
valeria-meli
92c874c2e2 rename query 2021-08-03 17:32:36 -03:00
valeria-meli
0e4865c40c Merge branch 'main' into javascript/ssrf 2021-08-03 17:17:50 -03:00
valeria-meli
f3c0bf7826 copy-paste from our repo 2021-07-27 18:09:11 -03:00
jorgectf
f9b244ecad Polish documentation 2021-07-24 01:06:05 +02:00
jorgectf
68f79f054b Update .expected 2021-07-21 21:32:08 +02:00
jorgectf
8d84d63b94 Add Python-Jose modeling and tests 2021-07-21 21:31:53 +02:00
jorgectf
ce507beed4 Add Authlib modeling and tests 2021-07-21 21:31:35 +02:00
jorgectf
e14b10370e Add indeterminate test to pyjwt 2021-07-21 21:30:54 +02:00
jorgectf
f1b3c70909 Divide JWT libraries 2021-07-21 21:29:23 +02:00
jorgectf
3d2b6f7a2d Delete outdated comment 2021-07-01 17:54:46 +02:00
jorgectf
7fb44470ee Add .expected results 2021-07-01 17:53:04 +02:00
jorgectf
a1f48db60b Make verifiesSignature() a predicate 2021-07-01 17:51:56 +02:00
jorgectf
4079e5352e Add JWT framework to Frameworks.qll 2021-07-01 17:51:34 +02:00
jorgectf
07422a1dce Move tests under test/ 2021-07-01 17:51:00 +02:00
jorgectf
058ade4d8e Merge remote-tracking branch 'upstream/main' into jorgectf/python/jwt-queries 2021-06-18 22:21:38 +02:00
jorgectf
6565680dd6 Finish query 2021-06-18 22:16:39 +02:00
jorgectf
d22da880e7 Fix verifiesSignature() 2021-04-04 20:31:07 +02:00
jorgectf
198f8dcc1f Improve predicates 2021-04-03 23:01:50 +02:00
jorgectf
7ed7809a60 Use LocalSourceNode and flowsTo() for better performance 2021-04-02 21:17:18 +02:00
jorgectf
513055cae5 Change old comments 2021-04-01 18:45:39 +02:00
jorgectf
ee70eb709c Remove old comment 2021-04-01 18:34:54 +02:00
jorgectf
5edb3b1153 Query upload 2021-04-01 18:31:45 +02:00
1114 changed files with 63062 additions and 29110 deletions

View File

@@ -1,11 +1,23 @@
{ "provide": [ "ruby/.codeqlmanifest.json",
"*/ql/src/qlpack.yml",
"*/ql/lib/qlpack.yml",
"*/ql/test/qlpack.yml",
"cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/qlpack.yml",
"*/ql/examples/qlpack.yml",
"*/upgrades/qlpack.yml",
"javascript/ql/experimental/adaptivethreatmodeling/lib/qlpack.yml",
"javascript/ql/experimental/adaptivethreatmodeling/src/qlpack.yml",
"misc/legacy-support/*/qlpack.yml",
"misc/suite-helpers/qlpack.yml" ] }
{
"provide": [
"*/ql/src/qlpack.yml",
"*/ql/lib/qlpack.yml",
"*/ql/test/qlpack.yml",
"*/ql/examples/qlpack.yml",
"*/upgrades/qlpack.yml",
"cpp/ql/test/query-tests/Security/CWE/CWE-190/semmle/tainted/qlpack.yml",
"javascript/ql/experimental/adaptivethreatmodeling/lib/qlpack.yml",
"javascript/ql/experimental/adaptivethreatmodeling/src/qlpack.yml",
"misc/legacy-support/*/qlpack.yml",
"misc/suite-helpers/qlpack.yml",
"ruby/extractor-pack/codeql-extractor.yml",
"ruby/ql/consistency-queries/qlpack.yml"
],
"versionPolicies": {
"default": {
"requireChangeNotes": true,
"committedPrereleaseSuffix": "dev",
"committedVersion": "nextPatchRelease"
}
}
}

View File

@@ -8,7 +8,7 @@ runs:
run: |
LATEST=$(gh release list --repo https://github.com/github/codeql-cli-binaries | cut -f 1 | grep -v beta | sort --version-sort | tail -1)
gh release download --repo https://github.com/github/codeql-cli-binaries --pattern codeql-linux64.zip "$LATEST"
unzip -q codeql-linux64.zip
echo "${{ github.workspace }}/codeql" >> $GITHUB_PATH
unzip -q -d "${RUNNER_TEMP}" codeql-linux64.zip
echo "${RUNNER_TEMP}/codeql" >> "${GITHUB_PATH}"
env:
GITHUB_TOKEN: ${{ github.token }}

31
.github/workflows/post-pr-comment.yml vendored Normal file
View File

@@ -0,0 +1,31 @@
name: Post pull-request comment
on:
workflow_run:
workflows: ["Query help preview"]
types:
- completed
permissions:
pull-requests: write
jobs:
post_comment:
runs-on: ubuntu-latest
steps:
- name: Download artifact
run: gh run download "${WORKFLOW_RUN_ID}" --repo "${GITHUB_REPOSITORY}" --name "comment"
env:
GITHUB_TOKEN: ${{ github.token }}
WORKFLOW_RUN_ID: ${{ github.event.workflow_run.id }}
- run: |
PR="$(grep -o '^[0-9]\+$' pr.txt)"
PR_HEAD_SHA="$(gh api "/repos/${GITHUB_REPOSITORY}/pulls/${PR}" --jq .head.sha)"
# Check that the pull-request head SHA matches the head SHA of the workflow run
if [ "${WORKFLOW_RUN_HEAD_SHA}" != "${PR_HEAD_SHA}" ]; then
echo "PR head SHA ${PR_HEAD_SHA} does not match workflow_run event SHA ${WORKFLOW_RUN_HEAD_SHA}. Stopping." 1>&2
exit 1
fi
gh pr comment "${PR}" --repo "${GITHUB_REPOSITORY}" -F comment.txt
env:
GITHUB_TOKEN: ${{ github.token }}
WORKFLOW_RUN_HEAD_SHA: ${{ github.event.workflow_run.head_commit.id }}

View File

@@ -1,10 +1,13 @@
name: Query help preview
permissions:
contents: read
on:
pull_request:
branches:
- main
- 'rc/*'
- "rc/*"
paths:
- "ruby/**/*.qhelp"
@@ -12,28 +15,49 @@ jobs:
qhelp:
runs-on: ubuntu-latest
steps:
- run: echo "${{ github.event.number }}" > pr.txt
- uses: actions/upload-artifact@v2
with:
name: comment
path: pr.txt
retention-days: 1
- uses: actions/checkout@v2
with:
fetch-depth: 2
persist-credentials: false
- uses: ./.github/actions/fetch-codeql
- name: Determine changed files
id: changes
run: |
echo -n "::set-output name=qhelp_files::"
(git diff --name-only --diff-filter=ACMRT HEAD~1 HEAD | grep .qhelp$ | grep -v .inc.qhelp;
git diff --name-only --diff-filter=ACMRT HEAD~1 HEAD | grep .inc.qhelp$ | xargs -d '\n' -rn1 basename | xargs -d '\n' -rn1 git grep -l) |
sort -u | xargs -d '\n' -n1 printf "'%s' "
- uses: ./.github/actions/fetch-codeql
(git diff -z --name-only --diff-filter=ACMRT HEAD~1 HEAD | grep -z '.qhelp$' | grep -z -v '.inc.qhelp';
git diff -z --name-only --diff-filter=ACMRT HEAD~1 HEAD | grep -z '.inc.qhelp$' | xargs --null -rn1 basename | xargs --null -rn1 git grep -z -l) |
grep -z '.qhelp$' | grep -z -v '^-' | sort -z -u > "${RUNNER_TEMP}/paths.txt"
- name: QHelp preview
if: ${{ steps.changes.outputs.qhelp_files }}
run: |
( echo "QHelp previews:";
for path in ${{ steps.changes.outputs.qhelp_files }} ; do
EXIT_CODE=0
echo "QHelp previews:" > comment.txt
while read -r -d $'\0' path; do
if [ ! -f "${path}" ]; then
exit 1
fi
echo "<details> <summary>${path}</summary>"
echo
codeql generate query-help --format=markdown ${path}
codeql generate query-help --format=markdown -- "./${path}" 2> errors.txt || EXIT_CODE="$?"
if [ -s errors.txt ]; then
echo "# errors/warnings:"
echo '```'
cat errors.txt
cat errors.txt 1>&2
echo '```'
fi
echo "</details>"
done) | gh pr comment "${{ github.event.pull_request.number }}" -F -
env:
GITHUB_TOKEN: ${{ github.token }}
done < "${RUNNER_TEMP}/paths.txt" >> comment.txt
exit "${EXIT_CODE}"
- if: always()
uses: actions/upload-artifact@v2
with:
name: comment
path: comment.txt
retention-days: 1

View File

@@ -3,16 +3,18 @@ name: "Ruby: Build"
on:
push:
paths:
- 'ruby/**'
- "ruby/**"
- .github/workflows/ruby-build.yml
branches:
- main
- 'rc/*'
- "rc/*"
pull_request:
paths:
- 'ruby/**'
- "ruby/**"
- .github/workflows/ruby-build.yml
branches:
- main
- 'rc/*'
- "rc/*"
workflow_dispatch:
inputs:
tag:
@@ -100,16 +102,6 @@ jobs:
PACK_FOLDER=$(readlink -f target/packs/codeql/ruby-queries/*)
codeql/codeql generate query-help --format=sarifv2.1.0 --output="${PACK_FOLDER}/rules.sarif" ql/src
(cd ql/src; find queries \( -name '*.qhelp' -o -name '*.rb' -o -name '*.erb' \) -exec bash -c 'mkdir -p "'"${PACK_FOLDER}"'/$(dirname "{}")"' \; -exec cp "{}" "${PACK_FOLDER}/{}" \;)
- name: Compile with previous CodeQL versions
run: |
for version in $(gh release list --repo https://github.com/github/codeql-cli-binaries | cut -f 1 | sort --version-sort | tail -3 | head -2); do
rm -f codeql-linux64.zip
gh release download --repo https://github.com/github/codeql-cli-binaries --pattern codeql-linux64.zip "$version"
rm -rf codeql; unzip -q codeql-linux64.zip
codeql/codeql query compile target/packs/*
done
env:
GITHUB_TOKEN: ${{ github.token }}
- uses: actions/upload-artifact@v2
with:
name: codeql-ruby-queries

View File

@@ -4,15 +4,17 @@ on:
push:
branches:
- main
- 'rc/*'
- "rc/*"
paths:
- ruby/ql/lib/ruby.dbscheme
- .github/workflows/ruby-dataset-measure.yml
pull_request:
branches:
- main
- 'rc/*'
- "rc/*"
paths:
- ruby/ql/lib/ruby.dbscheme
- .github/workflows/ruby-dataset-measure.yml
workflow_dispatch:
jobs:
@@ -39,7 +41,7 @@ jobs:
- name: Create database
run: |
codeql database create \
--search-path "${{ github.workspace }}/ruby" \
--search-path "${{ github.workspace }}/ruby/extractor-pack" \
--threads 4 \
--language ruby --source-root "${{ github.workspace }}/repo" \
"${{ runner.temp }}/database"

View File

@@ -3,16 +3,18 @@ name: "Ruby: Run QL Tests"
on:
push:
paths:
- 'ruby/**'
- "ruby/**"
- .github/workflows/ruby-qltest.yml
branches:
- main
- 'rc/*'
- "rc/*"
pull_request:
paths:
- 'ruby/**'
- "ruby/**"
- .github/workflows/ruby-qltest.yml
branches:
- main
- 'rc/*'
- "rc/*"
env:
CARGO_TERM_COLOR: always
@@ -30,19 +32,19 @@ jobs:
- uses: ./ruby/actions/create-extractor-pack
- name: Run QL tests
run: |
codeql test run --check-databases --check-unused-labels --check-repeated-labels --check-redefined-labels --check-use-before-definition --search-path "${{ github.workspace }}/ruby" --additional-packs "${{ github.workspace }}" --consistency-queries ql/consistency-queries ql/test
codeql test run --search-path "${{ github.workspace }}/ruby/extractor-pack" --check-databases --check-unused-labels --check-repeated-labels --check-redefined-labels --check-use-before-definition --consistency-queries ql/consistency-queries ql/test
env:
GITHUB_TOKEN: ${{ github.token }}
- name: Check QL formatting
run: find ql "(" -name "*.ql" -or -name "*.qll" ")" -print0 | xargs -0 codeql query format --check-only
- name: Check QL compilation
run: |
codeql query compile --check-only --threads=4 --warnings=error --search-path "${{ github.workspace }}/ruby" --additional-packs "${{ github.workspace }}" "ql/src" "ql/examples"
codeql query compile --check-only --threads=4 --warnings=error "ql/src" "ql/examples"
env:
GITHUB_TOKEN: ${{ github.token }}
- name: Check DB upgrade scripts
run: |
echo >empty.trap
codeql dataset import -S ql/lib/upgrades/initial/ruby.dbscheme testdb empty.trap
codeql dataset upgrade testdb --additional-packs ql/lib/upgrades
codeql dataset upgrade testdb --additional-packs ql/lib
diff -q testdb/ruby.dbscheme ql/lib/ruby.dbscheme

3
.gitignore vendored
View File

@@ -27,3 +27,6 @@ csharp/extractor/Semmle.Extraction.CSharp.Driver/Properties/launchSettings.json
# Avoid committing cached package components
.codeql
# Compiled class file
*.class

View File

@@ -449,7 +449,8 @@
"csharp/ql/lib/semmle/code/csharp/controlflow/internal/pressa/SsaImplCommon.qll",
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/basessa/SsaImplCommon.qll",
"csharp/ql/lib/semmle/code/cil/internal/SsaImplCommon.qll",
"ruby/ql/lib/codeql/ruby/dataflow/internal/SsaImplCommon.qll"
"ruby/ql/lib/codeql/ruby/dataflow/internal/SsaImplCommon.qll",
"cpp/ql/lib/semmle/code/cpp/ir/dataflow/internal/SsaImplCommon.qll"
],
"CryptoAlgorithms Python/JS": [
"javascript/ql/lib/semmle/javascript/security/CryptoAlgorithms.qll",
@@ -459,9 +460,10 @@
"javascript/ql/lib/semmle/javascript/security/internal/SensitiveDataHeuristics.qll",
"python/ql/lib/semmle/python/security/internal/SensitiveDataHeuristics.qll"
],
"ReDoS Util Python/JS": [
"ReDoS Util Python/JS/Ruby": [
"javascript/ql/lib/semmle/javascript/security/performance/ReDoSUtil.qll",
"python/ql/lib/semmle/python/security/performance/ReDoSUtil.qll"
"python/ql/lib/semmle/python/security/performance/ReDoSUtil.qll",
"ruby/ql/lib/codeql/ruby/security/performance/ReDoSUtil.qll"
],
"ReDoS Exponential Python/JS": [
"javascript/ql/lib/semmle/javascript/security/performance/ExponentialBackTracking.qll",
@@ -470,7 +472,12 @@
"ReDoS Polynomial Python/JS": [
"javascript/ql/lib/semmle/javascript/security/performance/SuperlinearBackTracking.qll",
"python/ql/lib/semmle/python/security/performance/SuperlinearBackTracking.qll",
"ruby/ql/lib/codeql/ruby/regexp/SuperlinearBackTracking.qll"
"ruby/ql/lib/codeql/ruby/security/performance/SuperlinearBackTracking.qll"
],
"BadTagFilterQuery Python/JS/Ruby": [
"javascript/ql/lib/semmle/javascript/security/BadTagFilterQuery.qll",
"python/ql/lib/semmle/python/security/BadTagFilterQuery.qll",
"ruby/ql/lib/codeql/ruby/security/BadTagFilterQuery.qll"
],
"CFG": [
"csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraphImplShared.qll",

View File

@@ -0,0 +1,2 @@
lgtm,codescanning
* A new query `cpp/non-https-url` has been added for C/C++. The query flags uses of `http` URLs that might be better replaced with `https`.

7
cpp/ql/lib/CHANGELOG.md Normal file
View File

@@ -0,0 +1,7 @@
## 0.0.4
### New Features
* The QL library `semmle.code.cpp.commons.Exclusions` now contains a predicate
`isFromSystemMacroDefinition` for identifying code that originates from a
macro outside the project being analyzed.

View File

@@ -0,0 +1,7 @@
## 0.0.4
### New Features
* The QL library `semmle.code.cpp.commons.Exclusions` now contains a predicate
`isFromSystemMacroDefinition` for identifying code that originates from a
macro outside the project being analyzed.

View File

@@ -0,0 +1,2 @@
---
lastReleaseVersion: 0.0.4

View File

@@ -1,7 +1,8 @@
name: codeql/cpp-all
version: 0.0.2
version: 0.0.5-dev
groups: cpp
dbscheme: semmlecode.cpp.dbscheme
extractor: cpp
library: true
dependencies:
codeql/cpp-upgrades: 0.0.2
codeql/cpp-upgrades: 0.0.3

View File

@@ -3,11 +3,14 @@ private import semmle.code.cpp.models.interfaces.ArrayFunction
private import semmle.code.cpp.models.implementations.Strcat
import semmle.code.cpp.dataflow.DataFlow
private predicate mayAddNullTerminatorHelper(Expr e, VariableAccess va, Expr e0) {
exists(StackVariable v0, Expr val |
exprDefinition(v0, e, val) and
val.getAChild*() = va and
mayAddNullTerminator(e0, v0.getAnAccess())
/**
* Holds if the expression `e` assigns something including `va` to a
* stack variable `v0`.
*/
private predicate mayAddNullTerminatorHelper(Expr e, VariableAccess va, StackVariable v0) {
exists(Expr val |
exprDefinition(v0, e, val) and // `e` is `v0 := val`
val.getAChild*() = va
)
}
@@ -25,8 +28,8 @@ private predicate controlFlowNodeSuccessorTransitive(ControlFlowNode n1, Control
}
/**
* Holds if the expression `e` may add a null terminator to the string in
* variable `v`.
* Holds if the expression `e` may add a null terminator to the string
* accessed by `va`.
*/
predicate mayAddNullTerminator(Expr e, VariableAccess va) {
// Assignment: dereferencing or array access
@@ -43,8 +46,9 @@ predicate mayAddNullTerminator(Expr e, VariableAccess va) {
)
or
// Assignment to another stack variable
exists(Expr e0 |
mayAddNullTerminatorHelper(pragma[only_bind_into](e), va, pragma[only_bind_into](e0)) and
exists(StackVariable v0, Expr e0 |
mayAddNullTerminatorHelper(e, va, v0) and
mayAddNullTerminator(pragma[only_bind_into](e0), pragma[only_bind_into](v0.getAnAccess())) and
controlFlowNodeSuccessorTransitive(e, e0)
)
or

View File

@@ -6,6 +6,8 @@ import semmle.code.cpp.Type
import semmle.code.cpp.commons.CommonType
import semmle.code.cpp.commons.StringAnalysis
import semmle.code.cpp.models.interfaces.FormattingFunction
private import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
private import semmle.code.cpp.rangeanalysis.RangeAnalysisUtils
class PrintfFormatAttribute extends FormatAttribute {
PrintfFormatAttribute() { this.getArchetype() = ["printf", "__printf__"] }
@@ -268,6 +270,18 @@ class FormattingFunctionCall extends Expr {
}
}
/**
* Gets the number of digits required to represent the integer represented by `f`.
*
* `f` is assumed to be nonnegative.
*/
bindingset[f]
private int lengthInBase10(float f) {
f = 0 and result = 1
or
result = f.log10().floor() + 1
}
/**
* A class to represent format strings that occur as arguments to invocations of formatting functions.
*/
@@ -1046,39 +1060,63 @@ class FormatLiteral extends Literal {
or
this.getConversionChar(n).toLowerCase() = ["d", "i"] and
// e.g. -2^31 = "-2147483648"
exists(int sizeBits |
sizeBits =
min(int bits |
bits = this.getIntegralDisplayType(n).getSize() * 8
or
exists(IntegralType t |
t = this.getUse().getConversionArgument(n).getType().getUnderlyingType()
|
t.isSigned() and bits = t.getSize() * 8
)
) and
len = 1 + ((sizeBits - 1) / 10.0.log2()).ceil()
// this calculation is as %u (below) only we take out the sign bit (- 1) and allow a whole
// character for it to be expressed as '-'.
)
len =
min(float cand |
// The first case handles length sub-specifiers
// Subtract one in the exponent because one bit is for the sign.
// Add 1 to account for the possible sign in the output.
cand = 1 + lengthInBase10(2.pow(this.getIntegralDisplayType(n).getSize() * 8 - 1))
or
// The second case uses range analysis to deduce a length that's shorter than the length
// of the number -2^31.
exists(Expr arg, float lower, float upper |
arg = this.getUse().getConversionArgument(n) and
lower = lowerBound(arg.getFullyConverted()) and
upper = upperBound(arg.getFullyConverted())
|
cand =
max(int cand0 |
// Include the sign bit in the length if it can be negative
(
if lower < 0
then cand0 = 1 + lengthInBase10(lower.abs())
else cand0 = lengthInBase10(lower)
)
or
(
if upper < 0
then cand0 = 1 + lengthInBase10(upper.abs())
else cand0 = lengthInBase10(upper)
)
)
)
)
or
this.getConversionChar(n).toLowerCase() = "u" and
// e.g. 2^32 - 1 = "4294967295"
exists(int sizeBits |
sizeBits =
min(int bits |
bits = this.getIntegralDisplayType(n).getSize() * 8
or
exists(IntegralType t |
t = this.getUse().getConversionArgument(n).getType().getUnderlyingType()
|
t.isUnsigned() and bits = t.getSize() * 8
)
) and
len = (sizeBits / 10.0.log2()).ceil()
// convert the size from bits to decimal characters, and round up as you can't have
// fractional characters (10.0.log2() is the number of bits expressed per decimal character)
)
len =
min(float cand |
// The first case handles length sub-specifiers
cand = 2.pow(this.getIntegralDisplayType(n).getSize() * 8)
or
// The second case uses range analysis to deduce a length that's shorter than
// the length of the number 2^31 - 1.
exists(Expr arg, float lower |
arg = this.getUse().getConversionArgument(n) and
lower = lowerBound(arg.getFullyConverted())
|
cand =
max(float cand0 |
// If lower can be negative we use `(unsigned)-1` as the candidate value.
lower < 0 and
cand0 = 2.pow(any(IntType t | t.isUnsigned()).getSize() * 8)
or
cand0 = upperBound(arg.getFullyConverted())
)
)
|
lengthInBase10(cand)
)
or
this.getConversionChar(n).toLowerCase() = "x" and
// e.g. "12345678"

View File

@@ -10,6 +10,7 @@
private import DataFlowImplCommon
private import DataFlowImplSpecific::Private
import DataFlowImplSpecific::Public
import DataFlowImplCommonPublic
/**
* A configuration of interprocedural data flow analysis. This defines
@@ -94,6 +95,22 @@ abstract class Configuration extends string {
*/
int fieldFlowBranchLimit() { result = 2 }
/**
* Gets a data flow configuration feature to add restrictions to the set of
* valid flow paths.
*
* - `FeatureHasSourceCallContext`:
* Assume that sources have some existing call context to disallow
* conflicting return-flow directly following the source.
* - `FeatureHasSinkCallContext`:
* Assume that sinks have some existing call context to disallow
* conflicting argument-to-parameter flow directly preceding the sink.
* - `FeatureEqualSourceSinkCallContext`:
* Implies both of the above and additionally ensures that the entire flow
* path preserves the call context.
*/
FlowFeature getAFeature() { none() }
/**
* Holds if data may flow from `source` to `sink` for this configuration.
*/
@@ -272,6 +289,7 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
config.isBarrier(n)
@@ -290,11 +308,23 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
}
pragma[nomagic]
private predicate sourceNode(NodeEx node, Configuration config) { config.isSource(node.asNode()) }
private predicate sourceNode(NodeEx node, Configuration config) {
config.isSource(node.asNode()) and
not fullBarrier(node, config)
}
pragma[nomagic]
private predicate sinkNode(NodeEx node, Configuration config) { config.isSink(node.asNode()) }
/** 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 fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
/**
* Holds if data can flow in one local step from `node1` to `node2`.
*/
@@ -303,16 +333,14 @@ private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config
node1.asNode() = n1 and
node2.asNode() = n2 and
simpleLocalFlowStepExt(n1, n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
stepFilter(node1, node2, config)
)
or
exists(Node n |
config.allowImplicitRead(n, _) and
node1.asNode() = n and
node2.isImplicitReadNode(n, false)
node2.isImplicitReadNode(n, false) and
not fullBarrier(node1, config)
)
}
@@ -325,16 +353,14 @@ private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configurat
node2.asNode() = n2 and
config.isAdditionalFlowStep(n1, n2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
stepFilter(node1, node2, config)
)
or
exists(Node n |
config.allowImplicitRead(n, _) and
node1.isImplicitReadNode(n, true) and
node2.asNode() = n
node2.asNode() = n and
not fullBarrier(node2, config)
)
}
@@ -346,10 +372,8 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) {
node1.asNode() = n1 and
node2.asNode() = n2 and
jumpStepCached(n1, n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
stepFilter(node1, node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
}
@@ -362,15 +386,14 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c
node2.asNode() = n2 and
config.isAdditionalFlowStep(n1, n2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
stepFilter(node1, node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
}
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
read(node1.asNode(), c, node2.asNode())
read(node1.asNode(), c, node2.asNode()) and
stepFilter(node1, node2, config)
or
exists(Node n |
node2.isImplicitReadNode(n, true) and
@@ -383,7 +406,8 @@ private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
) {
store(node1.asNode(), tc, node2.asNode(), contentType) and
read(_, tc.getContent(), _, config)
read(_, tc.getContent(), _, config) and
stepFilter(node1, node2, config)
}
pragma[nomagic]
@@ -401,6 +425,20 @@ private predicate viableParamArgEx(DataFlowCall call, ParamNodeEx p, ArgNodeEx a
*/
private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 }
private predicate hasSourceCallCtx(Configuration config) {
exists(FlowFeature feature | feature = config.getAFeature() |
feature instanceof FeatureHasSourceCallContext or
feature instanceof FeatureEqualSourceSinkCallContext
)
}
private predicate hasSinkCallCtx(Configuration config) {
exists(FlowFeature feature | feature = config.getAFeature() |
feature instanceof FeatureHasSinkCallContext or
feature instanceof FeatureEqualSourceSinkCallContext
)
}
private module Stage1 {
class ApApprox = Unit;
@@ -418,63 +456,59 @@ private module Stage1 {
* argument in a call.
*/
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
not fullBarrier(node, config) and
(
sourceNode(node, config) and
sourceNode(node, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config)
)
or
// flow into a callable
exists(NodeEx arg |
fwdFlow(arg, _, config) and
viableParamArgEx(_, node, arg) and
cc = true and
not fullBarrier(node, config)
)
or
// flow out of a callable
exists(DataFlowCall call |
fwdFlowOut(call, node, false, config) and
cc = false
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config) and
not outBarrier(mid, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config) and
not inBarrier(node, config)
)
or
// flow into a callable
exists(NodeEx arg |
fwdFlow(arg, _, config) and
viableParamArgEx(_, node, arg) and
cc = true
)
or
// flow out of a callable
exists(DataFlowCall call |
fwdFlowOut(call, node, false, config) and
cc = false
or
fwdFlowOutFromArg(call, node, config) and
fwdFlowIsEntered(call, cc, config)
)
fwdFlowOutFromArg(call, node, config) and
fwdFlowIsEntered(call, cc, config)
)
}
@@ -514,7 +548,8 @@ private module Stage1 {
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
exists(ReturnPosition pos |
fwdFlowReturnPosition(pos, cc, config) and
viableReturnPosOutEx(call, pos, out)
viableReturnPosOutEx(call, pos, out) and
not fullBarrier(out, config)
)
}
@@ -551,7 +586,7 @@ private module Stage1 {
private predicate revFlow0(NodeEx node, boolean toReturn, Configuration config) {
fwdFlow(node, config) and
sinkNode(node, config) and
toReturn = false
if hasSinkCallCtx(config) then toReturn = true else toReturn = false
or
exists(NodeEx mid |
localFlowStep(node, mid, config) and
@@ -740,6 +775,7 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary.
*/
pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and
@@ -937,6 +973,8 @@ private module Stage2 {
Cc ccNone() { result instanceof CallContextAny }
CcCall ccSomeCall() { result instanceof CallContextSomeCall }
private class LocalCc = Unit;
bindingset[call, c, outercc]
@@ -984,12 +1022,14 @@ private module Stage2 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
}
/**
@@ -1004,7 +1044,7 @@ private module Stage2 {
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
cc = ccNone() and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and
ap = getApNil(node)
or
@@ -1107,9 +1147,8 @@ private module Stage2 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1124,9 +1163,8 @@ private module Stage2 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1136,10 +1174,8 @@ private module Stage2 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1195,6 +1231,11 @@ private module Stage2 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -1215,7 +1256,7 @@ private module Stage2 {
) {
fwdFlow(node, _, _, ap, config) and
sinkNode(node, config) and
toReturn = false and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and
returnAp = apNone() and
ap instanceof ApNil
or
@@ -1271,7 +1312,7 @@ private module Stage2 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
if returnNodeMayFlowThrough(node, ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -1306,9 +1347,8 @@ private module Stage2 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1318,9 +1358,8 @@ private module Stage2 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1330,9 +1369,8 @@ private module Stage2 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1616,6 +1654,8 @@ private module Stage3 {
Cc ccNone() { result = false }
CcCall ccSomeCall() { result = true }
private class LocalCc = Unit;
bindingset[call, c, outercc]
@@ -1670,12 +1710,14 @@ private module Stage3 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
}
/**
@@ -1697,7 +1739,7 @@ private module Stage3 {
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
cc = ccNone() and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and
ap = getApNil(node)
or
@@ -1800,9 +1842,8 @@ private module Stage3 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1817,9 +1858,8 @@ private module Stage3 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1829,10 +1869,8 @@ private module Stage3 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1888,6 +1926,11 @@ private module Stage3 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -1908,7 +1951,7 @@ private module Stage3 {
) {
fwdFlow(node, _, _, ap, config) and
sinkNode(node, config) and
toReturn = false and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and
returnAp = apNone() and
ap instanceof ApNil
or
@@ -1964,7 +2007,7 @@ private module Stage3 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
if returnNodeMayFlowThrough(node, ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -1999,9 +2042,8 @@ private module Stage3 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2011,9 +2053,8 @@ private module Stage3 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2023,9 +2064,8 @@ private module Stage3 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2366,6 +2406,8 @@ private module Stage4 {
Cc ccNone() { result instanceof CallContextAny }
CcCall ccSomeCall() { result instanceof CallContextSomeCall }
private class LocalCc = LocalCallContext;
bindingset[call, c, outercc]
@@ -2434,12 +2476,14 @@ private module Stage4 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
}
/**
@@ -2461,7 +2505,7 @@ private module Stage4 {
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
cc = ccNone() and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and
ap = getApNil(node)
or
@@ -2564,9 +2608,8 @@ private module Stage4 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2581,9 +2624,8 @@ private module Stage4 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2593,10 +2635,8 @@ private module Stage4 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2652,6 +2692,11 @@ private module Stage4 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -2672,7 +2717,7 @@ private module Stage4 {
) {
fwdFlow(node, _, _, ap, config) and
sinkNode(node, config) and
toReturn = false and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and
returnAp = apNone() and
ap instanceof ApNil
or
@@ -2728,7 +2773,7 @@ private module Stage4 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
if returnNodeMayFlowThrough(node, ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -2763,9 +2808,8 @@ private module Stage4 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2775,9 +2819,8 @@ private module Stage4 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2787,9 +2830,8 @@ private module Stage4 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -3064,7 +3106,11 @@ private newtype TPathNode =
// A PathNode is introduced by a source ...
Stage4::revFlow(node, config) and
sourceNode(node, config) and
cc instanceof CallContextAny and
(
if hasSourceCallCtx(config)
then cc instanceof CallContextSomeCall
else cc instanceof CallContextAny
) and
sc instanceof SummaryCtxNone and
ap = TAccessPathNil(node.getDataFlowType())
or
@@ -3076,17 +3122,10 @@ private newtype TPathNode =
)
} or
TPathNodeSink(NodeEx node, Configuration config) {
sinkNode(node, pragma[only_bind_into](config)) and
Stage4::revFlow(node, pragma[only_bind_into](config)) and
(
// A sink that is also a source ...
sourceNode(node, config)
or
// ... or a sink that can be reached from a source
exists(PathNodeMid mid |
pathStep(mid, node, _, _, TAccessPathNil(_)) and
pragma[only_bind_into](config) = mid.getConfiguration()
)
exists(PathNodeMid sink |
sink.isAtSink() and
node = sink.getNodeEx() and
config = sink.getConfiguration()
)
}
@@ -3403,22 +3442,46 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
// an intermediate step to another intermediate node
result = this.getSuccMid()
or
// a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges
exists(PathNodeMid mid, PathNodeSink sink |
mid = this.getSuccMid() and
mid.getNodeEx() = sink.getNodeEx() and
mid.getAp() instanceof AccessPathNil and
sink.getConfiguration() = unbindConf(mid.getConfiguration()) and
result = sink
)
// a final step to a sink
result = this.getSuccMid().projectToSink()
}
override predicate isSource() {
sourceNode(node, config) and
cc instanceof CallContextAny and
(
if hasSourceCallCtx(config)
then cc instanceof CallContextSomeCall
else cc instanceof CallContextAny
) and
sc instanceof SummaryCtxNone and
ap instanceof AccessPathNil
}
predicate isAtSink() {
sinkNode(node, config) and
ap instanceof AccessPathNil and
if hasSinkCallCtx(config)
then
// For `FeatureHasSinkCallContext` the condition `cc instanceof CallContextNoCall`
// is exactly what we need to check. This also implies
// `sc instanceof SummaryCtxNone`.
// For `FeatureEqualSourceSinkCallContext` the initial call context was
// set to `CallContextSomeCall` and jumps are disallowed, so
// `cc instanceof CallContextNoCall` never holds. On the other hand,
// in this case there's never any need to enter a call except to identify
// a summary, so the condition in `pathIntoCallable` enforces this, which
// means that `sc instanceof SummaryCtxNone` holds if and only if we are
// in the call context of the source.
sc instanceof SummaryCtxNone or
cc instanceof CallContextNoCall
else any()
}
PathNodeSink projectToSink() {
this.isAtSink() and
result.getNodeEx() = node and
result.getConfiguration() = unbindConf(config)
}
}
/**
@@ -3572,7 +3635,7 @@ private predicate pathIntoArg(
)
}
pragma[noinline]
pragma[nomagic]
private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) {
@@ -3613,7 +3676,11 @@ private predicate pathIntoCallable(
sc = TSummaryCtxSome(p, ap)
or
not exists(TSummaryCtxSome(p, ap)) and
sc = TSummaryCtxNone()
sc = TSummaryCtxNone() and
// When the call contexts of source and sink needs to match then there's
// never any reason to enter a callable except to find a summary. See also
// the comment in `PathNodeMid::isAtSink`.
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
|
if recordDataFlowCallSite(call, callable)
@@ -3676,13 +3743,14 @@ private module Subpaths {
*/
pragma[nomagic]
private predicate subpaths01(
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, AccessPath apout
) {
exists(Configuration config |
pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and
pathIntoCallable(arg, par, _, innercc, sc, _, config) and
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config))
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config)) and
not arg.isHidden()
)
}
@@ -3716,8 +3784,17 @@ private module Subpaths {
innercc = ret.getCallContext() and
sc = ret.getSummaryCtx() and
ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and
apout = ret.getAp() and
not ret.isHidden()
apout = ret.getAp()
)
}
private PathNodeImpl localStepToHidden(PathNodeImpl n) {
n.getASuccessorImpl() = result and
result.isHidden() and
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
localFlowBigStep(n1, n2, _, _, _, _) or
store(n1, _, n2, _, _) or
read(n1, _, n2, _)
)
}
@@ -3726,11 +3803,12 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) {
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNodeMid out) {
exists(ParamNodeEx p, NodeEx o, AccessPath apout |
pragma[only_bind_into](arg).getASuccessor() = par and
pragma[only_bind_into](arg).getASuccessor() = out and
subpaths03(arg, p, ret, o, apout) and
subpaths03(arg, p, localStepToHidden*(ret), o, apout) and
not ret.isHidden() and
par.getNodeEx() = p and
out.getNodeEx() = o and
out.getAp() = apout

View File

@@ -10,6 +10,7 @@
private import DataFlowImplCommon
private import DataFlowImplSpecific::Private
import DataFlowImplSpecific::Public
import DataFlowImplCommonPublic
/**
* A configuration of interprocedural data flow analysis. This defines
@@ -94,6 +95,22 @@ abstract class Configuration extends string {
*/
int fieldFlowBranchLimit() { result = 2 }
/**
* Gets a data flow configuration feature to add restrictions to the set of
* valid flow paths.
*
* - `FeatureHasSourceCallContext`:
* Assume that sources have some existing call context to disallow
* conflicting return-flow directly following the source.
* - `FeatureHasSinkCallContext`:
* Assume that sinks have some existing call context to disallow
* conflicting argument-to-parameter flow directly preceding the sink.
* - `FeatureEqualSourceSinkCallContext`:
* Implies both of the above and additionally ensures that the entire flow
* path preserves the call context.
*/
FlowFeature getAFeature() { none() }
/**
* Holds if data may flow from `source` to `sink` for this configuration.
*/
@@ -272,6 +289,7 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
config.isBarrier(n)
@@ -290,11 +308,23 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
}
pragma[nomagic]
private predicate sourceNode(NodeEx node, Configuration config) { config.isSource(node.asNode()) }
private predicate sourceNode(NodeEx node, Configuration config) {
config.isSource(node.asNode()) and
not fullBarrier(node, config)
}
pragma[nomagic]
private predicate sinkNode(NodeEx node, Configuration config) { config.isSink(node.asNode()) }
/** 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 fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
/**
* Holds if data can flow in one local step from `node1` to `node2`.
*/
@@ -303,16 +333,14 @@ private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config
node1.asNode() = n1 and
node2.asNode() = n2 and
simpleLocalFlowStepExt(n1, n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
stepFilter(node1, node2, config)
)
or
exists(Node n |
config.allowImplicitRead(n, _) and
node1.asNode() = n and
node2.isImplicitReadNode(n, false)
node2.isImplicitReadNode(n, false) and
not fullBarrier(node1, config)
)
}
@@ -325,16 +353,14 @@ private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configurat
node2.asNode() = n2 and
config.isAdditionalFlowStep(n1, n2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
stepFilter(node1, node2, config)
)
or
exists(Node n |
config.allowImplicitRead(n, _) and
node1.isImplicitReadNode(n, true) and
node2.asNode() = n
node2.asNode() = n and
not fullBarrier(node2, config)
)
}
@@ -346,10 +372,8 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) {
node1.asNode() = n1 and
node2.asNode() = n2 and
jumpStepCached(n1, n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
stepFilter(node1, node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
}
@@ -362,15 +386,14 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c
node2.asNode() = n2 and
config.isAdditionalFlowStep(n1, n2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
stepFilter(node1, node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
}
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
read(node1.asNode(), c, node2.asNode())
read(node1.asNode(), c, node2.asNode()) and
stepFilter(node1, node2, config)
or
exists(Node n |
node2.isImplicitReadNode(n, true) and
@@ -383,7 +406,8 @@ private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
) {
store(node1.asNode(), tc, node2.asNode(), contentType) and
read(_, tc.getContent(), _, config)
read(_, tc.getContent(), _, config) and
stepFilter(node1, node2, config)
}
pragma[nomagic]
@@ -401,6 +425,20 @@ private predicate viableParamArgEx(DataFlowCall call, ParamNodeEx p, ArgNodeEx a
*/
private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 }
private predicate hasSourceCallCtx(Configuration config) {
exists(FlowFeature feature | feature = config.getAFeature() |
feature instanceof FeatureHasSourceCallContext or
feature instanceof FeatureEqualSourceSinkCallContext
)
}
private predicate hasSinkCallCtx(Configuration config) {
exists(FlowFeature feature | feature = config.getAFeature() |
feature instanceof FeatureHasSinkCallContext or
feature instanceof FeatureEqualSourceSinkCallContext
)
}
private module Stage1 {
class ApApprox = Unit;
@@ -418,63 +456,59 @@ private module Stage1 {
* argument in a call.
*/
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
not fullBarrier(node, config) and
(
sourceNode(node, config) and
sourceNode(node, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config)
)
or
// flow into a callable
exists(NodeEx arg |
fwdFlow(arg, _, config) and
viableParamArgEx(_, node, arg) and
cc = true and
not fullBarrier(node, config)
)
or
// flow out of a callable
exists(DataFlowCall call |
fwdFlowOut(call, node, false, config) and
cc = false
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config) and
not outBarrier(mid, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config) and
not inBarrier(node, config)
)
or
// flow into a callable
exists(NodeEx arg |
fwdFlow(arg, _, config) and
viableParamArgEx(_, node, arg) and
cc = true
)
or
// flow out of a callable
exists(DataFlowCall call |
fwdFlowOut(call, node, false, config) and
cc = false
or
fwdFlowOutFromArg(call, node, config) and
fwdFlowIsEntered(call, cc, config)
)
fwdFlowOutFromArg(call, node, config) and
fwdFlowIsEntered(call, cc, config)
)
}
@@ -514,7 +548,8 @@ private module Stage1 {
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
exists(ReturnPosition pos |
fwdFlowReturnPosition(pos, cc, config) and
viableReturnPosOutEx(call, pos, out)
viableReturnPosOutEx(call, pos, out) and
not fullBarrier(out, config)
)
}
@@ -551,7 +586,7 @@ private module Stage1 {
private predicate revFlow0(NodeEx node, boolean toReturn, Configuration config) {
fwdFlow(node, config) and
sinkNode(node, config) and
toReturn = false
if hasSinkCallCtx(config) then toReturn = true else toReturn = false
or
exists(NodeEx mid |
localFlowStep(node, mid, config) and
@@ -740,6 +775,7 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary.
*/
pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and
@@ -937,6 +973,8 @@ private module Stage2 {
Cc ccNone() { result instanceof CallContextAny }
CcCall ccSomeCall() { result instanceof CallContextSomeCall }
private class LocalCc = Unit;
bindingset[call, c, outercc]
@@ -984,12 +1022,14 @@ private module Stage2 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
}
/**
@@ -1004,7 +1044,7 @@ private module Stage2 {
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
cc = ccNone() and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and
ap = getApNil(node)
or
@@ -1107,9 +1147,8 @@ private module Stage2 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1124,9 +1163,8 @@ private module Stage2 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1136,10 +1174,8 @@ private module Stage2 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1195,6 +1231,11 @@ private module Stage2 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -1215,7 +1256,7 @@ private module Stage2 {
) {
fwdFlow(node, _, _, ap, config) and
sinkNode(node, config) and
toReturn = false and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and
returnAp = apNone() and
ap instanceof ApNil
or
@@ -1271,7 +1312,7 @@ private module Stage2 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
if returnNodeMayFlowThrough(node, ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -1306,9 +1347,8 @@ private module Stage2 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1318,9 +1358,8 @@ private module Stage2 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1330,9 +1369,8 @@ private module Stage2 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1616,6 +1654,8 @@ private module Stage3 {
Cc ccNone() { result = false }
CcCall ccSomeCall() { result = true }
private class LocalCc = Unit;
bindingset[call, c, outercc]
@@ -1670,12 +1710,14 @@ private module Stage3 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
}
/**
@@ -1697,7 +1739,7 @@ private module Stage3 {
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
cc = ccNone() and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and
ap = getApNil(node)
or
@@ -1800,9 +1842,8 @@ private module Stage3 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1817,9 +1858,8 @@ private module Stage3 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1829,10 +1869,8 @@ private module Stage3 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1888,6 +1926,11 @@ private module Stage3 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -1908,7 +1951,7 @@ private module Stage3 {
) {
fwdFlow(node, _, _, ap, config) and
sinkNode(node, config) and
toReturn = false and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and
returnAp = apNone() and
ap instanceof ApNil
or
@@ -1964,7 +2007,7 @@ private module Stage3 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
if returnNodeMayFlowThrough(node, ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -1999,9 +2042,8 @@ private module Stage3 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2011,9 +2053,8 @@ private module Stage3 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2023,9 +2064,8 @@ private module Stage3 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2366,6 +2406,8 @@ private module Stage4 {
Cc ccNone() { result instanceof CallContextAny }
CcCall ccSomeCall() { result instanceof CallContextSomeCall }
private class LocalCc = LocalCallContext;
bindingset[call, c, outercc]
@@ -2434,12 +2476,14 @@ private module Stage4 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
}
/**
@@ -2461,7 +2505,7 @@ private module Stage4 {
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
cc = ccNone() and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and
ap = getApNil(node)
or
@@ -2564,9 +2608,8 @@ private module Stage4 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2581,9 +2624,8 @@ private module Stage4 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2593,10 +2635,8 @@ private module Stage4 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2652,6 +2692,11 @@ private module Stage4 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -2672,7 +2717,7 @@ private module Stage4 {
) {
fwdFlow(node, _, _, ap, config) and
sinkNode(node, config) and
toReturn = false and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and
returnAp = apNone() and
ap instanceof ApNil
or
@@ -2728,7 +2773,7 @@ private module Stage4 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
if returnNodeMayFlowThrough(node, ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -2763,9 +2808,8 @@ private module Stage4 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2775,9 +2819,8 @@ private module Stage4 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2787,9 +2830,8 @@ private module Stage4 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -3064,7 +3106,11 @@ private newtype TPathNode =
// A PathNode is introduced by a source ...
Stage4::revFlow(node, config) and
sourceNode(node, config) and
cc instanceof CallContextAny and
(
if hasSourceCallCtx(config)
then cc instanceof CallContextSomeCall
else cc instanceof CallContextAny
) and
sc instanceof SummaryCtxNone and
ap = TAccessPathNil(node.getDataFlowType())
or
@@ -3076,17 +3122,10 @@ private newtype TPathNode =
)
} or
TPathNodeSink(NodeEx node, Configuration config) {
sinkNode(node, pragma[only_bind_into](config)) and
Stage4::revFlow(node, pragma[only_bind_into](config)) and
(
// A sink that is also a source ...
sourceNode(node, config)
or
// ... or a sink that can be reached from a source
exists(PathNodeMid mid |
pathStep(mid, node, _, _, TAccessPathNil(_)) and
pragma[only_bind_into](config) = mid.getConfiguration()
)
exists(PathNodeMid sink |
sink.isAtSink() and
node = sink.getNodeEx() and
config = sink.getConfiguration()
)
}
@@ -3403,22 +3442,46 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
// an intermediate step to another intermediate node
result = this.getSuccMid()
or
// a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges
exists(PathNodeMid mid, PathNodeSink sink |
mid = this.getSuccMid() and
mid.getNodeEx() = sink.getNodeEx() and
mid.getAp() instanceof AccessPathNil and
sink.getConfiguration() = unbindConf(mid.getConfiguration()) and
result = sink
)
// a final step to a sink
result = this.getSuccMid().projectToSink()
}
override predicate isSource() {
sourceNode(node, config) and
cc instanceof CallContextAny and
(
if hasSourceCallCtx(config)
then cc instanceof CallContextSomeCall
else cc instanceof CallContextAny
) and
sc instanceof SummaryCtxNone and
ap instanceof AccessPathNil
}
predicate isAtSink() {
sinkNode(node, config) and
ap instanceof AccessPathNil and
if hasSinkCallCtx(config)
then
// For `FeatureHasSinkCallContext` the condition `cc instanceof CallContextNoCall`
// is exactly what we need to check. This also implies
// `sc instanceof SummaryCtxNone`.
// For `FeatureEqualSourceSinkCallContext` the initial call context was
// set to `CallContextSomeCall` and jumps are disallowed, so
// `cc instanceof CallContextNoCall` never holds. On the other hand,
// in this case there's never any need to enter a call except to identify
// a summary, so the condition in `pathIntoCallable` enforces this, which
// means that `sc instanceof SummaryCtxNone` holds if and only if we are
// in the call context of the source.
sc instanceof SummaryCtxNone or
cc instanceof CallContextNoCall
else any()
}
PathNodeSink projectToSink() {
this.isAtSink() and
result.getNodeEx() = node and
result.getConfiguration() = unbindConf(config)
}
}
/**
@@ -3572,7 +3635,7 @@ private predicate pathIntoArg(
)
}
pragma[noinline]
pragma[nomagic]
private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) {
@@ -3613,7 +3676,11 @@ private predicate pathIntoCallable(
sc = TSummaryCtxSome(p, ap)
or
not exists(TSummaryCtxSome(p, ap)) and
sc = TSummaryCtxNone()
sc = TSummaryCtxNone() and
// When the call contexts of source and sink needs to match then there's
// never any reason to enter a callable except to find a summary. See also
// the comment in `PathNodeMid::isAtSink`.
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
|
if recordDataFlowCallSite(call, callable)
@@ -3676,13 +3743,14 @@ private module Subpaths {
*/
pragma[nomagic]
private predicate subpaths01(
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, AccessPath apout
) {
exists(Configuration config |
pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and
pathIntoCallable(arg, par, _, innercc, sc, _, config) and
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config))
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config)) and
not arg.isHidden()
)
}
@@ -3716,8 +3784,17 @@ private module Subpaths {
innercc = ret.getCallContext() and
sc = ret.getSummaryCtx() and
ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and
apout = ret.getAp() and
not ret.isHidden()
apout = ret.getAp()
)
}
private PathNodeImpl localStepToHidden(PathNodeImpl n) {
n.getASuccessorImpl() = result and
result.isHidden() and
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
localFlowBigStep(n1, n2, _, _, _, _) or
store(n1, _, n2, _, _) or
read(n1, _, n2, _)
)
}
@@ -3726,11 +3803,12 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) {
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNodeMid out) {
exists(ParamNodeEx p, NodeEx o, AccessPath apout |
pragma[only_bind_into](arg).getASuccessor() = par and
pragma[only_bind_into](arg).getASuccessor() = out and
subpaths03(arg, p, ret, o, apout) and
subpaths03(arg, p, localStepToHidden*(ret), o, apout) and
not ret.isHidden() and
par.getNodeEx() = p and
out.getNodeEx() = o and
out.getAp() = apout

View File

@@ -10,6 +10,7 @@
private import DataFlowImplCommon
private import DataFlowImplSpecific::Private
import DataFlowImplSpecific::Public
import DataFlowImplCommonPublic
/**
* A configuration of interprocedural data flow analysis. This defines
@@ -94,6 +95,22 @@ abstract class Configuration extends string {
*/
int fieldFlowBranchLimit() { result = 2 }
/**
* Gets a data flow configuration feature to add restrictions to the set of
* valid flow paths.
*
* - `FeatureHasSourceCallContext`:
* Assume that sources have some existing call context to disallow
* conflicting return-flow directly following the source.
* - `FeatureHasSinkCallContext`:
* Assume that sinks have some existing call context to disallow
* conflicting argument-to-parameter flow directly preceding the sink.
* - `FeatureEqualSourceSinkCallContext`:
* Implies both of the above and additionally ensures that the entire flow
* path preserves the call context.
*/
FlowFeature getAFeature() { none() }
/**
* Holds if data may flow from `source` to `sink` for this configuration.
*/
@@ -272,6 +289,7 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
config.isBarrier(n)
@@ -290,11 +308,23 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
}
pragma[nomagic]
private predicate sourceNode(NodeEx node, Configuration config) { config.isSource(node.asNode()) }
private predicate sourceNode(NodeEx node, Configuration config) {
config.isSource(node.asNode()) and
not fullBarrier(node, config)
}
pragma[nomagic]
private predicate sinkNode(NodeEx node, Configuration config) { config.isSink(node.asNode()) }
/** 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 fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
/**
* Holds if data can flow in one local step from `node1` to `node2`.
*/
@@ -303,16 +333,14 @@ private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config
node1.asNode() = n1 and
node2.asNode() = n2 and
simpleLocalFlowStepExt(n1, n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
stepFilter(node1, node2, config)
)
or
exists(Node n |
config.allowImplicitRead(n, _) and
node1.asNode() = n and
node2.isImplicitReadNode(n, false)
node2.isImplicitReadNode(n, false) and
not fullBarrier(node1, config)
)
}
@@ -325,16 +353,14 @@ private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configurat
node2.asNode() = n2 and
config.isAdditionalFlowStep(n1, n2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
stepFilter(node1, node2, config)
)
or
exists(Node n |
config.allowImplicitRead(n, _) and
node1.isImplicitReadNode(n, true) and
node2.asNode() = n
node2.asNode() = n and
not fullBarrier(node2, config)
)
}
@@ -346,10 +372,8 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) {
node1.asNode() = n1 and
node2.asNode() = n2 and
jumpStepCached(n1, n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
stepFilter(node1, node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
}
@@ -362,15 +386,14 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c
node2.asNode() = n2 and
config.isAdditionalFlowStep(n1, n2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
stepFilter(node1, node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
}
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
read(node1.asNode(), c, node2.asNode())
read(node1.asNode(), c, node2.asNode()) and
stepFilter(node1, node2, config)
or
exists(Node n |
node2.isImplicitReadNode(n, true) and
@@ -383,7 +406,8 @@ private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
) {
store(node1.asNode(), tc, node2.asNode(), contentType) and
read(_, tc.getContent(), _, config)
read(_, tc.getContent(), _, config) and
stepFilter(node1, node2, config)
}
pragma[nomagic]
@@ -401,6 +425,20 @@ private predicate viableParamArgEx(DataFlowCall call, ParamNodeEx p, ArgNodeEx a
*/
private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 }
private predicate hasSourceCallCtx(Configuration config) {
exists(FlowFeature feature | feature = config.getAFeature() |
feature instanceof FeatureHasSourceCallContext or
feature instanceof FeatureEqualSourceSinkCallContext
)
}
private predicate hasSinkCallCtx(Configuration config) {
exists(FlowFeature feature | feature = config.getAFeature() |
feature instanceof FeatureHasSinkCallContext or
feature instanceof FeatureEqualSourceSinkCallContext
)
}
private module Stage1 {
class ApApprox = Unit;
@@ -418,63 +456,59 @@ private module Stage1 {
* argument in a call.
*/
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
not fullBarrier(node, config) and
(
sourceNode(node, config) and
sourceNode(node, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config)
)
or
// flow into a callable
exists(NodeEx arg |
fwdFlow(arg, _, config) and
viableParamArgEx(_, node, arg) and
cc = true and
not fullBarrier(node, config)
)
or
// flow out of a callable
exists(DataFlowCall call |
fwdFlowOut(call, node, false, config) and
cc = false
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config) and
not outBarrier(mid, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config) and
not inBarrier(node, config)
)
or
// flow into a callable
exists(NodeEx arg |
fwdFlow(arg, _, config) and
viableParamArgEx(_, node, arg) and
cc = true
)
or
// flow out of a callable
exists(DataFlowCall call |
fwdFlowOut(call, node, false, config) and
cc = false
or
fwdFlowOutFromArg(call, node, config) and
fwdFlowIsEntered(call, cc, config)
)
fwdFlowOutFromArg(call, node, config) and
fwdFlowIsEntered(call, cc, config)
)
}
@@ -514,7 +548,8 @@ private module Stage1 {
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
exists(ReturnPosition pos |
fwdFlowReturnPosition(pos, cc, config) and
viableReturnPosOutEx(call, pos, out)
viableReturnPosOutEx(call, pos, out) and
not fullBarrier(out, config)
)
}
@@ -551,7 +586,7 @@ private module Stage1 {
private predicate revFlow0(NodeEx node, boolean toReturn, Configuration config) {
fwdFlow(node, config) and
sinkNode(node, config) and
toReturn = false
if hasSinkCallCtx(config) then toReturn = true else toReturn = false
or
exists(NodeEx mid |
localFlowStep(node, mid, config) and
@@ -740,6 +775,7 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary.
*/
pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and
@@ -937,6 +973,8 @@ private module Stage2 {
Cc ccNone() { result instanceof CallContextAny }
CcCall ccSomeCall() { result instanceof CallContextSomeCall }
private class LocalCc = Unit;
bindingset[call, c, outercc]
@@ -984,12 +1022,14 @@ private module Stage2 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
}
/**
@@ -1004,7 +1044,7 @@ private module Stage2 {
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
cc = ccNone() and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and
ap = getApNil(node)
or
@@ -1107,9 +1147,8 @@ private module Stage2 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1124,9 +1163,8 @@ private module Stage2 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1136,10 +1174,8 @@ private module Stage2 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1195,6 +1231,11 @@ private module Stage2 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -1215,7 +1256,7 @@ private module Stage2 {
) {
fwdFlow(node, _, _, ap, config) and
sinkNode(node, config) and
toReturn = false and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and
returnAp = apNone() and
ap instanceof ApNil
or
@@ -1271,7 +1312,7 @@ private module Stage2 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
if returnNodeMayFlowThrough(node, ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -1306,9 +1347,8 @@ private module Stage2 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1318,9 +1358,8 @@ private module Stage2 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1330,9 +1369,8 @@ private module Stage2 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1616,6 +1654,8 @@ private module Stage3 {
Cc ccNone() { result = false }
CcCall ccSomeCall() { result = true }
private class LocalCc = Unit;
bindingset[call, c, outercc]
@@ -1670,12 +1710,14 @@ private module Stage3 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
}
/**
@@ -1697,7 +1739,7 @@ private module Stage3 {
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
cc = ccNone() and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and
ap = getApNil(node)
or
@@ -1800,9 +1842,8 @@ private module Stage3 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1817,9 +1858,8 @@ private module Stage3 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1829,10 +1869,8 @@ private module Stage3 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1888,6 +1926,11 @@ private module Stage3 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -1908,7 +1951,7 @@ private module Stage3 {
) {
fwdFlow(node, _, _, ap, config) and
sinkNode(node, config) and
toReturn = false and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and
returnAp = apNone() and
ap instanceof ApNil
or
@@ -1964,7 +2007,7 @@ private module Stage3 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
if returnNodeMayFlowThrough(node, ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -1999,9 +2042,8 @@ private module Stage3 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2011,9 +2053,8 @@ private module Stage3 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2023,9 +2064,8 @@ private module Stage3 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2366,6 +2406,8 @@ private module Stage4 {
Cc ccNone() { result instanceof CallContextAny }
CcCall ccSomeCall() { result instanceof CallContextSomeCall }
private class LocalCc = LocalCallContext;
bindingset[call, c, outercc]
@@ -2434,12 +2476,14 @@ private module Stage4 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
}
/**
@@ -2461,7 +2505,7 @@ private module Stage4 {
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
cc = ccNone() and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and
ap = getApNil(node)
or
@@ -2564,9 +2608,8 @@ private module Stage4 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2581,9 +2624,8 @@ private module Stage4 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2593,10 +2635,8 @@ private module Stage4 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2652,6 +2692,11 @@ private module Stage4 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -2672,7 +2717,7 @@ private module Stage4 {
) {
fwdFlow(node, _, _, ap, config) and
sinkNode(node, config) and
toReturn = false and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and
returnAp = apNone() and
ap instanceof ApNil
or
@@ -2728,7 +2773,7 @@ private module Stage4 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
if returnNodeMayFlowThrough(node, ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -2763,9 +2808,8 @@ private module Stage4 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2775,9 +2819,8 @@ private module Stage4 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2787,9 +2830,8 @@ private module Stage4 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -3064,7 +3106,11 @@ private newtype TPathNode =
// A PathNode is introduced by a source ...
Stage4::revFlow(node, config) and
sourceNode(node, config) and
cc instanceof CallContextAny and
(
if hasSourceCallCtx(config)
then cc instanceof CallContextSomeCall
else cc instanceof CallContextAny
) and
sc instanceof SummaryCtxNone and
ap = TAccessPathNil(node.getDataFlowType())
or
@@ -3076,17 +3122,10 @@ private newtype TPathNode =
)
} or
TPathNodeSink(NodeEx node, Configuration config) {
sinkNode(node, pragma[only_bind_into](config)) and
Stage4::revFlow(node, pragma[only_bind_into](config)) and
(
// A sink that is also a source ...
sourceNode(node, config)
or
// ... or a sink that can be reached from a source
exists(PathNodeMid mid |
pathStep(mid, node, _, _, TAccessPathNil(_)) and
pragma[only_bind_into](config) = mid.getConfiguration()
)
exists(PathNodeMid sink |
sink.isAtSink() and
node = sink.getNodeEx() and
config = sink.getConfiguration()
)
}
@@ -3403,22 +3442,46 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
// an intermediate step to another intermediate node
result = this.getSuccMid()
or
// a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges
exists(PathNodeMid mid, PathNodeSink sink |
mid = this.getSuccMid() and
mid.getNodeEx() = sink.getNodeEx() and
mid.getAp() instanceof AccessPathNil and
sink.getConfiguration() = unbindConf(mid.getConfiguration()) and
result = sink
)
// a final step to a sink
result = this.getSuccMid().projectToSink()
}
override predicate isSource() {
sourceNode(node, config) and
cc instanceof CallContextAny and
(
if hasSourceCallCtx(config)
then cc instanceof CallContextSomeCall
else cc instanceof CallContextAny
) and
sc instanceof SummaryCtxNone and
ap instanceof AccessPathNil
}
predicate isAtSink() {
sinkNode(node, config) and
ap instanceof AccessPathNil and
if hasSinkCallCtx(config)
then
// For `FeatureHasSinkCallContext` the condition `cc instanceof CallContextNoCall`
// is exactly what we need to check. This also implies
// `sc instanceof SummaryCtxNone`.
// For `FeatureEqualSourceSinkCallContext` the initial call context was
// set to `CallContextSomeCall` and jumps are disallowed, so
// `cc instanceof CallContextNoCall` never holds. On the other hand,
// in this case there's never any need to enter a call except to identify
// a summary, so the condition in `pathIntoCallable` enforces this, which
// means that `sc instanceof SummaryCtxNone` holds if and only if we are
// in the call context of the source.
sc instanceof SummaryCtxNone or
cc instanceof CallContextNoCall
else any()
}
PathNodeSink projectToSink() {
this.isAtSink() and
result.getNodeEx() = node and
result.getConfiguration() = unbindConf(config)
}
}
/**
@@ -3572,7 +3635,7 @@ private predicate pathIntoArg(
)
}
pragma[noinline]
pragma[nomagic]
private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) {
@@ -3613,7 +3676,11 @@ private predicate pathIntoCallable(
sc = TSummaryCtxSome(p, ap)
or
not exists(TSummaryCtxSome(p, ap)) and
sc = TSummaryCtxNone()
sc = TSummaryCtxNone() and
// When the call contexts of source and sink needs to match then there's
// never any reason to enter a callable except to find a summary. See also
// the comment in `PathNodeMid::isAtSink`.
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
|
if recordDataFlowCallSite(call, callable)
@@ -3676,13 +3743,14 @@ private module Subpaths {
*/
pragma[nomagic]
private predicate subpaths01(
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, AccessPath apout
) {
exists(Configuration config |
pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and
pathIntoCallable(arg, par, _, innercc, sc, _, config) and
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config))
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config)) and
not arg.isHidden()
)
}
@@ -3716,8 +3784,17 @@ private module Subpaths {
innercc = ret.getCallContext() and
sc = ret.getSummaryCtx() and
ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and
apout = ret.getAp() and
not ret.isHidden()
apout = ret.getAp()
)
}
private PathNodeImpl localStepToHidden(PathNodeImpl n) {
n.getASuccessorImpl() = result and
result.isHidden() and
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
localFlowBigStep(n1, n2, _, _, _, _) or
store(n1, _, n2, _, _) or
read(n1, _, n2, _)
)
}
@@ -3726,11 +3803,12 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) {
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNodeMid out) {
exists(ParamNodeEx p, NodeEx o, AccessPath apout |
pragma[only_bind_into](arg).getASuccessor() = par and
pragma[only_bind_into](arg).getASuccessor() = out and
subpaths03(arg, p, ret, o, apout) and
subpaths03(arg, p, localStepToHidden*(ret), o, apout) and
not ret.isHidden() and
par.getNodeEx() = p and
out.getNodeEx() = o and
out.getAp() = apout

View File

@@ -10,6 +10,7 @@
private import DataFlowImplCommon
private import DataFlowImplSpecific::Private
import DataFlowImplSpecific::Public
import DataFlowImplCommonPublic
/**
* A configuration of interprocedural data flow analysis. This defines
@@ -94,6 +95,22 @@ abstract class Configuration extends string {
*/
int fieldFlowBranchLimit() { result = 2 }
/**
* Gets a data flow configuration feature to add restrictions to the set of
* valid flow paths.
*
* - `FeatureHasSourceCallContext`:
* Assume that sources have some existing call context to disallow
* conflicting return-flow directly following the source.
* - `FeatureHasSinkCallContext`:
* Assume that sinks have some existing call context to disallow
* conflicting argument-to-parameter flow directly preceding the sink.
* - `FeatureEqualSourceSinkCallContext`:
* Implies both of the above and additionally ensures that the entire flow
* path preserves the call context.
*/
FlowFeature getAFeature() { none() }
/**
* Holds if data may flow from `source` to `sink` for this configuration.
*/
@@ -272,6 +289,7 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
config.isBarrier(n)
@@ -290,11 +308,23 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
}
pragma[nomagic]
private predicate sourceNode(NodeEx node, Configuration config) { config.isSource(node.asNode()) }
private predicate sourceNode(NodeEx node, Configuration config) {
config.isSource(node.asNode()) and
not fullBarrier(node, config)
}
pragma[nomagic]
private predicate sinkNode(NodeEx node, Configuration config) { config.isSink(node.asNode()) }
/** 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 fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
/**
* Holds if data can flow in one local step from `node1` to `node2`.
*/
@@ -303,16 +333,14 @@ private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config
node1.asNode() = n1 and
node2.asNode() = n2 and
simpleLocalFlowStepExt(n1, n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
stepFilter(node1, node2, config)
)
or
exists(Node n |
config.allowImplicitRead(n, _) and
node1.asNode() = n and
node2.isImplicitReadNode(n, false)
node2.isImplicitReadNode(n, false) and
not fullBarrier(node1, config)
)
}
@@ -325,16 +353,14 @@ private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configurat
node2.asNode() = n2 and
config.isAdditionalFlowStep(n1, n2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
stepFilter(node1, node2, config)
)
or
exists(Node n |
config.allowImplicitRead(n, _) and
node1.isImplicitReadNode(n, true) and
node2.asNode() = n
node2.asNode() = n and
not fullBarrier(node2, config)
)
}
@@ -346,10 +372,8 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) {
node1.asNode() = n1 and
node2.asNode() = n2 and
jumpStepCached(n1, n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
stepFilter(node1, node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
}
@@ -362,15 +386,14 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c
node2.asNode() = n2 and
config.isAdditionalFlowStep(n1, n2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
stepFilter(node1, node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
}
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
read(node1.asNode(), c, node2.asNode())
read(node1.asNode(), c, node2.asNode()) and
stepFilter(node1, node2, config)
or
exists(Node n |
node2.isImplicitReadNode(n, true) and
@@ -383,7 +406,8 @@ private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
) {
store(node1.asNode(), tc, node2.asNode(), contentType) and
read(_, tc.getContent(), _, config)
read(_, tc.getContent(), _, config) and
stepFilter(node1, node2, config)
}
pragma[nomagic]
@@ -401,6 +425,20 @@ private predicate viableParamArgEx(DataFlowCall call, ParamNodeEx p, ArgNodeEx a
*/
private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 }
private predicate hasSourceCallCtx(Configuration config) {
exists(FlowFeature feature | feature = config.getAFeature() |
feature instanceof FeatureHasSourceCallContext or
feature instanceof FeatureEqualSourceSinkCallContext
)
}
private predicate hasSinkCallCtx(Configuration config) {
exists(FlowFeature feature | feature = config.getAFeature() |
feature instanceof FeatureHasSinkCallContext or
feature instanceof FeatureEqualSourceSinkCallContext
)
}
private module Stage1 {
class ApApprox = Unit;
@@ -418,63 +456,59 @@ private module Stage1 {
* argument in a call.
*/
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
not fullBarrier(node, config) and
(
sourceNode(node, config) and
sourceNode(node, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config)
)
or
// flow into a callable
exists(NodeEx arg |
fwdFlow(arg, _, config) and
viableParamArgEx(_, node, arg) and
cc = true and
not fullBarrier(node, config)
)
or
// flow out of a callable
exists(DataFlowCall call |
fwdFlowOut(call, node, false, config) and
cc = false
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config) and
not outBarrier(mid, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config) and
not inBarrier(node, config)
)
or
// flow into a callable
exists(NodeEx arg |
fwdFlow(arg, _, config) and
viableParamArgEx(_, node, arg) and
cc = true
)
or
// flow out of a callable
exists(DataFlowCall call |
fwdFlowOut(call, node, false, config) and
cc = false
or
fwdFlowOutFromArg(call, node, config) and
fwdFlowIsEntered(call, cc, config)
)
fwdFlowOutFromArg(call, node, config) and
fwdFlowIsEntered(call, cc, config)
)
}
@@ -514,7 +548,8 @@ private module Stage1 {
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
exists(ReturnPosition pos |
fwdFlowReturnPosition(pos, cc, config) and
viableReturnPosOutEx(call, pos, out)
viableReturnPosOutEx(call, pos, out) and
not fullBarrier(out, config)
)
}
@@ -551,7 +586,7 @@ private module Stage1 {
private predicate revFlow0(NodeEx node, boolean toReturn, Configuration config) {
fwdFlow(node, config) and
sinkNode(node, config) and
toReturn = false
if hasSinkCallCtx(config) then toReturn = true else toReturn = false
or
exists(NodeEx mid |
localFlowStep(node, mid, config) and
@@ -740,6 +775,7 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary.
*/
pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and
@@ -937,6 +973,8 @@ private module Stage2 {
Cc ccNone() { result instanceof CallContextAny }
CcCall ccSomeCall() { result instanceof CallContextSomeCall }
private class LocalCc = Unit;
bindingset[call, c, outercc]
@@ -984,12 +1022,14 @@ private module Stage2 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
}
/**
@@ -1004,7 +1044,7 @@ private module Stage2 {
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
cc = ccNone() and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and
ap = getApNil(node)
or
@@ -1107,9 +1147,8 @@ private module Stage2 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1124,9 +1163,8 @@ private module Stage2 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1136,10 +1174,8 @@ private module Stage2 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1195,6 +1231,11 @@ private module Stage2 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -1215,7 +1256,7 @@ private module Stage2 {
) {
fwdFlow(node, _, _, ap, config) and
sinkNode(node, config) and
toReturn = false and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and
returnAp = apNone() and
ap instanceof ApNil
or
@@ -1271,7 +1312,7 @@ private module Stage2 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
if returnNodeMayFlowThrough(node, ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -1306,9 +1347,8 @@ private module Stage2 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1318,9 +1358,8 @@ private module Stage2 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1330,9 +1369,8 @@ private module Stage2 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1616,6 +1654,8 @@ private module Stage3 {
Cc ccNone() { result = false }
CcCall ccSomeCall() { result = true }
private class LocalCc = Unit;
bindingset[call, c, outercc]
@@ -1670,12 +1710,14 @@ private module Stage3 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
}
/**
@@ -1697,7 +1739,7 @@ private module Stage3 {
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
cc = ccNone() and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and
ap = getApNil(node)
or
@@ -1800,9 +1842,8 @@ private module Stage3 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1817,9 +1858,8 @@ private module Stage3 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1829,10 +1869,8 @@ private module Stage3 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1888,6 +1926,11 @@ private module Stage3 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -1908,7 +1951,7 @@ private module Stage3 {
) {
fwdFlow(node, _, _, ap, config) and
sinkNode(node, config) and
toReturn = false and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and
returnAp = apNone() and
ap instanceof ApNil
or
@@ -1964,7 +2007,7 @@ private module Stage3 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
if returnNodeMayFlowThrough(node, ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -1999,9 +2042,8 @@ private module Stage3 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2011,9 +2053,8 @@ private module Stage3 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2023,9 +2064,8 @@ private module Stage3 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2366,6 +2406,8 @@ private module Stage4 {
Cc ccNone() { result instanceof CallContextAny }
CcCall ccSomeCall() { result instanceof CallContextSomeCall }
private class LocalCc = LocalCallContext;
bindingset[call, c, outercc]
@@ -2434,12 +2476,14 @@ private module Stage4 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
}
/**
@@ -2461,7 +2505,7 @@ private module Stage4 {
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
cc = ccNone() and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and
ap = getApNil(node)
or
@@ -2564,9 +2608,8 @@ private module Stage4 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2581,9 +2624,8 @@ private module Stage4 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2593,10 +2635,8 @@ private module Stage4 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2652,6 +2692,11 @@ private module Stage4 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -2672,7 +2717,7 @@ private module Stage4 {
) {
fwdFlow(node, _, _, ap, config) and
sinkNode(node, config) and
toReturn = false and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and
returnAp = apNone() and
ap instanceof ApNil
or
@@ -2728,7 +2773,7 @@ private module Stage4 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
if returnNodeMayFlowThrough(node, ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -2763,9 +2808,8 @@ private module Stage4 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2775,9 +2819,8 @@ private module Stage4 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2787,9 +2830,8 @@ private module Stage4 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -3064,7 +3106,11 @@ private newtype TPathNode =
// A PathNode is introduced by a source ...
Stage4::revFlow(node, config) and
sourceNode(node, config) and
cc instanceof CallContextAny and
(
if hasSourceCallCtx(config)
then cc instanceof CallContextSomeCall
else cc instanceof CallContextAny
) and
sc instanceof SummaryCtxNone and
ap = TAccessPathNil(node.getDataFlowType())
or
@@ -3076,17 +3122,10 @@ private newtype TPathNode =
)
} or
TPathNodeSink(NodeEx node, Configuration config) {
sinkNode(node, pragma[only_bind_into](config)) and
Stage4::revFlow(node, pragma[only_bind_into](config)) and
(
// A sink that is also a source ...
sourceNode(node, config)
or
// ... or a sink that can be reached from a source
exists(PathNodeMid mid |
pathStep(mid, node, _, _, TAccessPathNil(_)) and
pragma[only_bind_into](config) = mid.getConfiguration()
)
exists(PathNodeMid sink |
sink.isAtSink() and
node = sink.getNodeEx() and
config = sink.getConfiguration()
)
}
@@ -3403,22 +3442,46 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
// an intermediate step to another intermediate node
result = this.getSuccMid()
or
// a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges
exists(PathNodeMid mid, PathNodeSink sink |
mid = this.getSuccMid() and
mid.getNodeEx() = sink.getNodeEx() and
mid.getAp() instanceof AccessPathNil and
sink.getConfiguration() = unbindConf(mid.getConfiguration()) and
result = sink
)
// a final step to a sink
result = this.getSuccMid().projectToSink()
}
override predicate isSource() {
sourceNode(node, config) and
cc instanceof CallContextAny and
(
if hasSourceCallCtx(config)
then cc instanceof CallContextSomeCall
else cc instanceof CallContextAny
) and
sc instanceof SummaryCtxNone and
ap instanceof AccessPathNil
}
predicate isAtSink() {
sinkNode(node, config) and
ap instanceof AccessPathNil and
if hasSinkCallCtx(config)
then
// For `FeatureHasSinkCallContext` the condition `cc instanceof CallContextNoCall`
// is exactly what we need to check. This also implies
// `sc instanceof SummaryCtxNone`.
// For `FeatureEqualSourceSinkCallContext` the initial call context was
// set to `CallContextSomeCall` and jumps are disallowed, so
// `cc instanceof CallContextNoCall` never holds. On the other hand,
// in this case there's never any need to enter a call except to identify
// a summary, so the condition in `pathIntoCallable` enforces this, which
// means that `sc instanceof SummaryCtxNone` holds if and only if we are
// in the call context of the source.
sc instanceof SummaryCtxNone or
cc instanceof CallContextNoCall
else any()
}
PathNodeSink projectToSink() {
this.isAtSink() and
result.getNodeEx() = node and
result.getConfiguration() = unbindConf(config)
}
}
/**
@@ -3572,7 +3635,7 @@ private predicate pathIntoArg(
)
}
pragma[noinline]
pragma[nomagic]
private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) {
@@ -3613,7 +3676,11 @@ private predicate pathIntoCallable(
sc = TSummaryCtxSome(p, ap)
or
not exists(TSummaryCtxSome(p, ap)) and
sc = TSummaryCtxNone()
sc = TSummaryCtxNone() and
// When the call contexts of source and sink needs to match then there's
// never any reason to enter a callable except to find a summary. See also
// the comment in `PathNodeMid::isAtSink`.
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
|
if recordDataFlowCallSite(call, callable)
@@ -3676,13 +3743,14 @@ private module Subpaths {
*/
pragma[nomagic]
private predicate subpaths01(
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, AccessPath apout
) {
exists(Configuration config |
pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and
pathIntoCallable(arg, par, _, innercc, sc, _, config) and
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config))
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config)) and
not arg.isHidden()
)
}
@@ -3716,8 +3784,17 @@ private module Subpaths {
innercc = ret.getCallContext() and
sc = ret.getSummaryCtx() and
ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and
apout = ret.getAp() and
not ret.isHidden()
apout = ret.getAp()
)
}
private PathNodeImpl localStepToHidden(PathNodeImpl n) {
n.getASuccessorImpl() = result and
result.isHidden() and
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
localFlowBigStep(n1, n2, _, _, _, _) or
store(n1, _, n2, _, _) or
read(n1, _, n2, _)
)
}
@@ -3726,11 +3803,12 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) {
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNodeMid out) {
exists(ParamNodeEx p, NodeEx o, AccessPath apout |
pragma[only_bind_into](arg).getASuccessor() = par and
pragma[only_bind_into](arg).getASuccessor() = out and
subpaths03(arg, p, ret, o, apout) and
subpaths03(arg, p, localStepToHidden*(ret), o, apout) and
not ret.isHidden() and
par.getNodeEx() = p and
out.getNodeEx() = o and
out.getAp() = apout

View File

@@ -2,6 +2,42 @@ private import DataFlowImplSpecific::Private
private import DataFlowImplSpecific::Public
import Cached
module DataFlowImplCommonPublic {
private newtype TFlowFeature =
TFeatureHasSourceCallContext() or
TFeatureHasSinkCallContext() or
TFeatureEqualSourceSinkCallContext()
/** A flow configuration feature for use in `Configuration::getAFeature()`. */
class FlowFeature extends TFlowFeature {
string toString() { none() }
}
/**
* A flow configuration feature that implies that sources have some existing
* call context.
*/
class FeatureHasSourceCallContext extends FlowFeature, TFeatureHasSourceCallContext {
override string toString() { result = "FeatureHasSourceCallContext" }
}
/**
* A flow configuration feature that implies that sinks have some existing
* call context.
*/
class FeatureHasSinkCallContext extends FlowFeature, TFeatureHasSinkCallContext {
override string toString() { result = "FeatureHasSinkCallContext" }
}
/**
* A flow configuration feature that implies that source-sink pairs have some
* shared existing call context.
*/
class FeatureEqualSourceSinkCallContext extends FlowFeature, TFeatureEqualSourceSinkCallContext {
override string toString() { result = "FeatureEqualSourceSinkCallContext" }
}
}
/**
* The cost limits for the `AccessPathFront` to `AccessPathApprox` expansion.
*

View File

@@ -9,6 +9,19 @@ private import tainttracking1.TaintTrackingParameter::Private
private import tainttracking1.TaintTrackingParameter::Public
module Consistency {
private newtype TConsistencyConfiguration = MkConsistencyConfiguration()
/** A class for configuring the consistency queries. */
class ConsistencyConfiguration extends TConsistencyConfiguration {
string toString() { none() }
/** Holds if `n` should be excluded from the consistency test `postWithInFlow`. */
predicate postWithInFlowExclude(Node n) { none() }
/** Holds if `n` should be excluded from the consistency test `argHasPostUpdate`. */
predicate argHasPostUpdateExclude(ArgumentNode n) { none() }
}
private class RelevantNode extends Node {
RelevantNode() {
this instanceof ArgumentNode or
@@ -164,7 +177,7 @@ module Consistency {
query predicate argHasPostUpdate(ArgumentNode n, string msg) {
not hasPost(n) and
not isImmutableOrUnobservable(n) and
not any(ConsistencyConfiguration c).argHasPostUpdateExclude(n) and
msg = "ArgumentNode is missing PostUpdateNode."
}
@@ -177,6 +190,7 @@ module Consistency {
isPostUpdateNode(n) and
not clearsContent(n, _) and
simpleLocalFlowStep(_, n) and
not any(ConsistencyConfiguration c).postWithInFlowExclude(n) and
msg = "PostUpdateNode should not be the target of local flow."
}
}

View File

@@ -10,6 +10,7 @@
private import DataFlowImplCommon
private import DataFlowImplSpecific::Private
import DataFlowImplSpecific::Public
import DataFlowImplCommonPublic
/**
* A configuration of interprocedural data flow analysis. This defines
@@ -94,6 +95,22 @@ abstract class Configuration extends string {
*/
int fieldFlowBranchLimit() { result = 2 }
/**
* Gets a data flow configuration feature to add restrictions to the set of
* valid flow paths.
*
* - `FeatureHasSourceCallContext`:
* Assume that sources have some existing call context to disallow
* conflicting return-flow directly following the source.
* - `FeatureHasSinkCallContext`:
* Assume that sinks have some existing call context to disallow
* conflicting argument-to-parameter flow directly preceding the sink.
* - `FeatureEqualSourceSinkCallContext`:
* Implies both of the above and additionally ensures that the entire flow
* path preserves the call context.
*/
FlowFeature getAFeature() { none() }
/**
* Holds if data may flow from `source` to `sink` for this configuration.
*/
@@ -272,6 +289,7 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
config.isBarrier(n)
@@ -290,11 +308,23 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
}
pragma[nomagic]
private predicate sourceNode(NodeEx node, Configuration config) { config.isSource(node.asNode()) }
private predicate sourceNode(NodeEx node, Configuration config) {
config.isSource(node.asNode()) and
not fullBarrier(node, config)
}
pragma[nomagic]
private predicate sinkNode(NodeEx node, Configuration config) { config.isSink(node.asNode()) }
/** 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 fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
/**
* Holds if data can flow in one local step from `node1` to `node2`.
*/
@@ -303,16 +333,14 @@ private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config
node1.asNode() = n1 and
node2.asNode() = n2 and
simpleLocalFlowStepExt(n1, n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
stepFilter(node1, node2, config)
)
or
exists(Node n |
config.allowImplicitRead(n, _) and
node1.asNode() = n and
node2.isImplicitReadNode(n, false)
node2.isImplicitReadNode(n, false) and
not fullBarrier(node1, config)
)
}
@@ -325,16 +353,14 @@ private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configurat
node2.asNode() = n2 and
config.isAdditionalFlowStep(n1, n2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
stepFilter(node1, node2, config)
)
or
exists(Node n |
config.allowImplicitRead(n, _) and
node1.isImplicitReadNode(n, true) and
node2.asNode() = n
node2.asNode() = n and
not fullBarrier(node2, config)
)
}
@@ -346,10 +372,8 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) {
node1.asNode() = n1 and
node2.asNode() = n2 and
jumpStepCached(n1, n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
stepFilter(node1, node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
}
@@ -362,15 +386,14 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c
node2.asNode() = n2 and
config.isAdditionalFlowStep(n1, n2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
stepFilter(node1, node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
}
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
read(node1.asNode(), c, node2.asNode())
read(node1.asNode(), c, node2.asNode()) and
stepFilter(node1, node2, config)
or
exists(Node n |
node2.isImplicitReadNode(n, true) and
@@ -383,7 +406,8 @@ private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
) {
store(node1.asNode(), tc, node2.asNode(), contentType) and
read(_, tc.getContent(), _, config)
read(_, tc.getContent(), _, config) and
stepFilter(node1, node2, config)
}
pragma[nomagic]
@@ -401,6 +425,20 @@ private predicate viableParamArgEx(DataFlowCall call, ParamNodeEx p, ArgNodeEx a
*/
private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 }
private predicate hasSourceCallCtx(Configuration config) {
exists(FlowFeature feature | feature = config.getAFeature() |
feature instanceof FeatureHasSourceCallContext or
feature instanceof FeatureEqualSourceSinkCallContext
)
}
private predicate hasSinkCallCtx(Configuration config) {
exists(FlowFeature feature | feature = config.getAFeature() |
feature instanceof FeatureHasSinkCallContext or
feature instanceof FeatureEqualSourceSinkCallContext
)
}
private module Stage1 {
class ApApprox = Unit;
@@ -418,63 +456,59 @@ private module Stage1 {
* argument in a call.
*/
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
not fullBarrier(node, config) and
(
sourceNode(node, config) and
sourceNode(node, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config)
)
or
// flow into a callable
exists(NodeEx arg |
fwdFlow(arg, _, config) and
viableParamArgEx(_, node, arg) and
cc = true and
not fullBarrier(node, config)
)
or
// flow out of a callable
exists(DataFlowCall call |
fwdFlowOut(call, node, false, config) and
cc = false
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config) and
not outBarrier(mid, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config) and
not inBarrier(node, config)
)
or
// flow into a callable
exists(NodeEx arg |
fwdFlow(arg, _, config) and
viableParamArgEx(_, node, arg) and
cc = true
)
or
// flow out of a callable
exists(DataFlowCall call |
fwdFlowOut(call, node, false, config) and
cc = false
or
fwdFlowOutFromArg(call, node, config) and
fwdFlowIsEntered(call, cc, config)
)
fwdFlowOutFromArg(call, node, config) and
fwdFlowIsEntered(call, cc, config)
)
}
@@ -514,7 +548,8 @@ private module Stage1 {
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
exists(ReturnPosition pos |
fwdFlowReturnPosition(pos, cc, config) and
viableReturnPosOutEx(call, pos, out)
viableReturnPosOutEx(call, pos, out) and
not fullBarrier(out, config)
)
}
@@ -551,7 +586,7 @@ private module Stage1 {
private predicate revFlow0(NodeEx node, boolean toReturn, Configuration config) {
fwdFlow(node, config) and
sinkNode(node, config) and
toReturn = false
if hasSinkCallCtx(config) then toReturn = true else toReturn = false
or
exists(NodeEx mid |
localFlowStep(node, mid, config) and
@@ -740,6 +775,7 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary.
*/
pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and
@@ -937,6 +973,8 @@ private module Stage2 {
Cc ccNone() { result instanceof CallContextAny }
CcCall ccSomeCall() { result instanceof CallContextSomeCall }
private class LocalCc = Unit;
bindingset[call, c, outercc]
@@ -984,12 +1022,14 @@ private module Stage2 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
}
/**
@@ -1004,7 +1044,7 @@ private module Stage2 {
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
cc = ccNone() and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and
ap = getApNil(node)
or
@@ -1107,9 +1147,8 @@ private module Stage2 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1124,9 +1163,8 @@ private module Stage2 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1136,10 +1174,8 @@ private module Stage2 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1195,6 +1231,11 @@ private module Stage2 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -1215,7 +1256,7 @@ private module Stage2 {
) {
fwdFlow(node, _, _, ap, config) and
sinkNode(node, config) and
toReturn = false and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and
returnAp = apNone() and
ap instanceof ApNil
or
@@ -1271,7 +1312,7 @@ private module Stage2 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
if returnNodeMayFlowThrough(node, ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -1306,9 +1347,8 @@ private module Stage2 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1318,9 +1358,8 @@ private module Stage2 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1330,9 +1369,8 @@ private module Stage2 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1616,6 +1654,8 @@ private module Stage3 {
Cc ccNone() { result = false }
CcCall ccSomeCall() { result = true }
private class LocalCc = Unit;
bindingset[call, c, outercc]
@@ -1670,12 +1710,14 @@ private module Stage3 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
}
/**
@@ -1697,7 +1739,7 @@ private module Stage3 {
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
cc = ccNone() and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and
ap = getApNil(node)
or
@@ -1800,9 +1842,8 @@ private module Stage3 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1817,9 +1858,8 @@ private module Stage3 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1829,10 +1869,8 @@ private module Stage3 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1888,6 +1926,11 @@ private module Stage3 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -1908,7 +1951,7 @@ private module Stage3 {
) {
fwdFlow(node, _, _, ap, config) and
sinkNode(node, config) and
toReturn = false and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and
returnAp = apNone() and
ap instanceof ApNil
or
@@ -1964,7 +2007,7 @@ private module Stage3 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
if returnNodeMayFlowThrough(node, ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -1999,9 +2042,8 @@ private module Stage3 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2011,9 +2053,8 @@ private module Stage3 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2023,9 +2064,8 @@ private module Stage3 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2366,6 +2406,8 @@ private module Stage4 {
Cc ccNone() { result instanceof CallContextAny }
CcCall ccSomeCall() { result instanceof CallContextSomeCall }
private class LocalCc = LocalCallContext;
bindingset[call, c, outercc]
@@ -2434,12 +2476,14 @@ private module Stage4 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
}
/**
@@ -2461,7 +2505,7 @@ private module Stage4 {
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
cc = ccNone() and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and
ap = getApNil(node)
or
@@ -2564,9 +2608,8 @@ private module Stage4 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2581,9 +2624,8 @@ private module Stage4 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2593,10 +2635,8 @@ private module Stage4 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2652,6 +2692,11 @@ private module Stage4 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -2672,7 +2717,7 @@ private module Stage4 {
) {
fwdFlow(node, _, _, ap, config) and
sinkNode(node, config) and
toReturn = false and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and
returnAp = apNone() and
ap instanceof ApNil
or
@@ -2728,7 +2773,7 @@ private module Stage4 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
if returnNodeMayFlowThrough(node, ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -2763,9 +2808,8 @@ private module Stage4 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2775,9 +2819,8 @@ private module Stage4 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2787,9 +2830,8 @@ private module Stage4 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -3064,7 +3106,11 @@ private newtype TPathNode =
// A PathNode is introduced by a source ...
Stage4::revFlow(node, config) and
sourceNode(node, config) and
cc instanceof CallContextAny and
(
if hasSourceCallCtx(config)
then cc instanceof CallContextSomeCall
else cc instanceof CallContextAny
) and
sc instanceof SummaryCtxNone and
ap = TAccessPathNil(node.getDataFlowType())
or
@@ -3076,17 +3122,10 @@ private newtype TPathNode =
)
} or
TPathNodeSink(NodeEx node, Configuration config) {
sinkNode(node, pragma[only_bind_into](config)) and
Stage4::revFlow(node, pragma[only_bind_into](config)) and
(
// A sink that is also a source ...
sourceNode(node, config)
or
// ... or a sink that can be reached from a source
exists(PathNodeMid mid |
pathStep(mid, node, _, _, TAccessPathNil(_)) and
pragma[only_bind_into](config) = mid.getConfiguration()
)
exists(PathNodeMid sink |
sink.isAtSink() and
node = sink.getNodeEx() and
config = sink.getConfiguration()
)
}
@@ -3403,22 +3442,46 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
// an intermediate step to another intermediate node
result = this.getSuccMid()
or
// a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges
exists(PathNodeMid mid, PathNodeSink sink |
mid = this.getSuccMid() and
mid.getNodeEx() = sink.getNodeEx() and
mid.getAp() instanceof AccessPathNil and
sink.getConfiguration() = unbindConf(mid.getConfiguration()) and
result = sink
)
// a final step to a sink
result = this.getSuccMid().projectToSink()
}
override predicate isSource() {
sourceNode(node, config) and
cc instanceof CallContextAny and
(
if hasSourceCallCtx(config)
then cc instanceof CallContextSomeCall
else cc instanceof CallContextAny
) and
sc instanceof SummaryCtxNone and
ap instanceof AccessPathNil
}
predicate isAtSink() {
sinkNode(node, config) and
ap instanceof AccessPathNil and
if hasSinkCallCtx(config)
then
// For `FeatureHasSinkCallContext` the condition `cc instanceof CallContextNoCall`
// is exactly what we need to check. This also implies
// `sc instanceof SummaryCtxNone`.
// For `FeatureEqualSourceSinkCallContext` the initial call context was
// set to `CallContextSomeCall` and jumps are disallowed, so
// `cc instanceof CallContextNoCall` never holds. On the other hand,
// in this case there's never any need to enter a call except to identify
// a summary, so the condition in `pathIntoCallable` enforces this, which
// means that `sc instanceof SummaryCtxNone` holds if and only if we are
// in the call context of the source.
sc instanceof SummaryCtxNone or
cc instanceof CallContextNoCall
else any()
}
PathNodeSink projectToSink() {
this.isAtSink() and
result.getNodeEx() = node and
result.getConfiguration() = unbindConf(config)
}
}
/**
@@ -3572,7 +3635,7 @@ private predicate pathIntoArg(
)
}
pragma[noinline]
pragma[nomagic]
private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) {
@@ -3613,7 +3676,11 @@ private predicate pathIntoCallable(
sc = TSummaryCtxSome(p, ap)
or
not exists(TSummaryCtxSome(p, ap)) and
sc = TSummaryCtxNone()
sc = TSummaryCtxNone() and
// When the call contexts of source and sink needs to match then there's
// never any reason to enter a callable except to find a summary. See also
// the comment in `PathNodeMid::isAtSink`.
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
|
if recordDataFlowCallSite(call, callable)
@@ -3676,13 +3743,14 @@ private module Subpaths {
*/
pragma[nomagic]
private predicate subpaths01(
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, AccessPath apout
) {
exists(Configuration config |
pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and
pathIntoCallable(arg, par, _, innercc, sc, _, config) and
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config))
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config)) and
not arg.isHidden()
)
}
@@ -3716,8 +3784,17 @@ private module Subpaths {
innercc = ret.getCallContext() and
sc = ret.getSummaryCtx() and
ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and
apout = ret.getAp() and
not ret.isHidden()
apout = ret.getAp()
)
}
private PathNodeImpl localStepToHidden(PathNodeImpl n) {
n.getASuccessorImpl() = result and
result.isHidden() and
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
localFlowBigStep(n1, n2, _, _, _, _) or
store(n1, _, n2, _, _) or
read(n1, _, n2, _)
)
}
@@ -3726,11 +3803,12 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) {
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNodeMid out) {
exists(ParamNodeEx p, NodeEx o, AccessPath apout |
pragma[only_bind_into](arg).getASuccessor() = par and
pragma[only_bind_into](arg).getASuccessor() = out and
subpaths03(arg, p, ret, o, apout) and
subpaths03(arg, p, localStepToHidden*(ret), o, apout) and
not ret.isHidden() and
par.getNodeEx() = p and
out.getNodeEx() = o and
out.getAp() = apout

View File

@@ -2,6 +2,7 @@ private import cpp
private import DataFlowUtil
private import DataFlowDispatch
private import FlowVar
private import DataFlowImplConsistency
/** Gets the callable in which this node occurs. */
DataFlowCallable nodeGetEnclosingCallable(Node n) { result = n.getEnclosingCallable() }
@@ -259,27 +260,6 @@ class Unit extends TUnit {
string toString() { result = "unit" }
}
/**
* Holds if `n` does not require a `PostUpdateNode` as it either cannot be
* modified or its modification cannot be observed, for example if it is a
* freshly created object that is not saved in a variable.
*
* This predicate is only used for consistency checks.
*/
predicate isImmutableOrUnobservable(Node n) {
// Is the null pointer (or something that's not really a pointer)
exists(n.asExpr().getValue())
or
// Isn't a pointer or is a pointer to const
forall(DerivedType dt | dt = n.asExpr().getActualType() |
dt.getBaseType().isConst()
or
dt.getBaseType() instanceof RoutineType
)
// The above list of cases isn't exhaustive, but it narrows down the
// consistency alerts enough that most of them are interesting.
}
/** Holds if `n` should be hidden from path explanations. */
predicate nodeIsHidden(Node n) { none() }
@@ -302,3 +282,19 @@ predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preserves
* by default as a heuristic.
*/
predicate allowParameterReturnInSelf(ParameterNode p) { none() }
private class MyConsistencyConfiguration extends Consistency::ConsistencyConfiguration {
override predicate argHasPostUpdateExclude(ArgumentNode n) {
// Is the null pointer (or something that's not really a pointer)
exists(n.asExpr().getValue())
or
// Isn't a pointer or is a pointer to const
forall(DerivedType dt | dt = n.asExpr().getActualType() |
dt.getBaseType().isConst()
or
dt.getBaseType() instanceof RoutineType
)
// The above list of cases isn't exhaustive, but it narrows down the
// consistency alerts enough that most of them are interesting.
}
}

View File

@@ -474,6 +474,25 @@ module TaintedWithPath {
}
}
/**
* INTERNAL: Do not use.
*/
module Private {
/** Gets a predecessor `PathNode` of `pathNode`, if any. */
PathNode getAPredecessor(PathNode pathNode) { edges(result, pathNode) }
/** Gets the element that `pathNode` wraps, if any. */
Element getElementFromPathNode(PathNode pathNode) {
exists(DataFlow::Node node | node = pathNode.(WrapPathNode).inner().getNode() |
result = node.asInstruction().getAST()
or
result = node.asOperand().getDef().getAST()
)
or
result = pathNode.(EndpointPathNode).inner()
}
}
private class WrapPathNode extends PathNode, TWrapPathNode {
DataFlow3::PathNode inner() { this = TWrapPathNode(result) }

View File

@@ -63,8 +63,10 @@ private module VirtualDispatch {
|
// Call argument
exists(DataFlowCall call, int i |
other.(DataFlow::ParameterNode).isParameterOf(call.getStaticCallTarget(), i) and
src.(ArgumentNode).argumentOf(call, i)
other
.(DataFlow::ParameterNode)
.isParameterOf(pragma[only_bind_into](call).getStaticCallTarget(), i) and
src.(ArgumentNode).argumentOf(call, pragma[only_bind_into](pragma[only_bind_out](i)))
) and
allowOtherFromArg = true and
allowFromArg = true
@@ -128,6 +130,7 @@ private module VirtualDispatch {
*
* Used to fix a join ordering issue in flowsFrom.
*/
pragma[noinline]
private predicate returnNodeWithKindAndEnclosingCallable(
ReturnNode node, ReturnKind kind, DataFlowCallable callable
) {

View File

@@ -10,6 +10,7 @@
private import DataFlowImplCommon
private import DataFlowImplSpecific::Private
import DataFlowImplSpecific::Public
import DataFlowImplCommonPublic
/**
* A configuration of interprocedural data flow analysis. This defines
@@ -94,6 +95,22 @@ abstract class Configuration extends string {
*/
int fieldFlowBranchLimit() { result = 2 }
/**
* Gets a data flow configuration feature to add restrictions to the set of
* valid flow paths.
*
* - `FeatureHasSourceCallContext`:
* Assume that sources have some existing call context to disallow
* conflicting return-flow directly following the source.
* - `FeatureHasSinkCallContext`:
* Assume that sinks have some existing call context to disallow
* conflicting argument-to-parameter flow directly preceding the sink.
* - `FeatureEqualSourceSinkCallContext`:
* Implies both of the above and additionally ensures that the entire flow
* path preserves the call context.
*/
FlowFeature getAFeature() { none() }
/**
* Holds if data may flow from `source` to `sink` for this configuration.
*/
@@ -272,6 +289,7 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
config.isBarrier(n)
@@ -290,11 +308,23 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
}
pragma[nomagic]
private predicate sourceNode(NodeEx node, Configuration config) { config.isSource(node.asNode()) }
private predicate sourceNode(NodeEx node, Configuration config) {
config.isSource(node.asNode()) and
not fullBarrier(node, config)
}
pragma[nomagic]
private predicate sinkNode(NodeEx node, Configuration config) { config.isSink(node.asNode()) }
/** 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 fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
/**
* Holds if data can flow in one local step from `node1` to `node2`.
*/
@@ -303,16 +333,14 @@ private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config
node1.asNode() = n1 and
node2.asNode() = n2 and
simpleLocalFlowStepExt(n1, n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
stepFilter(node1, node2, config)
)
or
exists(Node n |
config.allowImplicitRead(n, _) and
node1.asNode() = n and
node2.isImplicitReadNode(n, false)
node2.isImplicitReadNode(n, false) and
not fullBarrier(node1, config)
)
}
@@ -325,16 +353,14 @@ private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configurat
node2.asNode() = n2 and
config.isAdditionalFlowStep(n1, n2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
stepFilter(node1, node2, config)
)
or
exists(Node n |
config.allowImplicitRead(n, _) and
node1.isImplicitReadNode(n, true) and
node2.asNode() = n
node2.asNode() = n and
not fullBarrier(node2, config)
)
}
@@ -346,10 +372,8 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) {
node1.asNode() = n1 and
node2.asNode() = n2 and
jumpStepCached(n1, n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
stepFilter(node1, node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
}
@@ -362,15 +386,14 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c
node2.asNode() = n2 and
config.isAdditionalFlowStep(n1, n2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
stepFilter(node1, node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
}
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
read(node1.asNode(), c, node2.asNode())
read(node1.asNode(), c, node2.asNode()) and
stepFilter(node1, node2, config)
or
exists(Node n |
node2.isImplicitReadNode(n, true) and
@@ -383,7 +406,8 @@ private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
) {
store(node1.asNode(), tc, node2.asNode(), contentType) and
read(_, tc.getContent(), _, config)
read(_, tc.getContent(), _, config) and
stepFilter(node1, node2, config)
}
pragma[nomagic]
@@ -401,6 +425,20 @@ private predicate viableParamArgEx(DataFlowCall call, ParamNodeEx p, ArgNodeEx a
*/
private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 }
private predicate hasSourceCallCtx(Configuration config) {
exists(FlowFeature feature | feature = config.getAFeature() |
feature instanceof FeatureHasSourceCallContext or
feature instanceof FeatureEqualSourceSinkCallContext
)
}
private predicate hasSinkCallCtx(Configuration config) {
exists(FlowFeature feature | feature = config.getAFeature() |
feature instanceof FeatureHasSinkCallContext or
feature instanceof FeatureEqualSourceSinkCallContext
)
}
private module Stage1 {
class ApApprox = Unit;
@@ -418,63 +456,59 @@ private module Stage1 {
* argument in a call.
*/
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
not fullBarrier(node, config) and
(
sourceNode(node, config) and
sourceNode(node, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config)
)
or
// flow into a callable
exists(NodeEx arg |
fwdFlow(arg, _, config) and
viableParamArgEx(_, node, arg) and
cc = true and
not fullBarrier(node, config)
)
or
// flow out of a callable
exists(DataFlowCall call |
fwdFlowOut(call, node, false, config) and
cc = false
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config) and
not outBarrier(mid, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config) and
not inBarrier(node, config)
)
or
// flow into a callable
exists(NodeEx arg |
fwdFlow(arg, _, config) and
viableParamArgEx(_, node, arg) and
cc = true
)
or
// flow out of a callable
exists(DataFlowCall call |
fwdFlowOut(call, node, false, config) and
cc = false
or
fwdFlowOutFromArg(call, node, config) and
fwdFlowIsEntered(call, cc, config)
)
fwdFlowOutFromArg(call, node, config) and
fwdFlowIsEntered(call, cc, config)
)
}
@@ -514,7 +548,8 @@ private module Stage1 {
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
exists(ReturnPosition pos |
fwdFlowReturnPosition(pos, cc, config) and
viableReturnPosOutEx(call, pos, out)
viableReturnPosOutEx(call, pos, out) and
not fullBarrier(out, config)
)
}
@@ -551,7 +586,7 @@ private module Stage1 {
private predicate revFlow0(NodeEx node, boolean toReturn, Configuration config) {
fwdFlow(node, config) and
sinkNode(node, config) and
toReturn = false
if hasSinkCallCtx(config) then toReturn = true else toReturn = false
or
exists(NodeEx mid |
localFlowStep(node, mid, config) and
@@ -740,6 +775,7 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary.
*/
pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and
@@ -937,6 +973,8 @@ private module Stage2 {
Cc ccNone() { result instanceof CallContextAny }
CcCall ccSomeCall() { result instanceof CallContextSomeCall }
private class LocalCc = Unit;
bindingset[call, c, outercc]
@@ -984,12 +1022,14 @@ private module Stage2 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
}
/**
@@ -1004,7 +1044,7 @@ private module Stage2 {
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
cc = ccNone() and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and
ap = getApNil(node)
or
@@ -1107,9 +1147,8 @@ private module Stage2 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1124,9 +1163,8 @@ private module Stage2 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1136,10 +1174,8 @@ private module Stage2 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1195,6 +1231,11 @@ private module Stage2 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -1215,7 +1256,7 @@ private module Stage2 {
) {
fwdFlow(node, _, _, ap, config) and
sinkNode(node, config) and
toReturn = false and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and
returnAp = apNone() and
ap instanceof ApNil
or
@@ -1271,7 +1312,7 @@ private module Stage2 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
if returnNodeMayFlowThrough(node, ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -1306,9 +1347,8 @@ private module Stage2 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1318,9 +1358,8 @@ private module Stage2 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1330,9 +1369,8 @@ private module Stage2 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1616,6 +1654,8 @@ private module Stage3 {
Cc ccNone() { result = false }
CcCall ccSomeCall() { result = true }
private class LocalCc = Unit;
bindingset[call, c, outercc]
@@ -1670,12 +1710,14 @@ private module Stage3 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
}
/**
@@ -1697,7 +1739,7 @@ private module Stage3 {
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
cc = ccNone() and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and
ap = getApNil(node)
or
@@ -1800,9 +1842,8 @@ private module Stage3 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1817,9 +1858,8 @@ private module Stage3 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1829,10 +1869,8 @@ private module Stage3 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1888,6 +1926,11 @@ private module Stage3 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -1908,7 +1951,7 @@ private module Stage3 {
) {
fwdFlow(node, _, _, ap, config) and
sinkNode(node, config) and
toReturn = false and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and
returnAp = apNone() and
ap instanceof ApNil
or
@@ -1964,7 +2007,7 @@ private module Stage3 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
if returnNodeMayFlowThrough(node, ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -1999,9 +2042,8 @@ private module Stage3 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2011,9 +2053,8 @@ private module Stage3 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2023,9 +2064,8 @@ private module Stage3 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2366,6 +2406,8 @@ private module Stage4 {
Cc ccNone() { result instanceof CallContextAny }
CcCall ccSomeCall() { result instanceof CallContextSomeCall }
private class LocalCc = LocalCallContext;
bindingset[call, c, outercc]
@@ -2434,12 +2476,14 @@ private module Stage4 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
}
/**
@@ -2461,7 +2505,7 @@ private module Stage4 {
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
cc = ccNone() and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and
ap = getApNil(node)
or
@@ -2564,9 +2608,8 @@ private module Stage4 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2581,9 +2624,8 @@ private module Stage4 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2593,10 +2635,8 @@ private module Stage4 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2652,6 +2692,11 @@ private module Stage4 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -2672,7 +2717,7 @@ private module Stage4 {
) {
fwdFlow(node, _, _, ap, config) and
sinkNode(node, config) and
toReturn = false and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and
returnAp = apNone() and
ap instanceof ApNil
or
@@ -2728,7 +2773,7 @@ private module Stage4 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
if returnNodeMayFlowThrough(node, ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -2763,9 +2808,8 @@ private module Stage4 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2775,9 +2819,8 @@ private module Stage4 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2787,9 +2830,8 @@ private module Stage4 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -3064,7 +3106,11 @@ private newtype TPathNode =
// A PathNode is introduced by a source ...
Stage4::revFlow(node, config) and
sourceNode(node, config) and
cc instanceof CallContextAny and
(
if hasSourceCallCtx(config)
then cc instanceof CallContextSomeCall
else cc instanceof CallContextAny
) and
sc instanceof SummaryCtxNone and
ap = TAccessPathNil(node.getDataFlowType())
or
@@ -3076,17 +3122,10 @@ private newtype TPathNode =
)
} or
TPathNodeSink(NodeEx node, Configuration config) {
sinkNode(node, pragma[only_bind_into](config)) and
Stage4::revFlow(node, pragma[only_bind_into](config)) and
(
// A sink that is also a source ...
sourceNode(node, config)
or
// ... or a sink that can be reached from a source
exists(PathNodeMid mid |
pathStep(mid, node, _, _, TAccessPathNil(_)) and
pragma[only_bind_into](config) = mid.getConfiguration()
)
exists(PathNodeMid sink |
sink.isAtSink() and
node = sink.getNodeEx() and
config = sink.getConfiguration()
)
}
@@ -3403,22 +3442,46 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
// an intermediate step to another intermediate node
result = this.getSuccMid()
or
// a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges
exists(PathNodeMid mid, PathNodeSink sink |
mid = this.getSuccMid() and
mid.getNodeEx() = sink.getNodeEx() and
mid.getAp() instanceof AccessPathNil and
sink.getConfiguration() = unbindConf(mid.getConfiguration()) and
result = sink
)
// a final step to a sink
result = this.getSuccMid().projectToSink()
}
override predicate isSource() {
sourceNode(node, config) and
cc instanceof CallContextAny and
(
if hasSourceCallCtx(config)
then cc instanceof CallContextSomeCall
else cc instanceof CallContextAny
) and
sc instanceof SummaryCtxNone and
ap instanceof AccessPathNil
}
predicate isAtSink() {
sinkNode(node, config) and
ap instanceof AccessPathNil and
if hasSinkCallCtx(config)
then
// For `FeatureHasSinkCallContext` the condition `cc instanceof CallContextNoCall`
// is exactly what we need to check. This also implies
// `sc instanceof SummaryCtxNone`.
// For `FeatureEqualSourceSinkCallContext` the initial call context was
// set to `CallContextSomeCall` and jumps are disallowed, so
// `cc instanceof CallContextNoCall` never holds. On the other hand,
// in this case there's never any need to enter a call except to identify
// a summary, so the condition in `pathIntoCallable` enforces this, which
// means that `sc instanceof SummaryCtxNone` holds if and only if we are
// in the call context of the source.
sc instanceof SummaryCtxNone or
cc instanceof CallContextNoCall
else any()
}
PathNodeSink projectToSink() {
this.isAtSink() and
result.getNodeEx() = node and
result.getConfiguration() = unbindConf(config)
}
}
/**
@@ -3572,7 +3635,7 @@ private predicate pathIntoArg(
)
}
pragma[noinline]
pragma[nomagic]
private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) {
@@ -3613,7 +3676,11 @@ private predicate pathIntoCallable(
sc = TSummaryCtxSome(p, ap)
or
not exists(TSummaryCtxSome(p, ap)) and
sc = TSummaryCtxNone()
sc = TSummaryCtxNone() and
// When the call contexts of source and sink needs to match then there's
// never any reason to enter a callable except to find a summary. See also
// the comment in `PathNodeMid::isAtSink`.
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
|
if recordDataFlowCallSite(call, callable)
@@ -3676,13 +3743,14 @@ private module Subpaths {
*/
pragma[nomagic]
private predicate subpaths01(
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, AccessPath apout
) {
exists(Configuration config |
pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and
pathIntoCallable(arg, par, _, innercc, sc, _, config) and
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config))
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config)) and
not arg.isHidden()
)
}
@@ -3716,8 +3784,17 @@ private module Subpaths {
innercc = ret.getCallContext() and
sc = ret.getSummaryCtx() and
ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and
apout = ret.getAp() and
not ret.isHidden()
apout = ret.getAp()
)
}
private PathNodeImpl localStepToHidden(PathNodeImpl n) {
n.getASuccessorImpl() = result and
result.isHidden() and
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
localFlowBigStep(n1, n2, _, _, _, _) or
store(n1, _, n2, _, _) or
read(n1, _, n2, _)
)
}
@@ -3726,11 +3803,12 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) {
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNodeMid out) {
exists(ParamNodeEx p, NodeEx o, AccessPath apout |
pragma[only_bind_into](arg).getASuccessor() = par and
pragma[only_bind_into](arg).getASuccessor() = out and
subpaths03(arg, p, ret, o, apout) and
subpaths03(arg, p, localStepToHidden*(ret), o, apout) and
not ret.isHidden() and
par.getNodeEx() = p and
out.getNodeEx() = o and
out.getAp() = apout

View File

@@ -10,6 +10,7 @@
private import DataFlowImplCommon
private import DataFlowImplSpecific::Private
import DataFlowImplSpecific::Public
import DataFlowImplCommonPublic
/**
* A configuration of interprocedural data flow analysis. This defines
@@ -94,6 +95,22 @@ abstract class Configuration extends string {
*/
int fieldFlowBranchLimit() { result = 2 }
/**
* Gets a data flow configuration feature to add restrictions to the set of
* valid flow paths.
*
* - `FeatureHasSourceCallContext`:
* Assume that sources have some existing call context to disallow
* conflicting return-flow directly following the source.
* - `FeatureHasSinkCallContext`:
* Assume that sinks have some existing call context to disallow
* conflicting argument-to-parameter flow directly preceding the sink.
* - `FeatureEqualSourceSinkCallContext`:
* Implies both of the above and additionally ensures that the entire flow
* path preserves the call context.
*/
FlowFeature getAFeature() { none() }
/**
* Holds if data may flow from `source` to `sink` for this configuration.
*/
@@ -272,6 +289,7 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
config.isBarrier(n)
@@ -290,11 +308,23 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
}
pragma[nomagic]
private predicate sourceNode(NodeEx node, Configuration config) { config.isSource(node.asNode()) }
private predicate sourceNode(NodeEx node, Configuration config) {
config.isSource(node.asNode()) and
not fullBarrier(node, config)
}
pragma[nomagic]
private predicate sinkNode(NodeEx node, Configuration config) { config.isSink(node.asNode()) }
/** 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 fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
/**
* Holds if data can flow in one local step from `node1` to `node2`.
*/
@@ -303,16 +333,14 @@ private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config
node1.asNode() = n1 and
node2.asNode() = n2 and
simpleLocalFlowStepExt(n1, n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
stepFilter(node1, node2, config)
)
or
exists(Node n |
config.allowImplicitRead(n, _) and
node1.asNode() = n and
node2.isImplicitReadNode(n, false)
node2.isImplicitReadNode(n, false) and
not fullBarrier(node1, config)
)
}
@@ -325,16 +353,14 @@ private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configurat
node2.asNode() = n2 and
config.isAdditionalFlowStep(n1, n2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
stepFilter(node1, node2, config)
)
or
exists(Node n |
config.allowImplicitRead(n, _) and
node1.isImplicitReadNode(n, true) and
node2.asNode() = n
node2.asNode() = n and
not fullBarrier(node2, config)
)
}
@@ -346,10 +372,8 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) {
node1.asNode() = n1 and
node2.asNode() = n2 and
jumpStepCached(n1, n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
stepFilter(node1, node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
}
@@ -362,15 +386,14 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c
node2.asNode() = n2 and
config.isAdditionalFlowStep(n1, n2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
stepFilter(node1, node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
}
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
read(node1.asNode(), c, node2.asNode())
read(node1.asNode(), c, node2.asNode()) and
stepFilter(node1, node2, config)
or
exists(Node n |
node2.isImplicitReadNode(n, true) and
@@ -383,7 +406,8 @@ private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
) {
store(node1.asNode(), tc, node2.asNode(), contentType) and
read(_, tc.getContent(), _, config)
read(_, tc.getContent(), _, config) and
stepFilter(node1, node2, config)
}
pragma[nomagic]
@@ -401,6 +425,20 @@ private predicate viableParamArgEx(DataFlowCall call, ParamNodeEx p, ArgNodeEx a
*/
private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 }
private predicate hasSourceCallCtx(Configuration config) {
exists(FlowFeature feature | feature = config.getAFeature() |
feature instanceof FeatureHasSourceCallContext or
feature instanceof FeatureEqualSourceSinkCallContext
)
}
private predicate hasSinkCallCtx(Configuration config) {
exists(FlowFeature feature | feature = config.getAFeature() |
feature instanceof FeatureHasSinkCallContext or
feature instanceof FeatureEqualSourceSinkCallContext
)
}
private module Stage1 {
class ApApprox = Unit;
@@ -418,63 +456,59 @@ private module Stage1 {
* argument in a call.
*/
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
not fullBarrier(node, config) and
(
sourceNode(node, config) and
sourceNode(node, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config)
)
or
// flow into a callable
exists(NodeEx arg |
fwdFlow(arg, _, config) and
viableParamArgEx(_, node, arg) and
cc = true and
not fullBarrier(node, config)
)
or
// flow out of a callable
exists(DataFlowCall call |
fwdFlowOut(call, node, false, config) and
cc = false
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config) and
not outBarrier(mid, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config) and
not inBarrier(node, config)
)
or
// flow into a callable
exists(NodeEx arg |
fwdFlow(arg, _, config) and
viableParamArgEx(_, node, arg) and
cc = true
)
or
// flow out of a callable
exists(DataFlowCall call |
fwdFlowOut(call, node, false, config) and
cc = false
or
fwdFlowOutFromArg(call, node, config) and
fwdFlowIsEntered(call, cc, config)
)
fwdFlowOutFromArg(call, node, config) and
fwdFlowIsEntered(call, cc, config)
)
}
@@ -514,7 +548,8 @@ private module Stage1 {
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
exists(ReturnPosition pos |
fwdFlowReturnPosition(pos, cc, config) and
viableReturnPosOutEx(call, pos, out)
viableReturnPosOutEx(call, pos, out) and
not fullBarrier(out, config)
)
}
@@ -551,7 +586,7 @@ private module Stage1 {
private predicate revFlow0(NodeEx node, boolean toReturn, Configuration config) {
fwdFlow(node, config) and
sinkNode(node, config) and
toReturn = false
if hasSinkCallCtx(config) then toReturn = true else toReturn = false
or
exists(NodeEx mid |
localFlowStep(node, mid, config) and
@@ -740,6 +775,7 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary.
*/
pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and
@@ -937,6 +973,8 @@ private module Stage2 {
Cc ccNone() { result instanceof CallContextAny }
CcCall ccSomeCall() { result instanceof CallContextSomeCall }
private class LocalCc = Unit;
bindingset[call, c, outercc]
@@ -984,12 +1022,14 @@ private module Stage2 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
}
/**
@@ -1004,7 +1044,7 @@ private module Stage2 {
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
cc = ccNone() and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and
ap = getApNil(node)
or
@@ -1107,9 +1147,8 @@ private module Stage2 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1124,9 +1163,8 @@ private module Stage2 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1136,10 +1174,8 @@ private module Stage2 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1195,6 +1231,11 @@ private module Stage2 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -1215,7 +1256,7 @@ private module Stage2 {
) {
fwdFlow(node, _, _, ap, config) and
sinkNode(node, config) and
toReturn = false and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and
returnAp = apNone() and
ap instanceof ApNil
or
@@ -1271,7 +1312,7 @@ private module Stage2 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
if returnNodeMayFlowThrough(node, ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -1306,9 +1347,8 @@ private module Stage2 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1318,9 +1358,8 @@ private module Stage2 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1330,9 +1369,8 @@ private module Stage2 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1616,6 +1654,8 @@ private module Stage3 {
Cc ccNone() { result = false }
CcCall ccSomeCall() { result = true }
private class LocalCc = Unit;
bindingset[call, c, outercc]
@@ -1670,12 +1710,14 @@ private module Stage3 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
}
/**
@@ -1697,7 +1739,7 @@ private module Stage3 {
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
cc = ccNone() and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and
ap = getApNil(node)
or
@@ -1800,9 +1842,8 @@ private module Stage3 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1817,9 +1858,8 @@ private module Stage3 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1829,10 +1869,8 @@ private module Stage3 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1888,6 +1926,11 @@ private module Stage3 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -1908,7 +1951,7 @@ private module Stage3 {
) {
fwdFlow(node, _, _, ap, config) and
sinkNode(node, config) and
toReturn = false and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and
returnAp = apNone() and
ap instanceof ApNil
or
@@ -1964,7 +2007,7 @@ private module Stage3 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
if returnNodeMayFlowThrough(node, ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -1999,9 +2042,8 @@ private module Stage3 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2011,9 +2053,8 @@ private module Stage3 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2023,9 +2064,8 @@ private module Stage3 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2366,6 +2406,8 @@ private module Stage4 {
Cc ccNone() { result instanceof CallContextAny }
CcCall ccSomeCall() { result instanceof CallContextSomeCall }
private class LocalCc = LocalCallContext;
bindingset[call, c, outercc]
@@ -2434,12 +2476,14 @@ private module Stage4 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
}
/**
@@ -2461,7 +2505,7 @@ private module Stage4 {
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
cc = ccNone() and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and
ap = getApNil(node)
or
@@ -2564,9 +2608,8 @@ private module Stage4 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2581,9 +2624,8 @@ private module Stage4 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2593,10 +2635,8 @@ private module Stage4 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2652,6 +2692,11 @@ private module Stage4 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -2672,7 +2717,7 @@ private module Stage4 {
) {
fwdFlow(node, _, _, ap, config) and
sinkNode(node, config) and
toReturn = false and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and
returnAp = apNone() and
ap instanceof ApNil
or
@@ -2728,7 +2773,7 @@ private module Stage4 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
if returnNodeMayFlowThrough(node, ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -2763,9 +2808,8 @@ private module Stage4 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2775,9 +2819,8 @@ private module Stage4 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2787,9 +2830,8 @@ private module Stage4 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -3064,7 +3106,11 @@ private newtype TPathNode =
// A PathNode is introduced by a source ...
Stage4::revFlow(node, config) and
sourceNode(node, config) and
cc instanceof CallContextAny and
(
if hasSourceCallCtx(config)
then cc instanceof CallContextSomeCall
else cc instanceof CallContextAny
) and
sc instanceof SummaryCtxNone and
ap = TAccessPathNil(node.getDataFlowType())
or
@@ -3076,17 +3122,10 @@ private newtype TPathNode =
)
} or
TPathNodeSink(NodeEx node, Configuration config) {
sinkNode(node, pragma[only_bind_into](config)) and
Stage4::revFlow(node, pragma[only_bind_into](config)) and
(
// A sink that is also a source ...
sourceNode(node, config)
or
// ... or a sink that can be reached from a source
exists(PathNodeMid mid |
pathStep(mid, node, _, _, TAccessPathNil(_)) and
pragma[only_bind_into](config) = mid.getConfiguration()
)
exists(PathNodeMid sink |
sink.isAtSink() and
node = sink.getNodeEx() and
config = sink.getConfiguration()
)
}
@@ -3403,22 +3442,46 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
// an intermediate step to another intermediate node
result = this.getSuccMid()
or
// a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges
exists(PathNodeMid mid, PathNodeSink sink |
mid = this.getSuccMid() and
mid.getNodeEx() = sink.getNodeEx() and
mid.getAp() instanceof AccessPathNil and
sink.getConfiguration() = unbindConf(mid.getConfiguration()) and
result = sink
)
// a final step to a sink
result = this.getSuccMid().projectToSink()
}
override predicate isSource() {
sourceNode(node, config) and
cc instanceof CallContextAny and
(
if hasSourceCallCtx(config)
then cc instanceof CallContextSomeCall
else cc instanceof CallContextAny
) and
sc instanceof SummaryCtxNone and
ap instanceof AccessPathNil
}
predicate isAtSink() {
sinkNode(node, config) and
ap instanceof AccessPathNil and
if hasSinkCallCtx(config)
then
// For `FeatureHasSinkCallContext` the condition `cc instanceof CallContextNoCall`
// is exactly what we need to check. This also implies
// `sc instanceof SummaryCtxNone`.
// For `FeatureEqualSourceSinkCallContext` the initial call context was
// set to `CallContextSomeCall` and jumps are disallowed, so
// `cc instanceof CallContextNoCall` never holds. On the other hand,
// in this case there's never any need to enter a call except to identify
// a summary, so the condition in `pathIntoCallable` enforces this, which
// means that `sc instanceof SummaryCtxNone` holds if and only if we are
// in the call context of the source.
sc instanceof SummaryCtxNone or
cc instanceof CallContextNoCall
else any()
}
PathNodeSink projectToSink() {
this.isAtSink() and
result.getNodeEx() = node and
result.getConfiguration() = unbindConf(config)
}
}
/**
@@ -3572,7 +3635,7 @@ private predicate pathIntoArg(
)
}
pragma[noinline]
pragma[nomagic]
private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) {
@@ -3613,7 +3676,11 @@ private predicate pathIntoCallable(
sc = TSummaryCtxSome(p, ap)
or
not exists(TSummaryCtxSome(p, ap)) and
sc = TSummaryCtxNone()
sc = TSummaryCtxNone() and
// When the call contexts of source and sink needs to match then there's
// never any reason to enter a callable except to find a summary. See also
// the comment in `PathNodeMid::isAtSink`.
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
|
if recordDataFlowCallSite(call, callable)
@@ -3676,13 +3743,14 @@ private module Subpaths {
*/
pragma[nomagic]
private predicate subpaths01(
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, AccessPath apout
) {
exists(Configuration config |
pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and
pathIntoCallable(arg, par, _, innercc, sc, _, config) and
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config))
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config)) and
not arg.isHidden()
)
}
@@ -3716,8 +3784,17 @@ private module Subpaths {
innercc = ret.getCallContext() and
sc = ret.getSummaryCtx() and
ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and
apout = ret.getAp() and
not ret.isHidden()
apout = ret.getAp()
)
}
private PathNodeImpl localStepToHidden(PathNodeImpl n) {
n.getASuccessorImpl() = result and
result.isHidden() and
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
localFlowBigStep(n1, n2, _, _, _, _) or
store(n1, _, n2, _, _) or
read(n1, _, n2, _)
)
}
@@ -3726,11 +3803,12 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) {
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNodeMid out) {
exists(ParamNodeEx p, NodeEx o, AccessPath apout |
pragma[only_bind_into](arg).getASuccessor() = par and
pragma[only_bind_into](arg).getASuccessor() = out and
subpaths03(arg, p, ret, o, apout) and
subpaths03(arg, p, localStepToHidden*(ret), o, apout) and
not ret.isHidden() and
par.getNodeEx() = p and
out.getNodeEx() = o and
out.getAp() = apout

View File

@@ -10,6 +10,7 @@
private import DataFlowImplCommon
private import DataFlowImplSpecific::Private
import DataFlowImplSpecific::Public
import DataFlowImplCommonPublic
/**
* A configuration of interprocedural data flow analysis. This defines
@@ -94,6 +95,22 @@ abstract class Configuration extends string {
*/
int fieldFlowBranchLimit() { result = 2 }
/**
* Gets a data flow configuration feature to add restrictions to the set of
* valid flow paths.
*
* - `FeatureHasSourceCallContext`:
* Assume that sources have some existing call context to disallow
* conflicting return-flow directly following the source.
* - `FeatureHasSinkCallContext`:
* Assume that sinks have some existing call context to disallow
* conflicting argument-to-parameter flow directly preceding the sink.
* - `FeatureEqualSourceSinkCallContext`:
* Implies both of the above and additionally ensures that the entire flow
* path preserves the call context.
*/
FlowFeature getAFeature() { none() }
/**
* Holds if data may flow from `source` to `sink` for this configuration.
*/
@@ -272,6 +289,7 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
config.isBarrier(n)
@@ -290,11 +308,23 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
}
pragma[nomagic]
private predicate sourceNode(NodeEx node, Configuration config) { config.isSource(node.asNode()) }
private predicate sourceNode(NodeEx node, Configuration config) {
config.isSource(node.asNode()) and
not fullBarrier(node, config)
}
pragma[nomagic]
private predicate sinkNode(NodeEx node, Configuration config) { config.isSink(node.asNode()) }
/** 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 fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
/**
* Holds if data can flow in one local step from `node1` to `node2`.
*/
@@ -303,16 +333,14 @@ private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config
node1.asNode() = n1 and
node2.asNode() = n2 and
simpleLocalFlowStepExt(n1, n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
stepFilter(node1, node2, config)
)
or
exists(Node n |
config.allowImplicitRead(n, _) and
node1.asNode() = n and
node2.isImplicitReadNode(n, false)
node2.isImplicitReadNode(n, false) and
not fullBarrier(node1, config)
)
}
@@ -325,16 +353,14 @@ private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configurat
node2.asNode() = n2 and
config.isAdditionalFlowStep(n1, n2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
stepFilter(node1, node2, config)
)
or
exists(Node n |
config.allowImplicitRead(n, _) and
node1.isImplicitReadNode(n, true) and
node2.asNode() = n
node2.asNode() = n and
not fullBarrier(node2, config)
)
}
@@ -346,10 +372,8 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) {
node1.asNode() = n1 and
node2.asNode() = n2 and
jumpStepCached(n1, n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
stepFilter(node1, node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
}
@@ -362,15 +386,14 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c
node2.asNode() = n2 and
config.isAdditionalFlowStep(n1, n2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
stepFilter(node1, node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
}
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
read(node1.asNode(), c, node2.asNode())
read(node1.asNode(), c, node2.asNode()) and
stepFilter(node1, node2, config)
or
exists(Node n |
node2.isImplicitReadNode(n, true) and
@@ -383,7 +406,8 @@ private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
) {
store(node1.asNode(), tc, node2.asNode(), contentType) and
read(_, tc.getContent(), _, config)
read(_, tc.getContent(), _, config) and
stepFilter(node1, node2, config)
}
pragma[nomagic]
@@ -401,6 +425,20 @@ private predicate viableParamArgEx(DataFlowCall call, ParamNodeEx p, ArgNodeEx a
*/
private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 }
private predicate hasSourceCallCtx(Configuration config) {
exists(FlowFeature feature | feature = config.getAFeature() |
feature instanceof FeatureHasSourceCallContext or
feature instanceof FeatureEqualSourceSinkCallContext
)
}
private predicate hasSinkCallCtx(Configuration config) {
exists(FlowFeature feature | feature = config.getAFeature() |
feature instanceof FeatureHasSinkCallContext or
feature instanceof FeatureEqualSourceSinkCallContext
)
}
private module Stage1 {
class ApApprox = Unit;
@@ -418,63 +456,59 @@ private module Stage1 {
* argument in a call.
*/
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
not fullBarrier(node, config) and
(
sourceNode(node, config) and
sourceNode(node, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config)
)
or
// flow into a callable
exists(NodeEx arg |
fwdFlow(arg, _, config) and
viableParamArgEx(_, node, arg) and
cc = true and
not fullBarrier(node, config)
)
or
// flow out of a callable
exists(DataFlowCall call |
fwdFlowOut(call, node, false, config) and
cc = false
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config) and
not outBarrier(mid, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config) and
not inBarrier(node, config)
)
or
// flow into a callable
exists(NodeEx arg |
fwdFlow(arg, _, config) and
viableParamArgEx(_, node, arg) and
cc = true
)
or
// flow out of a callable
exists(DataFlowCall call |
fwdFlowOut(call, node, false, config) and
cc = false
or
fwdFlowOutFromArg(call, node, config) and
fwdFlowIsEntered(call, cc, config)
)
fwdFlowOutFromArg(call, node, config) and
fwdFlowIsEntered(call, cc, config)
)
}
@@ -514,7 +548,8 @@ private module Stage1 {
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
exists(ReturnPosition pos |
fwdFlowReturnPosition(pos, cc, config) and
viableReturnPosOutEx(call, pos, out)
viableReturnPosOutEx(call, pos, out) and
not fullBarrier(out, config)
)
}
@@ -551,7 +586,7 @@ private module Stage1 {
private predicate revFlow0(NodeEx node, boolean toReturn, Configuration config) {
fwdFlow(node, config) and
sinkNode(node, config) and
toReturn = false
if hasSinkCallCtx(config) then toReturn = true else toReturn = false
or
exists(NodeEx mid |
localFlowStep(node, mid, config) and
@@ -740,6 +775,7 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary.
*/
pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and
@@ -937,6 +973,8 @@ private module Stage2 {
Cc ccNone() { result instanceof CallContextAny }
CcCall ccSomeCall() { result instanceof CallContextSomeCall }
private class LocalCc = Unit;
bindingset[call, c, outercc]
@@ -984,12 +1022,14 @@ private module Stage2 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
}
/**
@@ -1004,7 +1044,7 @@ private module Stage2 {
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
cc = ccNone() and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and
ap = getApNil(node)
or
@@ -1107,9 +1147,8 @@ private module Stage2 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1124,9 +1163,8 @@ private module Stage2 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1136,10 +1174,8 @@ private module Stage2 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1195,6 +1231,11 @@ private module Stage2 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -1215,7 +1256,7 @@ private module Stage2 {
) {
fwdFlow(node, _, _, ap, config) and
sinkNode(node, config) and
toReturn = false and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and
returnAp = apNone() and
ap instanceof ApNil
or
@@ -1271,7 +1312,7 @@ private module Stage2 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
if returnNodeMayFlowThrough(node, ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -1306,9 +1347,8 @@ private module Stage2 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1318,9 +1358,8 @@ private module Stage2 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1330,9 +1369,8 @@ private module Stage2 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1616,6 +1654,8 @@ private module Stage3 {
Cc ccNone() { result = false }
CcCall ccSomeCall() { result = true }
private class LocalCc = Unit;
bindingset[call, c, outercc]
@@ -1670,12 +1710,14 @@ private module Stage3 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
}
/**
@@ -1697,7 +1739,7 @@ private module Stage3 {
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
cc = ccNone() and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and
ap = getApNil(node)
or
@@ -1800,9 +1842,8 @@ private module Stage3 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1817,9 +1858,8 @@ private module Stage3 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1829,10 +1869,8 @@ private module Stage3 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1888,6 +1926,11 @@ private module Stage3 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -1908,7 +1951,7 @@ private module Stage3 {
) {
fwdFlow(node, _, _, ap, config) and
sinkNode(node, config) and
toReturn = false and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and
returnAp = apNone() and
ap instanceof ApNil
or
@@ -1964,7 +2007,7 @@ private module Stage3 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
if returnNodeMayFlowThrough(node, ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -1999,9 +2042,8 @@ private module Stage3 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2011,9 +2053,8 @@ private module Stage3 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2023,9 +2064,8 @@ private module Stage3 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2366,6 +2406,8 @@ private module Stage4 {
Cc ccNone() { result instanceof CallContextAny }
CcCall ccSomeCall() { result instanceof CallContextSomeCall }
private class LocalCc = LocalCallContext;
bindingset[call, c, outercc]
@@ -2434,12 +2476,14 @@ private module Stage4 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
}
/**
@@ -2461,7 +2505,7 @@ private module Stage4 {
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
cc = ccNone() and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and
ap = getApNil(node)
or
@@ -2564,9 +2608,8 @@ private module Stage4 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2581,9 +2624,8 @@ private module Stage4 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2593,10 +2635,8 @@ private module Stage4 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2652,6 +2692,11 @@ private module Stage4 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -2672,7 +2717,7 @@ private module Stage4 {
) {
fwdFlow(node, _, _, ap, config) and
sinkNode(node, config) and
toReturn = false and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and
returnAp = apNone() and
ap instanceof ApNil
or
@@ -2728,7 +2773,7 @@ private module Stage4 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
if returnNodeMayFlowThrough(node, ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -2763,9 +2808,8 @@ private module Stage4 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2775,9 +2819,8 @@ private module Stage4 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2787,9 +2830,8 @@ private module Stage4 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -3064,7 +3106,11 @@ private newtype TPathNode =
// A PathNode is introduced by a source ...
Stage4::revFlow(node, config) and
sourceNode(node, config) and
cc instanceof CallContextAny and
(
if hasSourceCallCtx(config)
then cc instanceof CallContextSomeCall
else cc instanceof CallContextAny
) and
sc instanceof SummaryCtxNone and
ap = TAccessPathNil(node.getDataFlowType())
or
@@ -3076,17 +3122,10 @@ private newtype TPathNode =
)
} or
TPathNodeSink(NodeEx node, Configuration config) {
sinkNode(node, pragma[only_bind_into](config)) and
Stage4::revFlow(node, pragma[only_bind_into](config)) and
(
// A sink that is also a source ...
sourceNode(node, config)
or
// ... or a sink that can be reached from a source
exists(PathNodeMid mid |
pathStep(mid, node, _, _, TAccessPathNil(_)) and
pragma[only_bind_into](config) = mid.getConfiguration()
)
exists(PathNodeMid sink |
sink.isAtSink() and
node = sink.getNodeEx() and
config = sink.getConfiguration()
)
}
@@ -3403,22 +3442,46 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
// an intermediate step to another intermediate node
result = this.getSuccMid()
or
// a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges
exists(PathNodeMid mid, PathNodeSink sink |
mid = this.getSuccMid() and
mid.getNodeEx() = sink.getNodeEx() and
mid.getAp() instanceof AccessPathNil and
sink.getConfiguration() = unbindConf(mid.getConfiguration()) and
result = sink
)
// a final step to a sink
result = this.getSuccMid().projectToSink()
}
override predicate isSource() {
sourceNode(node, config) and
cc instanceof CallContextAny and
(
if hasSourceCallCtx(config)
then cc instanceof CallContextSomeCall
else cc instanceof CallContextAny
) and
sc instanceof SummaryCtxNone and
ap instanceof AccessPathNil
}
predicate isAtSink() {
sinkNode(node, config) and
ap instanceof AccessPathNil and
if hasSinkCallCtx(config)
then
// For `FeatureHasSinkCallContext` the condition `cc instanceof CallContextNoCall`
// is exactly what we need to check. This also implies
// `sc instanceof SummaryCtxNone`.
// For `FeatureEqualSourceSinkCallContext` the initial call context was
// set to `CallContextSomeCall` and jumps are disallowed, so
// `cc instanceof CallContextNoCall` never holds. On the other hand,
// in this case there's never any need to enter a call except to identify
// a summary, so the condition in `pathIntoCallable` enforces this, which
// means that `sc instanceof SummaryCtxNone` holds if and only if we are
// in the call context of the source.
sc instanceof SummaryCtxNone or
cc instanceof CallContextNoCall
else any()
}
PathNodeSink projectToSink() {
this.isAtSink() and
result.getNodeEx() = node and
result.getConfiguration() = unbindConf(config)
}
}
/**
@@ -3572,7 +3635,7 @@ private predicate pathIntoArg(
)
}
pragma[noinline]
pragma[nomagic]
private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) {
@@ -3613,7 +3676,11 @@ private predicate pathIntoCallable(
sc = TSummaryCtxSome(p, ap)
or
not exists(TSummaryCtxSome(p, ap)) and
sc = TSummaryCtxNone()
sc = TSummaryCtxNone() and
// When the call contexts of source and sink needs to match then there's
// never any reason to enter a callable except to find a summary. See also
// the comment in `PathNodeMid::isAtSink`.
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
|
if recordDataFlowCallSite(call, callable)
@@ -3676,13 +3743,14 @@ private module Subpaths {
*/
pragma[nomagic]
private predicate subpaths01(
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, AccessPath apout
) {
exists(Configuration config |
pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and
pathIntoCallable(arg, par, _, innercc, sc, _, config) and
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config))
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config)) and
not arg.isHidden()
)
}
@@ -3716,8 +3784,17 @@ private module Subpaths {
innercc = ret.getCallContext() and
sc = ret.getSummaryCtx() and
ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and
apout = ret.getAp() and
not ret.isHidden()
apout = ret.getAp()
)
}
private PathNodeImpl localStepToHidden(PathNodeImpl n) {
n.getASuccessorImpl() = result and
result.isHidden() and
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
localFlowBigStep(n1, n2, _, _, _, _) or
store(n1, _, n2, _, _) or
read(n1, _, n2, _)
)
}
@@ -3726,11 +3803,12 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) {
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNodeMid out) {
exists(ParamNodeEx p, NodeEx o, AccessPath apout |
pragma[only_bind_into](arg).getASuccessor() = par and
pragma[only_bind_into](arg).getASuccessor() = out and
subpaths03(arg, p, ret, o, apout) and
subpaths03(arg, p, localStepToHidden*(ret), o, apout) and
not ret.isHidden() and
par.getNodeEx() = p and
out.getNodeEx() = o and
out.getAp() = apout

View File

@@ -10,6 +10,7 @@
private import DataFlowImplCommon
private import DataFlowImplSpecific::Private
import DataFlowImplSpecific::Public
import DataFlowImplCommonPublic
/**
* A configuration of interprocedural data flow analysis. This defines
@@ -94,6 +95,22 @@ abstract class Configuration extends string {
*/
int fieldFlowBranchLimit() { result = 2 }
/**
* Gets a data flow configuration feature to add restrictions to the set of
* valid flow paths.
*
* - `FeatureHasSourceCallContext`:
* Assume that sources have some existing call context to disallow
* conflicting return-flow directly following the source.
* - `FeatureHasSinkCallContext`:
* Assume that sinks have some existing call context to disallow
* conflicting argument-to-parameter flow directly preceding the sink.
* - `FeatureEqualSourceSinkCallContext`:
* Implies both of the above and additionally ensures that the entire flow
* path preserves the call context.
*/
FlowFeature getAFeature() { none() }
/**
* Holds if data may flow from `source` to `sink` for this configuration.
*/
@@ -272,6 +289,7 @@ private predicate outBarrier(NodeEx node, Configuration config) {
)
}
pragma[nomagic]
private predicate fullBarrier(NodeEx node, Configuration config) {
exists(Node n | node.asNode() = n |
config.isBarrier(n)
@@ -290,11 +308,23 @@ private predicate fullBarrier(NodeEx node, Configuration config) {
}
pragma[nomagic]
private predicate sourceNode(NodeEx node, Configuration config) { config.isSource(node.asNode()) }
private predicate sourceNode(NodeEx node, Configuration config) {
config.isSource(node.asNode()) and
not fullBarrier(node, config)
}
pragma[nomagic]
private predicate sinkNode(NodeEx node, Configuration config) { config.isSink(node.asNode()) }
/** 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 fullBarrier(node1, config) and
not fullBarrier(node2, config)
}
/**
* Holds if data can flow in one local step from `node1` to `node2`.
*/
@@ -303,16 +333,14 @@ private predicate localFlowStep(NodeEx node1, NodeEx node2, Configuration config
node1.asNode() = n1 and
node2.asNode() = n2 and
simpleLocalFlowStepExt(n1, n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
stepFilter(node1, node2, config)
)
or
exists(Node n |
config.allowImplicitRead(n, _) and
node1.asNode() = n and
node2.isImplicitReadNode(n, false)
node2.isImplicitReadNode(n, false) and
not fullBarrier(node1, config)
)
}
@@ -325,16 +353,14 @@ private predicate additionalLocalFlowStep(NodeEx node1, NodeEx node2, Configurat
node2.asNode() = n2 and
config.isAdditionalFlowStep(n1, n2) and
getNodeEnclosingCallable(n1) = getNodeEnclosingCallable(n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
stepFilter(node1, node2, config)
)
or
exists(Node n |
config.allowImplicitRead(n, _) and
node1.isImplicitReadNode(n, true) and
node2.asNode() = n
node2.asNode() = n and
not fullBarrier(node2, config)
)
}
@@ -346,10 +372,8 @@ private predicate jumpStep(NodeEx node1, NodeEx node2, Configuration config) {
node1.asNode() = n1 and
node2.asNode() = n2 and
jumpStepCached(n1, n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
stepFilter(node1, node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
}
@@ -362,15 +386,14 @@ private predicate additionalJumpStep(NodeEx node1, NodeEx node2, Configuration c
node2.asNode() = n2 and
config.isAdditionalFlowStep(n1, n2) and
getNodeEnclosingCallable(n1) != getNodeEnclosingCallable(n2) and
not outBarrier(node1, config) and
not inBarrier(node2, config) and
not fullBarrier(node1, config) and
not fullBarrier(node2, config)
stepFilter(node1, node2, config) and
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
}
private predicate read(NodeEx node1, Content c, NodeEx node2, Configuration config) {
read(node1.asNode(), c, node2.asNode())
read(node1.asNode(), c, node2.asNode()) and
stepFilter(node1, node2, config)
or
exists(Node n |
node2.isImplicitReadNode(n, true) and
@@ -383,7 +406,8 @@ private predicate store(
NodeEx node1, TypedContent tc, NodeEx node2, DataFlowType contentType, Configuration config
) {
store(node1.asNode(), tc, node2.asNode(), contentType) and
read(_, tc.getContent(), _, config)
read(_, tc.getContent(), _, config) and
stepFilter(node1, node2, config)
}
pragma[nomagic]
@@ -401,6 +425,20 @@ private predicate viableParamArgEx(DataFlowCall call, ParamNodeEx p, ArgNodeEx a
*/
private predicate useFieldFlow(Configuration config) { config.fieldFlowBranchLimit() >= 1 }
private predicate hasSourceCallCtx(Configuration config) {
exists(FlowFeature feature | feature = config.getAFeature() |
feature instanceof FeatureHasSourceCallContext or
feature instanceof FeatureEqualSourceSinkCallContext
)
}
private predicate hasSinkCallCtx(Configuration config) {
exists(FlowFeature feature | feature = config.getAFeature() |
feature instanceof FeatureHasSinkCallContext or
feature instanceof FeatureEqualSourceSinkCallContext
)
}
private module Stage1 {
class ApApprox = Unit;
@@ -418,63 +456,59 @@ private module Stage1 {
* argument in a call.
*/
predicate fwdFlow(NodeEx node, Cc cc, Configuration config) {
not fullBarrier(node, config) and
(
sourceNode(node, config) and
sourceNode(node, config) and
if hasSourceCallCtx(config) then cc = true else cc = false
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config)
)
or
// flow into a callable
exists(NodeEx arg |
fwdFlow(arg, _, config) and
viableParamArgEx(_, node, arg) and
cc = true and
not fullBarrier(node, config)
)
or
// flow out of a callable
exists(DataFlowCall call |
fwdFlowOut(call, node, false, config) and
cc = false
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
localFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, cc, config) and
additionalLocalFlowStep(mid, node, config)
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
jumpStep(mid, node, config) and
cc = false
)
or
exists(NodeEx mid |
fwdFlow(mid, _, config) and
additionalJumpStep(mid, node, config) and
cc = false
)
or
// store
exists(NodeEx mid |
useFieldFlow(config) and
fwdFlow(mid, cc, config) and
store(mid, _, node, _, config) and
not outBarrier(mid, config)
)
or
// read
exists(Content c |
fwdFlowRead(c, node, cc, config) and
fwdFlowConsCand(c, config) and
not inBarrier(node, config)
)
or
// flow into a callable
exists(NodeEx arg |
fwdFlow(arg, _, config) and
viableParamArgEx(_, node, arg) and
cc = true
)
or
// flow out of a callable
exists(DataFlowCall call |
fwdFlowOut(call, node, false, config) and
cc = false
or
fwdFlowOutFromArg(call, node, config) and
fwdFlowIsEntered(call, cc, config)
)
fwdFlowOutFromArg(call, node, config) and
fwdFlowIsEntered(call, cc, config)
)
}
@@ -514,7 +548,8 @@ private module Stage1 {
private predicate fwdFlowOut(DataFlowCall call, NodeEx out, Cc cc, Configuration config) {
exists(ReturnPosition pos |
fwdFlowReturnPosition(pos, cc, config) and
viableReturnPosOutEx(call, pos, out)
viableReturnPosOutEx(call, pos, out) and
not fullBarrier(out, config)
)
}
@@ -551,7 +586,7 @@ private module Stage1 {
private predicate revFlow0(NodeEx node, boolean toReturn, Configuration config) {
fwdFlow(node, config) and
sinkNode(node, config) and
toReturn = false
if hasSinkCallCtx(config) then toReturn = true else toReturn = false
or
exists(NodeEx mid |
localFlowStep(node, mid, config) and
@@ -740,6 +775,7 @@ private module Stage1 {
* Holds if flow may enter through `p` and reach a return node making `p` a
* candidate for the origin of a summary.
*/
pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, DataFlowCallable c, Ap ap, Configuration config) {
exists(ReturnKindExt kind |
throughFlowNodeCand(p, config) and
@@ -937,6 +973,8 @@ private module Stage2 {
Cc ccNone() { result instanceof CallContextAny }
CcCall ccSomeCall() { result instanceof CallContextSomeCall }
private class LocalCc = Unit;
bindingset[call, c, outercc]
@@ -984,12 +1022,14 @@ private module Stage2 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
}
/**
@@ -1004,7 +1044,7 @@ private module Stage2 {
predicate fwdFlow(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
cc = ccNone() and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and
ap = getApNil(node)
or
@@ -1107,9 +1147,8 @@ private module Stage2 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1124,9 +1163,8 @@ private module Stage2 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1136,10 +1174,8 @@ private module Stage2 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1195,6 +1231,11 @@ private module Stage2 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -1215,7 +1256,7 @@ private module Stage2 {
) {
fwdFlow(node, _, _, ap, config) and
sinkNode(node, config) and
toReturn = false and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and
returnAp = apNone() and
ap instanceof ApNil
or
@@ -1271,7 +1312,7 @@ private module Stage2 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
if returnNodeMayFlowThrough(node, ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -1306,9 +1347,8 @@ private module Stage2 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1318,9 +1358,8 @@ private module Stage2 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1330,9 +1369,8 @@ private module Stage2 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1616,6 +1654,8 @@ private module Stage3 {
Cc ccNone() { result = false }
CcCall ccSomeCall() { result = true }
private class LocalCc = Unit;
bindingset[call, c, outercc]
@@ -1670,12 +1710,14 @@ private module Stage3 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
}
/**
@@ -1697,7 +1739,7 @@ private module Stage3 {
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
cc = ccNone() and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and
ap = getApNil(node)
or
@@ -1800,9 +1842,8 @@ private module Stage3 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1817,9 +1858,8 @@ private module Stage3 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1829,10 +1869,8 @@ private module Stage3 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -1888,6 +1926,11 @@ private module Stage3 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -1908,7 +1951,7 @@ private module Stage3 {
) {
fwdFlow(node, _, _, ap, config) and
sinkNode(node, config) and
toReturn = false and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and
returnAp = apNone() and
ap instanceof ApNil
or
@@ -1964,7 +2007,7 @@ private module Stage3 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
if returnNodeMayFlowThrough(node, ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -1999,9 +2042,8 @@ private module Stage3 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2011,9 +2053,8 @@ private module Stage3 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2023,9 +2064,8 @@ private module Stage3 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2366,6 +2406,8 @@ private module Stage4 {
Cc ccNone() { result instanceof CallContextAny }
CcCall ccSomeCall() { result instanceof CallContextSomeCall }
private class LocalCc = LocalCallContext;
bindingset[call, c, outercc]
@@ -2434,12 +2476,14 @@ private module Stage4 {
pragma[nomagic]
private predicate flowThroughOutOfCall(
DataFlowCall call, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow, Configuration config
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
Configuration config
) {
flowOutOfCall(call, ret, out, allowsFieldFlow, pragma[only_bind_into](config)) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(_, ret.getEnclosingCallable(), _,
pragma[only_bind_into](config))
pragma[only_bind_into](config)) and
ccc.matchesCall(call)
}
/**
@@ -2461,7 +2505,7 @@ private module Stage4 {
private predicate fwdFlow0(NodeEx node, Cc cc, ApOption argAp, Ap ap, Configuration config) {
flowCand(node, _, config) and
sourceNode(node, config) and
cc = ccNone() and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and
ap = getApNil(node)
or
@@ -2564,9 +2608,8 @@ private module Stage4 {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, outercc, argAp, ap, config) and
flowIntoCall(call, arg, p, allowsFieldFlow, config) and
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc)
|
ap instanceof ApNil or allowsFieldFlow = true
innercc = getCallContextCall(call, p.getEnclosingCallable(), outercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2581,9 +2624,8 @@ private module Stage4 {
fwdFlow(ret, innercc, argAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
inner = ret.getEnclosingCallable() and
ccOut = getCallContextReturn(inner, call, innercc)
|
ap instanceof ApNil or allowsFieldFlow = true
ccOut = getCallContextReturn(inner, call, innercc) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2593,10 +2635,8 @@ private module Stage4 {
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc |
fwdFlow(ret, ccc, apSome(argAp), ap, config) and
flowThroughOutOfCall(call, ret, out, allowsFieldFlow, config) and
ccc.matchesCall(call)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2652,6 +2692,11 @@ private module Stage4 {
callMayFlowThroughFwd(call, pragma[only_bind_into](config))
}
pragma[nomagic]
private predicate returnNodeMayFlowThrough(RetNodeEx ret, Ap ap, Configuration config) {
fwdFlow(ret, any(CcCall ccc), apSome(_), ap, config)
}
/**
* Holds if `node` with access path `ap` is part of a path from a source to a
* sink in the configuration `config`.
@@ -2672,7 +2717,7 @@ private module Stage4 {
) {
fwdFlow(node, _, _, ap, config) and
sinkNode(node, config) and
toReturn = false and
(if hasSinkCallCtx(config) then toReturn = true else toReturn = false) and
returnAp = apNone() and
ap instanceof ApNil
or
@@ -2728,7 +2773,7 @@ private module Stage4 {
// flow out of a callable
revFlowOut(_, node, _, _, ap, config) and
toReturn = true and
if fwdFlow(node, any(CcCall ccc), apSome(_), ap, config)
if returnNodeMayFlowThrough(node, ap, config)
then returnAp = apSome(ap)
else returnAp = apNone()
}
@@ -2763,9 +2808,8 @@ private module Stage4 {
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, toReturn, returnAp, ap, config) and
flowOutOfCall(call, ret, out, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowOutOfCall(call, ret, out, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2775,9 +2819,8 @@ private module Stage4 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, false, returnAp, ap, config) and
flowIntoCall(_, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowIntoCall(_, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -2787,9 +2830,8 @@ private module Stage4 {
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlow(p, true, apSome(returnAp), ap, config) and
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config)
|
ap instanceof ApNil or allowsFieldFlow = true
flowThroughIntoCall(call, arg, p, allowsFieldFlow, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
@@ -3064,7 +3106,11 @@ private newtype TPathNode =
// A PathNode is introduced by a source ...
Stage4::revFlow(node, config) and
sourceNode(node, config) and
cc instanceof CallContextAny and
(
if hasSourceCallCtx(config)
then cc instanceof CallContextSomeCall
else cc instanceof CallContextAny
) and
sc instanceof SummaryCtxNone and
ap = TAccessPathNil(node.getDataFlowType())
or
@@ -3076,17 +3122,10 @@ private newtype TPathNode =
)
} or
TPathNodeSink(NodeEx node, Configuration config) {
sinkNode(node, pragma[only_bind_into](config)) and
Stage4::revFlow(node, pragma[only_bind_into](config)) and
(
// A sink that is also a source ...
sourceNode(node, config)
or
// ... or a sink that can be reached from a source
exists(PathNodeMid mid |
pathStep(mid, node, _, _, TAccessPathNil(_)) and
pragma[only_bind_into](config) = mid.getConfiguration()
)
exists(PathNodeMid sink |
sink.isAtSink() and
node = sink.getNodeEx() and
config = sink.getConfiguration()
)
}
@@ -3403,22 +3442,46 @@ private class PathNodeMid extends PathNodeImpl, TPathNodeMid {
// an intermediate step to another intermediate node
result = this.getSuccMid()
or
// a final step to a sink via zero steps means we merge the last two steps to prevent trivial-looking edges
exists(PathNodeMid mid, PathNodeSink sink |
mid = this.getSuccMid() and
mid.getNodeEx() = sink.getNodeEx() and
mid.getAp() instanceof AccessPathNil and
sink.getConfiguration() = unbindConf(mid.getConfiguration()) and
result = sink
)
// a final step to a sink
result = this.getSuccMid().projectToSink()
}
override predicate isSource() {
sourceNode(node, config) and
cc instanceof CallContextAny and
(
if hasSourceCallCtx(config)
then cc instanceof CallContextSomeCall
else cc instanceof CallContextAny
) and
sc instanceof SummaryCtxNone and
ap instanceof AccessPathNil
}
predicate isAtSink() {
sinkNode(node, config) and
ap instanceof AccessPathNil and
if hasSinkCallCtx(config)
then
// For `FeatureHasSinkCallContext` the condition `cc instanceof CallContextNoCall`
// is exactly what we need to check. This also implies
// `sc instanceof SummaryCtxNone`.
// For `FeatureEqualSourceSinkCallContext` the initial call context was
// set to `CallContextSomeCall` and jumps are disallowed, so
// `cc instanceof CallContextNoCall` never holds. On the other hand,
// in this case there's never any need to enter a call except to identify
// a summary, so the condition in `pathIntoCallable` enforces this, which
// means that `sc instanceof SummaryCtxNone` holds if and only if we are
// in the call context of the source.
sc instanceof SummaryCtxNone or
cc instanceof CallContextNoCall
else any()
}
PathNodeSink projectToSink() {
this.isAtSink() and
result.getNodeEx() = node and
result.getConfiguration() = unbindConf(config)
}
}
/**
@@ -3572,7 +3635,7 @@ private predicate pathIntoArg(
)
}
pragma[noinline]
pragma[nomagic]
private predicate parameterCand(
DataFlowCallable callable, int i, AccessPathApprox apa, Configuration config
) {
@@ -3613,7 +3676,11 @@ private predicate pathIntoCallable(
sc = TSummaryCtxSome(p, ap)
or
not exists(TSummaryCtxSome(p, ap)) and
sc = TSummaryCtxNone()
sc = TSummaryCtxNone() and
// When the call contexts of source and sink needs to match then there's
// never any reason to enter a callable except to find a summary. See also
// the comment in `PathNodeMid::isAtSink`.
not config.getAFeature() instanceof FeatureEqualSourceSinkCallContext
)
|
if recordDataFlowCallSite(call, callable)
@@ -3676,13 +3743,14 @@ private module Subpaths {
*/
pragma[nomagic]
private predicate subpaths01(
PathNode arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
PathNodeImpl arg, ParamNodeEx par, SummaryCtxSome sc, CallContext innercc, ReturnKindExt kind,
NodeEx out, AccessPath apout
) {
exists(Configuration config |
pathThroughCallable(arg, out, _, pragma[only_bind_into](apout)) and
pathIntoCallable(arg, par, _, innercc, sc, _, config) and
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config))
paramFlowsThrough(kind, innercc, sc, pragma[only_bind_into](apout), _, unbindConf(config)) and
not arg.isHidden()
)
}
@@ -3716,8 +3784,17 @@ private module Subpaths {
innercc = ret.getCallContext() and
sc = ret.getSummaryCtx() and
ret.getConfiguration() = unbindConf(getPathNodeConf(arg)) and
apout = ret.getAp() and
not ret.isHidden()
apout = ret.getAp()
)
}
private PathNodeImpl localStepToHidden(PathNodeImpl n) {
n.getASuccessorImpl() = result and
result.isHidden() and
exists(NodeEx n1, NodeEx n2 | n1 = n.getNodeEx() and n2 = result.getNodeEx() |
localFlowBigStep(n1, n2, _, _, _, _) or
store(n1, _, n2, _, _) or
read(n1, _, n2, _)
)
}
@@ -3726,11 +3803,12 @@ private module Subpaths {
* a subpath between `par` and `ret` with the connecting edges `arg -> par` and
* `ret -> out` is summarized as the edge `arg -> out`.
*/
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeMid ret, PathNodeMid out) {
predicate subpaths(PathNode arg, PathNodeImpl par, PathNodeImpl ret, PathNodeMid out) {
exists(ParamNodeEx p, NodeEx o, AccessPath apout |
pragma[only_bind_into](arg).getASuccessor() = par and
pragma[only_bind_into](arg).getASuccessor() = out and
subpaths03(arg, p, ret, o, apout) and
subpaths03(arg, p, localStepToHidden*(ret), o, apout) and
not ret.isHidden() and
par.getNodeEx() = p and
out.getNodeEx() = o and
out.getAp() = apout

View File

@@ -2,6 +2,42 @@ private import DataFlowImplSpecific::Private
private import DataFlowImplSpecific::Public
import Cached
module DataFlowImplCommonPublic {
private newtype TFlowFeature =
TFeatureHasSourceCallContext() or
TFeatureHasSinkCallContext() or
TFeatureEqualSourceSinkCallContext()
/** A flow configuration feature for use in `Configuration::getAFeature()`. */
class FlowFeature extends TFlowFeature {
string toString() { none() }
}
/**
* A flow configuration feature that implies that sources have some existing
* call context.
*/
class FeatureHasSourceCallContext extends FlowFeature, TFeatureHasSourceCallContext {
override string toString() { result = "FeatureHasSourceCallContext" }
}
/**
* A flow configuration feature that implies that sinks have some existing
* call context.
*/
class FeatureHasSinkCallContext extends FlowFeature, TFeatureHasSinkCallContext {
override string toString() { result = "FeatureHasSinkCallContext" }
}
/**
* A flow configuration feature that implies that source-sink pairs have some
* shared existing call context.
*/
class FeatureEqualSourceSinkCallContext extends FlowFeature, TFeatureEqualSourceSinkCallContext {
override string toString() { result = "FeatureEqualSourceSinkCallContext" }
}
}
/**
* The cost limits for the `AccessPathFront` to `AccessPathApprox` expansion.
*

View File

@@ -9,6 +9,19 @@ private import tainttracking1.TaintTrackingParameter::Private
private import tainttracking1.TaintTrackingParameter::Public
module Consistency {
private newtype TConsistencyConfiguration = MkConsistencyConfiguration()
/** A class for configuring the consistency queries. */
class ConsistencyConfiguration extends TConsistencyConfiguration {
string toString() { none() }
/** Holds if `n` should be excluded from the consistency test `postWithInFlow`. */
predicate postWithInFlowExclude(Node n) { none() }
/** Holds if `n` should be excluded from the consistency test `argHasPostUpdate`. */
predicate argHasPostUpdateExclude(ArgumentNode n) { none() }
}
private class RelevantNode extends Node {
RelevantNode() {
this instanceof ArgumentNode or
@@ -164,7 +177,7 @@ module Consistency {
query predicate argHasPostUpdate(ArgumentNode n, string msg) {
not hasPost(n) and
not isImmutableOrUnobservable(n) and
not any(ConsistencyConfiguration c).argHasPostUpdateExclude(n) and
msg = "ArgumentNode is missing PostUpdateNode."
}
@@ -177,6 +190,7 @@ module Consistency {
isPostUpdateNode(n) and
not clearsContent(n, _) and
simpleLocalFlowStep(_, n) and
not any(ConsistencyConfiguration c).postWithInFlowExclude(n) and
msg = "PostUpdateNode should not be the target of local flow."
}
}

View File

@@ -2,6 +2,7 @@ private import cpp
private import DataFlowUtil
private import semmle.code.cpp.ir.IR
private import DataFlowDispatch
private import DataFlowImplConsistency
/** Gets the callable in which this node occurs. */
DataFlowCallable nodeGetEnclosingCallable(Node n) { result = n.getEnclosingCallable() }
@@ -112,11 +113,9 @@ class ReturnNode extends InstructionNode {
Instruction primary;
ReturnNode() {
exists(ReturnValueInstruction ret | instr = ret.getReturnValue() and primary = ret)
exists(ReturnValueInstruction ret | instr = ret and primary = ret)
or
exists(ReturnIndirectionInstruction rii |
instr = rii.getSideEffectOperand().getAnyDef() and primary = rii
)
exists(ReturnIndirectionInstruction rii | instr = rii and primary = rii)
}
/** Gets the kind of this returned value. */
@@ -190,108 +189,16 @@ OutNode getAnOutNode(DataFlowCall call, ReturnKind kind) {
*/
predicate jumpStep(Node n1, Node n2) { none() }
private predicate fieldStoreStepNoChi(Node node1, FieldContent f, PostUpdateNode node2) {
exists(StoreInstruction store, Class c |
store = node2.asInstruction() and
store.getSourceValueOperand() = node1.asOperand() and
getWrittenField(store, f.getAField(), c) and
f.hasOffset(c, _, _)
)
}
private FieldAddressInstruction getFieldInstruction(Instruction instr) {
result = instr or
result = instr.(CopyValueInstruction).getUnary()
}
pragma[noinline]
private predicate getWrittenField(Instruction instr, Field f, Class c) {
exists(FieldAddressInstruction fa |
fa =
getFieldInstruction([
instr.(StoreInstruction).getDestinationAddress(),
instr.(WriteSideEffectInstruction).getDestinationAddress()
]) and
f = fa.getField() and
c = f.getDeclaringType()
)
}
private predicate fieldStoreStepChi(Node node1, FieldContent f, PostUpdateNode node2) {
exists(ChiPartialOperand operand, ChiInstruction chi |
chi.getPartialOperand() = operand and
node1.asOperand() = operand and
node2.asInstruction() = chi and
exists(Class c |
c = chi.getResultType() and
exists(int startBit, int endBit |
chi.getUpdatedInterval(startBit, endBit) and
f.hasOffset(c, startBit, endBit)
)
or
getWrittenField(operand.getDef(), f.getAField(), c) and
f.hasOffset(c, _, _)
)
)
}
private predicate arrayStoreStepChi(Node node1, ArrayContent a, PostUpdateNode node2) {
exists(a) and
exists(ChiPartialOperand operand, ChiInstruction chi, StoreInstruction store |
chi.getPartialOperand() = operand and
store = operand.getDef() and
node1.asOperand() = operand and
// This `ChiInstruction` will always have a non-conflated result because both `ArrayStoreNode`
// and `PointerStoreNode` require it in their characteristic predicates.
node2.asInstruction() = chi and
(
// `x[i] = taint()`
// This matches the characteristic predicate in `ArrayStoreNode`.
store.getDestinationAddress() instanceof PointerAddInstruction
or
// `*p = taint()`
// This matches the characteristic predicate in `PointerStoreNode`.
store.getDestinationAddress().(CopyValueInstruction).getUnary() instanceof LoadInstruction
)
)
}
/**
* Holds if data can flow from `node1` to `node2` via an assignment to `f`.
* Thus, `node2` references an object with a field `f` that contains the
* value of `node1`.
*/
predicate storeStep(Node node1, Content f, PostUpdateNode node2) {
fieldStoreStepNoChi(node1, f, node2) or
fieldStoreStepChi(node1, f, node2) or
arrayStoreStepChi(node1, f, node2) or
fieldStoreStepAfterArraySuppression(node1, f, node2)
}
// This predicate pushes the correct `FieldContent` onto the access path when the
// `suppressArrayRead` predicate has popped off an `ArrayContent`.
private predicate fieldStoreStepAfterArraySuppression(
Node node1, FieldContent f, PostUpdateNode node2
) {
exists(WriteSideEffectInstruction write, ChiInstruction chi, Class c |
not chi.isResultConflated() and
node1.asInstruction() = chi and
node2.asInstruction() = chi and
chi.getPartial() = write and
getWrittenField(write, f.getAField(), c) and
f.hasOffset(c, _, _)
)
}
bindingset[result, i]
private int unbindInt(int i) { i <= result and i >= result }
pragma[noinline]
private predicate getLoadedField(LoadInstruction load, Field f, Class c) {
exists(FieldAddressInstruction fa |
fa = load.getSourceAddress() and
f = fa.getField() and
c = f.getDeclaringType()
predicate storeStep(StoreNodeInstr node1, FieldContent f, StoreNodeInstr node2) {
exists(FieldAddressInstruction fai |
node1.getInstruction() = fai and
node2.getInstruction() = fai.getObjectAddress() and
f.getField() = fai.getField()
)
}
@@ -300,122 +207,14 @@ private predicate getLoadedField(LoadInstruction load, Field f, Class c) {
* Thus, `node1` references an object with a field `f` whose value ends up in
* `node2`.
*/
private predicate fieldReadStep(Node node1, FieldContent f, Node node2) {
exists(LoadOperand operand |
node2.asOperand() = operand and
node1.asInstruction() = operand.getAnyDef() and
exists(Class c |
c = operand.getAnyDef().getResultType() and
exists(int startBit, int endBit |
operand.getUsedInterval(unbindInt(startBit), unbindInt(endBit)) and
f.hasOffset(c, startBit, endBit)
)
or
getLoadedField(operand.getUse(), f.getAField(), c) and
f.hasOffset(c, _, _)
)
predicate readStep(ReadNode node1, FieldContent f, ReadNode node2) {
exists(FieldAddressInstruction fai |
node1.getInstruction() = fai.getObjectAddress() and
node2.getInstruction() = fai and
f.getField() = fai.getField()
)
}
/**
* When a store step happens in a function that looks like an array write such as:
* ```cpp
* void f(int* pa) {
* pa = source();
* }
* ```
* it can be a write to an array, but it can also happen that `f` is called as `f(&a.x)`. If that is
* the case, the `ArrayContent` that was written by the call to `f` should be popped off the access
* path, and a `FieldContent` containing `x` should be pushed instead.
* So this case pops `ArrayContent` off the access path, and the `fieldStoreStepAfterArraySuppression`
* predicate in `storeStep` ensures that we push the right `FieldContent` onto the access path.
*/
predicate suppressArrayRead(Node node1, ArrayContent a, Node node2) {
exists(a) and
exists(WriteSideEffectInstruction write, ChiInstruction chi |
node1.asInstruction() = write and
node2.asInstruction() = chi and
chi.getPartial() = write and
getWrittenField(write, _, _)
)
}
private class ArrayToPointerConvertInstruction extends ConvertInstruction {
ArrayToPointerConvertInstruction() {
this.getUnary().getResultType() instanceof ArrayType and
this.getResultType() instanceof PointerType
}
}
private Instruction skipOneCopyValueInstructionRec(CopyValueInstruction copy) {
copy.getUnary() = result and not result instanceof CopyValueInstruction
or
result = skipOneCopyValueInstructionRec(copy.getUnary())
}
private Instruction skipCopyValueInstructions(Operand op) {
not result instanceof CopyValueInstruction and result = op.getDef()
or
result = skipOneCopyValueInstructionRec(op.getDef())
}
private predicate arrayReadStep(Node node1, ArrayContent a, Node node2) {
exists(a) and
// Explicit dereferences such as `*p` or `p[i]` where `p` is a pointer or array.
exists(LoadOperand operand, Instruction address |
operand.isDefinitionInexact() and
node1.asInstruction() = operand.getAnyDef() and
operand = node2.asOperand() and
address = skipCopyValueInstructions(operand.getAddressOperand()) and
(
address instanceof LoadInstruction or
address instanceof ArrayToPointerConvertInstruction or
address instanceof PointerOffsetInstruction
)
)
}
/**
* In cases such as:
* ```cpp
* void f(int* pa) {
* *pa = source();
* }
* ...
* int x;
* f(&x);
* use(x);
* ```
* the load on `x` in `use(x)` will exactly overlap with its definition (in this case the definition
* is a `WriteSideEffect`). This predicate pops the `ArrayContent` (pushed by the store in `f`)
* from the access path.
*/
private predicate exactReadStep(Node node1, ArrayContent a, Node node2) {
exists(a) and
exists(WriteSideEffectInstruction write, ChiInstruction chi |
not chi.isResultConflated() and
chi.getPartial() = write and
node1.asInstruction() = write and
node2.asInstruction() = chi and
// To distinquish this case from the `arrayReadStep` case we require that the entire variable was
// overwritten by the `WriteSideEffectInstruction` (i.e., there is a load that reads the
// entire variable).
exists(LoadInstruction load | load.getSourceValue() = chi)
)
}
/**
* Holds if data can flow from `node1` to `node2` via a read of `f`.
* Thus, `node1` references an object with a field `f` whose value ends up in
* `node2`.
*/
predicate readStep(Node node1, Content f, Node node2) {
fieldReadStep(node1, f, node2) or
arrayReadStep(node1, f, node2) or
exactReadStep(node1, f, node2) or
suppressArrayRead(node1, f, node2)
}
/**
* Holds if values stored inside content `c` are cleared at node `n`.
*/
@@ -447,7 +246,7 @@ private predicate suppressUnusedNode(Node n) { any() }
// Java QL library compatibility wrappers
//////////////////////////////////////////////////////////////////////////////
/** A node that performs a type cast. */
class CastNode extends InstructionNode {
class CastNode extends Node {
CastNode() { none() } // stub implementation
}
@@ -487,21 +286,18 @@ class Unit extends TUnit {
string toString() { result = "unit" }
}
/**
* Holds if `n` does not require a `PostUpdateNode` as it either cannot be
* modified or its modification cannot be observed, for example if it is a
* freshly created object that is not saved in a variable.
*
* This predicate is only used for consistency checks.
*/
predicate isImmutableOrUnobservable(Node n) {
// The rules for whether an IR argument gets a post-update node are too
// complex to model here.
any()
}
/** Holds if `n` should be hidden from path explanations. */
predicate nodeIsHidden(Node n) { n instanceof OperandNode and not n instanceof ArgumentNode }
predicate nodeIsHidden(Node n) {
n instanceof OperandNode and not n instanceof ArgumentNode
or
StoreNodeFlow::flowThrough(n, _) and
not StoreNodeFlow::flowOutOf(n, _) and
not StoreNodeFlow::flowInto(_, n)
or
ReadNodeFlow::flowThrough(n, _) and
not ReadNodeFlow::flowOutOf(n, _) and
not ReadNodeFlow::flowInto(_, n)
}
class LambdaCallKind = Unit;
@@ -522,3 +318,11 @@ predicate additionalLambdaFlowStep(Node nodeFrom, Node nodeTo, boolean preserves
* by default as a heuristic.
*/
predicate allowParameterReturnInSelf(ParameterNode p) { none() }
private class MyConsistencyConfiguration extends Consistency::ConsistencyConfiguration {
override predicate argHasPostUpdateExclude(ArgumentNode n) {
// The rules for whether an IR argument gets a post-update node are too
// complex to model here.
any()
}
}

View File

@@ -10,19 +10,78 @@ private import semmle.code.cpp.ir.ValueNumbering
private import semmle.code.cpp.ir.IR
private import semmle.code.cpp.controlflow.IRGuards
private import semmle.code.cpp.models.interfaces.DataFlow
private import DataFlowPrivate
private import SsaInternals as Ssa
cached
private module Cached {
/**
* The IR dataflow graph consists of the following nodes:
* - `InstructionNode`, which represents an `Instruction` in the graph.
* - `OperandNode`, which represents an `Operand` in the graph.
* - `VariableNode`, which is used to model global variables.
* - Two kinds of `StoreNode`s:
* 1. `StoreNodeInstr`, which represents the value of an address computed by an `Instruction` that
* has been updated by a write operation.
* 2. `StoreNodeOperand`, which represents the value of an address in an `ArgumentOperand` after a
* function call that may have changed the value.
* - `ReadNode`, which represents the result of reading a field of an object.
* - `SsaPhiNode`, which represents phi nodes as computed by the shared SSA library.
*
* The following section describes how flow is generally transferred between these nodes:
* - Flow between `InstructionNode`s and `OperandNode`s follow the def-use information as computed by
* the IR. Because the IR compute must-alias information for memory operands, we only follow def-use
* flow for register operands.
* - Flow can enter a `StoreNode` in two ways (both done in `StoreNode.flowInto`):
* 1. Flow is transferred from a `StoreValueOperand` to a `StoreNodeInstr`. Flow will then proceed
* along the chain of addresses computed by `StoreNodeInstr.getInner` to identify field writes
* and call `storeStep` accordingly (i.e., for an expression like `a.b.c = x`, we visit `c`, then
* `b`, then `a`).
* 2. Flow is transfered from a `WriteSideEffectInstruction` to a `StoreNodeOperand` after flow
* returns to a caller. Flow will then proceed to the defining instruction of the operand (because
* the `StoreNodeInstr` computed by `StoreNodeOperand.getInner()` is the `StoreNode` containing
* the defining instruction), and then along the chain computed by `StoreNodeInstr.getInner` like
* above.
* In both cases, flow leaves a `StoreNode` once the entire chain has been traversed, and the shared
* SSA library is used to find the next use of the variable at the end of the chain.
* - Flow can enter a `ReadNode` through an `OperandNode` that represents an address of some variable.
* Flow will then proceed along the chain of addresses computed by `ReadNode.getOuter` (i.e., for an
* expression like `use(a.b.c)` we visit `a`, then `b`, then `c`) and call `readStep` accordingly.
* Once the entire chain has been traversed, flow is transferred to the load instruction that reads
* the final address of the chain.
* - Flow can enter a `SsaPhiNode` from an `InstructionNode`, a `StoreNode` or another `SsaPhiNode`
* (in `toPhiNode`), depending on which node provided the previous definition of the underlying
* variable. Flow leaves a `SsaPhiNode` (in `fromPhiNode`) by using the shared SSA library to
* determine the next use of the variable.
*/
cached
newtype TIRDataFlowNode =
TInstructionNode(Instruction i) or
TOperandNode(Operand op) or
TVariableNode(Variable var)
TVariableNode(Variable var) or
TStoreNodeInstr(Instruction i) { Ssa::explicitWrite(_, _, i) } or
TStoreNodeOperand(ArgumentOperand op) { Ssa::explicitWrite(_, _, op.getDef()) } or
TReadNode(Instruction i) { needsPostReadNode(i) } or
TSsaPhiNode(Ssa::PhiNode phi)
cached
predicate localFlowStepCached(Node nodeFrom, Node nodeTo) {
simpleLocalFlowStep(nodeFrom, nodeTo)
}
private predicate needsPostReadNode(Instruction iFrom) {
// If the instruction generates an address that flows to a load.
Ssa::addressFlowTC(iFrom, Ssa::getSourceAddress(_)) and
(
// And it is either a field address
iFrom instanceof FieldAddressInstruction
or
// Or it is instruction that either uses or is used for an address that needs a post read node.
exists(Instruction mid | needsPostReadNode(mid) |
Ssa::addressFlow(mid, iFrom) or Ssa::addressFlow(iFrom, mid)
)
)
}
}
private import Cached
@@ -180,6 +239,234 @@ class OperandNode extends Node, TOperandNode {
override string toString() { result = this.getOperand().toString() }
}
/**
* INTERNAL: do not use.
*
* A `StoreNode` is a node that has been (or is about to be) the
* source or target of a `storeStep`.
*/
abstract private class StoreNode extends Node {
/** Holds if this node should receive flow from `addr`. */
abstract predicate flowInto(Instruction addr);
override Declaration getEnclosingCallable() { result = this.getFunction() }
/** Holds if this `StoreNode` is the root of the address computation used by a store operation. */
predicate isTerminal() {
not exists(this.getInner()) and
not storeStep(this, _, _)
}
/** Gets the store operation that uses the address computed by this `StoreNode`. */
abstract Instruction getStoreInstruction();
/** Holds if the store operation associated with this `StoreNode` overwrites the entire variable. */
final predicate isCertain() { Ssa::explicitWrite(true, this.getStoreInstruction(), _) }
/**
* Gets the `StoreNode` that computes the address used by this `StoreNode`.
*/
abstract StoreNode getInner();
/** The inverse of `StoreNode.getInner`. */
final StoreNode getOuter() { result.getInner() = this }
}
class StoreNodeInstr extends StoreNode, TStoreNodeInstr {
Instruction instr;
StoreNodeInstr() { this = TStoreNodeInstr(instr) }
override predicate flowInto(Instruction addr) { this.getInstruction() = addr }
/** Gets the underlying instruction. */
Instruction getInstruction() { result = instr }
override Function getFunction() { result = this.getInstruction().getEnclosingFunction() }
override IRType getType() { result = this.getInstruction().getResultIRType() }
override Location getLocation() { result = this.getInstruction().getLocation() }
override string toString() {
result = instructionNode(this.getInstruction()).toString() + " [store]"
}
override Instruction getStoreInstruction() {
Ssa::explicitWrite(_, result, this.getInstruction())
}
override StoreNodeInstr getInner() {
Ssa::addressFlow(result.getInstruction(), this.getInstruction())
}
}
/**
* To avoid having `PostUpdateNode`s with multiple pre-update nodes (which can cause performance
* problems) we attach the `PostUpdateNode` that represent output arguments to an operand instead of
* an instruction.
*
* To see why we need this, consider the expression `b->set(new C())`. The IR of this expression looks
* like (simplified):
* ```
* r1(glval<unknown>) = FunctionAddress[set] :
* r2(glval<unknown>) = FunctionAddress[operator new] :
* r3(unsigned long) = Constant[8] :
* r4(void *) = Call[operator new] : func:r2, 0:r3
* r5(C *) = Convert : r4
* r6(glval<unknown>) = FunctionAddress[C] :
* v1(void) = Call[C] : func:r6, this:r5
* v2(void) = Call[set] : func:r1, this:r0, 0:r5
* ```
*
* Notice that both the call to `C` and the call to `set` will have an argument that is the
* result of calling `operator new` (i.e., `r4`). If we only have `PostUpdateNode`s that are
* instructions, both `PostUpdateNode`s would have `r4` as their pre-update node.
*
* We avoid this issue by having a `PostUpdateNode` for each argument, and let the pre-update node of
* each `PostUpdateNode` be the argument _operand_, instead of the defining instruction.
*/
class StoreNodeOperand extends StoreNode, TStoreNodeOperand {
ArgumentOperand operand;
StoreNodeOperand() { this = TStoreNodeOperand(operand) }
override predicate flowInto(Instruction addr) { this.getOperand().getDef() = addr }
/** Gets the underlying operand. */
Operand getOperand() { result = operand }
override Function getFunction() { result = operand.getDef().getEnclosingFunction() }
override IRType getType() { result = operand.getIRType() }
override Location getLocation() { result = operand.getLocation() }
override string toString() { result = operandNode(this.getOperand()).toString() + " [store]" }
override WriteSideEffectInstruction getStoreInstruction() {
Ssa::explicitWrite(_, result, operand.getDef())
}
/**
* The result of `StoreNodeOperand.getInner` is the `StoreNodeInstr` representation the instruction
* that defines this operand. This means the graph of `getInner` looks like this:
* ```
* I---I---I
* \ \ \
* O O O
* ```
* where each `StoreNodeOperand` "hooks" into the chain computed by `StoreNodeInstr.getInner`.
* This means that the chain of `getInner` calls on the argument `&o.f` on an expression
* like `func(&o.f)` is:
* ```
* r4---r3---r2
* \
* 0:r4
* ```
* where the IR for `func(&o.f)` looks like (simplified):
* ```
* r1(glval<unknown>) = FunctionAddress[func] :
* r2(glval<O>) = VariableAddress[o] :
* r3(glval<int>) = FieldAddress[f] : r2
* r4(int *) = CopyValue : r3
* v1(void) = Call[func] : func:r1, 0:r4
* ```
*/
override StoreNodeInstr getInner() { operand.getDef() = result.getInstruction() }
}
/**
* INTERNAL: do not use.
*
* A `ReadNode` is a node that has been (or is about to be) the
* source or target of a `readStep`.
*/
class ReadNode extends Node, TReadNode {
Instruction i;
ReadNode() { this = TReadNode(i) }
/** Gets the underlying instruction. */
Instruction getInstruction() { result = i }
override Declaration getEnclosingCallable() { result = this.getFunction() }
override Function getFunction() { result = this.getInstruction().getEnclosingFunction() }
override IRType getType() { result = this.getInstruction().getResultIRType() }
override Location getLocation() { result = this.getInstruction().getLocation() }
override string toString() {
result = instructionNode(this.getInstruction()).toString() + " [read]"
}
/** Gets a load instruction that uses the address computed by this read node. */
final Instruction getALoadInstruction() {
Ssa::addressFlowTC(this.getInstruction(), Ssa::getSourceAddress(result))
}
/**
* Gets a read node with an underlying instruction that is used by this
* underlying instruction to compute an address of a load instruction.
*/
final ReadNode getInner() { Ssa::addressFlow(result.getInstruction(), this.getInstruction()) }
/** The inverse of `ReadNode.getInner`. */
final ReadNode getOuter() { result.getInner() = this }
/** Holds if this read node computes a value that will not be used for any future read nodes. */
final predicate isTerminal() {
not exists(this.getOuter()) and
not readStep(this, _, _)
}
/** Holds if this read node computes a value that has not yet been used for any read operations. */
final predicate isInitial() {
not exists(this.getInner()) and
not readStep(_, _, this)
}
}
/**
* INTERNAL: do not use.
*
* A phi node produced by the shared SSA library, viewed as a node in a data flow graph.
*/
class SsaPhiNode extends Node, TSsaPhiNode {
Ssa::PhiNode phi;
SsaPhiNode() { this = TSsaPhiNode(phi) }
/* Get the phi node associated with this node. */
Ssa::PhiNode getPhiNode() { result = phi }
override Declaration getEnclosingCallable() { result = this.getFunction() }
override Function getFunction() { result = phi.getBasicBlock().getEnclosingFunction() }
override IRType getType() { result instanceof IRVoidType }
override Location getLocation() { result = phi.getBasicBlock().getLocation() }
/** Holds if this phi node has input from the `rnk`'th write operation in block `block`. */
final predicate hasInputAtRankInBlock(IRBlock block, int rnk) {
hasInputAtRankInBlock(block, rnk, _)
}
/**
* Holds if this phi node has input from the definition `input` (which is the `rnk`'th write
* operation in block `block`).
*/
cached
final predicate hasInputAtRankInBlock(IRBlock block, int rnk, Ssa::Definition input) {
Ssa::phiHasInputFromBlock(phi, input, _) and input.definesAt(_, block, rnk)
}
override string toString() { result = "Phi" }
}
/**
* An expression, viewed as a node in a data flow graph.
*/
@@ -313,15 +600,14 @@ deprecated class UninitializedNode extends Node {
* Nodes corresponding to AST elements, for example `ExprNode`, usually refer
* to the value before the update with the exception of `ClassInstanceExpr`,
* which represents the value after the constructor has run.
*
* This class exists to match the interface used by Java. There are currently no non-abstract
* classes that extend it. When we implement field flow, we can revisit this.
*/
abstract class PostUpdateNode extends InstructionNode {
abstract class PostUpdateNode extends Node {
/**
* Gets the node before the state update.
*/
abstract Node getPreUpdateNode();
override string toString() { result = this.getPreUpdateNode() + " [post update]" }
}
/**
@@ -332,7 +618,7 @@ abstract class PostUpdateNode extends InstructionNode {
* value, but does not necessarily replace it entirely. For example:
* ```
* x.y = 1; // a partial definition of the object `x`.
* x.y.z = 1; // a partial definition of the object `x.y`.
* x.y.z = 1; // a partial definition of the object `x.y` and `x`.
* x.setY(1); // a partial definition of the object `x`.
* setY(&x); // a partial definition of the object `x`.
* ```
@@ -341,135 +627,34 @@ abstract private class PartialDefinitionNode extends PostUpdateNode {
abstract Expr getDefinedExpr();
}
private class ExplicitFieldStoreQualifierNode extends PartialDefinitionNode {
override ChiInstruction instr;
StoreInstruction store;
ExplicitFieldStoreQualifierNode() {
not instr.isResultConflated() and
instr.getPartial() = store and
(
instr.getUpdatedInterval(_, _) or
store.getDestinationAddress() instanceof FieldAddressInstruction
)
private class FieldPartialDefinitionNode extends PartialDefinitionNode, StoreNodeInstr {
FieldPartialDefinitionNode() {
this.getInstruction() = any(FieldAddressInstruction fai).getObjectAddress()
}
// By using an operand as the result of this predicate we avoid the dataflow inconsistency errors
// caused by having multiple nodes sharing the same pre update node. This inconsistency error can cause
// a tuple explosion in the big step dataflow relation since it can make many nodes be the entry node
// into a big step.
override Node getPreUpdateNode() { result.asOperand() = instr.getTotalOperand() }
override Node getPreUpdateNode() { result.asInstruction() = this.getInstruction() }
override Expr getDefinedExpr() { result = this.getInstruction().getUnconvertedResultExpression() }
override string toString() { result = PartialDefinitionNode.super.toString() }
}
private class NonPartialDefinitionPostUpdate extends PostUpdateNode, StoreNodeInstr {
NonPartialDefinitionPostUpdate() { not this instanceof PartialDefinitionNode }
override Node getPreUpdateNode() { result.asInstruction() = this.getInstruction() }
override string toString() { result = PostUpdateNode.super.toString() }
}
private class ArgumentPostUpdateNode extends PartialDefinitionNode, StoreNodeOperand {
override ArgumentNode getPreUpdateNode() { result.asOperand() = operand }
override Expr getDefinedExpr() {
result =
store
.getDestinationAddress()
.(FieldAddressInstruction)
.getObjectAddress()
.getUnconvertedResultExpression()
}
}
/**
* Not every store instruction generates a chi instruction that we can attach a PostUpdateNode to.
* For instance, an update to a field of a struct containing only one field. Even if the store does
* have a chi instruction, a subsequent use of the result of the store may be linked directly to the
* result of the store as an inexact definition if the store totally overlaps the use. For these
* cases we attach the PostUpdateNode to the store instruction. There's no obvious pre update node
* for this case (as the entire memory is updated), so `getPreUpdateNode` is implemented as
* `none()`.
*/
private class ExplicitSingleFieldStoreQualifierNode extends PartialDefinitionNode {
override StoreInstruction instr;
ExplicitSingleFieldStoreQualifierNode() {
(
instr.getAUse().isDefinitionInexact()
or
not exists(ChiInstruction chi | chi.getPartial() = instr)
) and
// Without this condition any store would create a `PostUpdateNode`.
instr.getDestinationAddress() instanceof FieldAddressInstruction
result = this.getOperand().getDef().getUnconvertedResultExpression()
}
override Node getPreUpdateNode() { none() }
override Expr getDefinedExpr() {
result =
instr
.getDestinationAddress()
.(FieldAddressInstruction)
.getObjectAddress()
.getUnconvertedResultExpression()
}
}
private FieldAddressInstruction getFieldInstruction(Instruction instr) {
result = instr or
result = instr.(CopyValueInstruction).getUnary()
}
/**
* The target of a `fieldStoreStepAfterArraySuppression` store step, which is used to convert
* an `ArrayContent` to a `FieldContent` when the `WriteSideEffect` instruction stores
* into a field. See the QLDoc for `suppressArrayRead` for an example of where such a conversion
* is inserted.
*/
private class WriteSideEffectFieldStoreQualifierNode extends PartialDefinitionNode {
override ChiInstruction instr;
WriteSideEffectInstruction write;
FieldAddressInstruction field;
WriteSideEffectFieldStoreQualifierNode() {
not instr.isResultConflated() and
instr.getPartial() = write and
field = getFieldInstruction(write.getDestinationAddress())
}
override Node getPreUpdateNode() { result.asOperand() = instr.getTotalOperand() }
override Expr getDefinedExpr() {
result = field.getObjectAddress().getUnconvertedResultExpression()
}
}
/**
* The `PostUpdateNode` that is the target of a `arrayStoreStepChi` store step. The overriden
* `ChiInstruction` corresponds to the instruction represented by `node2` in `arrayStoreStepChi`.
*/
private class ArrayStoreNode extends PartialDefinitionNode {
override ChiInstruction instr;
PointerAddInstruction add;
ArrayStoreNode() {
not instr.isResultConflated() and
exists(StoreInstruction store |
instr.getPartial() = store and
add = store.getDestinationAddress()
)
}
override Node getPreUpdateNode() { result.asOperand() = instr.getTotalOperand() }
override Expr getDefinedExpr() { result = add.getLeft().getUnconvertedResultExpression() }
}
/**
* The `PostUpdateNode` that is the target of a `arrayStoreStepChi` store step. The overriden
* `ChiInstruction` corresponds to the instruction represented by `node2` in `arrayStoreStepChi`.
*/
private class PointerStoreNode extends PostUpdateNode {
override ChiInstruction instr;
PointerStoreNode() {
not instr.isResultConflated() and
exists(StoreInstruction store |
instr.getPartial() = store and
store.getDestinationAddress().(CopyValueInstruction).getUnary() instanceof LoadInstruction
)
}
override Node getPreUpdateNode() { result.asOperand() = instr.getTotalOperand() }
override string toString() { result = PartialDefinitionNode.super.toString() }
}
/**
@@ -548,6 +733,11 @@ class VariableNode extends Node, TVariableNode {
*/
InstructionNode instructionNode(Instruction instr) { result.getInstruction() = instr }
/**
* Gets the node corresponding to `operand`.
*/
OperandNode operandNode(Operand operand) { result.getOperand() = operand }
/**
* DEPRECATED: use `definitionByReferenceNodeFromArgument` instead.
*
@@ -614,61 +804,176 @@ predicate simpleLocalFlowStep(Node nodeFrom, Node nodeTo) {
or
// Instruction -> Operand flow
simpleOperandLocalFlowStep(nodeFrom.asInstruction(), nodeTo.asOperand())
or
// Flow into, through, and out of store nodes
StoreNodeFlow::flowInto(nodeFrom.asInstruction(), nodeTo)
or
StoreNodeFlow::flowThrough(nodeFrom, nodeTo)
or
StoreNodeFlow::flowOutOf(nodeFrom, nodeTo)
or
// Flow into, through, and out of read nodes
ReadNodeFlow::flowInto(nodeFrom, nodeTo)
or
ReadNodeFlow::flowThrough(nodeFrom, nodeTo)
or
ReadNodeFlow::flowOutOf(nodeFrom, nodeTo)
or
// Adjacent-def-use and adjacent-use-use flow
adjacentDefUseFlow(nodeFrom, nodeTo)
}
pragma[noinline]
private predicate getFieldSizeOfClass(Class c, Type type, int size) {
exists(Field f |
f.getDeclaringType() = c and
f.getUnderlyingType() = type and
type.getSize() = size
private predicate adjacentDefUseFlow(Node nodeFrom, Node nodeTo) {
// Flow that isn't already covered by field flow out of store/read nodes.
not nodeFrom.asInstruction() = any(StoreNode pun).getStoreInstruction() and
not nodeFrom.asInstruction() = any(ReadNode pun).getALoadInstruction() and
(
//Def-use flow
Ssa::ssaFlow(nodeFrom, nodeTo)
or
// Use-use flow through stores.
exists(Instruction loadAddress, Node store |
loadAddress = Ssa::getSourceAddressFromNode(nodeFrom) and
Ssa::explicitWrite(_, store.asInstruction(), loadAddress) and
Ssa::ssaFlow(store, nodeTo)
)
)
}
private predicate isSingleFieldClass(Type type, Operand op) {
exists(int size, Class c |
c = op.getType().getUnderlyingType() and
c.getSize() = size and
getFieldSizeOfClass(c, type, size)
)
/**
* INTERNAL: Do not use.
*/
module ReadNodeFlow {
/** Holds if the read node `nodeTo` should receive flow from `nodeFrom`. */
predicate flowInto(Node nodeFrom, ReadNode nodeTo) {
nodeTo.isInitial() and
(
// If we entered through an address operand.
nodeFrom.asOperand().getDef() = nodeTo.getInstruction()
or
// If we entered flow through a memory-producing instruction.
// This can happen if we have flow to an `InitializeParameterIndirection` through
// a `ReadSideEffectInstruction`.
exists(Instruction load, Instruction def |
def = nodeFrom.asInstruction() and
def = Ssa::getSourceValueOperand(load).getAnyDef() and
not def = any(StoreNode store).getStoreInstruction() and
pragma[only_bind_into](nodeTo).getALoadInstruction() = load
)
)
}
/**
* Holds if the read node `nodeTo` should receive flow from the read node `nodeFrom`.
*
* This happens when `readFrom` is _not_ the source of a `readStep`, and `nodeTo` is
* the `ReadNode` that represents an address that directly depends on `nodeFrom`.
*/
predicate flowThrough(ReadNode nodeFrom, ReadNode nodeTo) {
not readStep(nodeFrom, _, _) and
nodeFrom.getOuter() = nodeTo
}
/**
* Holds if flow should leave the read node `nFrom` and enter the node `nodeTo`.
* This happens either because there is use-use flow from one of the variables used in
* the read operation, or because we have traversed all the field dereferences in the
* read operation.
*/
predicate flowOutOf(ReadNode nFrom, Node nodeTo) {
// Use-use flow to another use of the same variable instruction
Ssa::ssaFlow(nFrom, nodeTo)
or
not exists(nFrom.getInner()) and
exists(Node store |
Ssa::explicitWrite(_, store.asInstruction(), nFrom.getInstruction()) and
Ssa::ssaFlow(store, nodeTo)
)
or
// Flow out of read nodes and into memory instructions if we cannot move any further through
// read nodes.
nFrom.isTerminal() and
(
exists(Instruction load |
load = nodeTo.asInstruction() and
Ssa::getSourceAddress(load) = nFrom.getInstruction()
)
or
exists(CallInstruction call, int i |
call.getArgument(i) = nodeTo.asInstruction() and
call.getArgument(i) = nFrom.getInstruction()
)
)
}
}
/**
* INTERNAL: Do not use.
*/
module StoreNodeFlow {
/** Holds if the store node `nodeTo` should receive flow from `nodeFrom`. */
predicate flowInto(Instruction instrFrom, StoreNode nodeTo) {
nodeTo.flowInto(Ssa::getDestinationAddress(instrFrom))
}
/**
* Holds if the store node `nodeTo` should receive flow from `nodeFom`.
*
* This happens when `nodeFrom` is _not_ the source of a `storeStep`, and `nodeFrom` is
* the `Storenode` that represents an address that directly depends on `nodeTo`.
*/
predicate flowThrough(StoreNode nodeFrom, StoreNode nodeTo) {
// Flow through a post update node that doesn't need a store step.
not storeStep(nodeFrom, _, _) and
nodeTo.getOuter() = nodeFrom
}
/**
* Holds if flow should leave the store node `nodeFrom` and enter the node `nodeTo`.
* This happens because we have traversed an entire chain of field dereferences
* after a store operation.
*/
predicate flowOutOf(StoreNodeInstr nFrom, Node nodeTo) {
nFrom.isTerminal() and
Ssa::ssaFlow(nFrom, nodeTo)
}
}
private predicate simpleOperandLocalFlowStep(Instruction iFrom, Operand opTo) {
// Propagate flow from an instruction to its exact uses.
// We do this for all instruction/operand pairs, except when the operand is the
// side effect operand of a ReturnIndirectionInstruction, or the load operand of a LoadInstruction.
// This is because we get these flows through the shared SSA library already, and including this
// flow here will create multiple dataflow paths which creates a blowup in stage 3 of dataflow.
(
not any(ReturnIndirectionInstruction ret).getSideEffectOperand() = opTo and
not any(LoadInstruction load).getSourceValueOperand() = opTo and
not any(ReturnValueInstruction ret).getReturnValueOperand() = opTo
) and
opTo.getDef() = iFrom
or
opTo = any(ReadSideEffectInstruction read).getSideEffectOperand() and
not iFrom.isResultConflated() and
iFrom = opTo.getAnyDef()
or
// Loading a single `int` from an `int *` parameter is not an exact load since
// the parameter may point to an entire array rather than a single `int`. The
// following rule ensures that any flow going into the
// `InitializeIndirectionInstruction`, even if it's for a different array
// element, will propagate to a load of the first element.
//
// Since we're linking `InitializeIndirectionInstruction` and
// `LoadInstruction` together directly, this rule will break if there's any
// reassignment of the parameter indirection, including a conditional one that
// leads to a phi node.
exists(InitializeIndirectionInstruction init |
iFrom = init and
opTo.(LoadOperand).getAnyDef() = init and
// Check that the types match. Otherwise we can get flow from an object to
// its fields, which leads to field conflation when there's flow from other
// fields to the object elsewhere.
init.getParameter().getType().getUnspecifiedType().(DerivedType).getBaseType() =
opTo.getType().getUnspecifiedType()
)
or
// Flow from stores to structs with a single field to a load of that field.
exists(LoadInstruction load |
load.getSourceValueOperand() = opTo and
opTo.getAnyDef() = iFrom and
isSingleFieldClass(pragma[only_bind_out](pragma[only_bind_out](iFrom).getResultType()), opTo)
}
pragma[noinline]
private predicate getAddressType(LoadInstruction load, Type t) {
exists(Instruction address |
address = load.getSourceAddress() and
t = address.getResultType()
)
}
/**
* Like the AST dataflow library, we want to conflate the address and value of a reference. This class
* represents the `LoadInstruction` that is generated from a reference dereference.
*/
private class ReferenceDereferenceInstruction extends LoadInstruction {
ReferenceDereferenceInstruction() {
exists(ReferenceType ref |
getAddressType(this, ref) and
this.getResultType() = ref.getBaseType()
)
}
}
private predicate simpleInstructionLocalFlowStep(Operand opFrom, Instruction iTo) {
iTo.(CopyInstruction).getSourceValueOperand() = opFrom
or
@@ -681,40 +986,8 @@ private predicate simpleInstructionLocalFlowStep(Operand opFrom, Instruction iTo
or
iTo.(InheritanceConversionInstruction).getUnaryOperand() = opFrom
or
// A chi instruction represents a point where a new value (the _partial_
// operand) may overwrite an old value (the _total_ operand), but the alias
// analysis couldn't determine that it surely will overwrite every bit of it or
// that it surely will overwrite no bit of it.
//
// By allowing flow through the total operand, we ensure that flow is not lost
// due to shortcomings of the alias analysis. We may get false flow in cases
// where the data is indeed overwritten.
//
// Flow through the partial operand belongs in the taint-tracking libraries
// for now.
iTo.getAnOperand().(ChiTotalOperand) = opFrom
or
// Add flow from write side-effects to non-conflated chi instructions through their
// partial operands. From there, a `readStep` will find subsequent reads of that field.
// Consider the following example:
// ```
// void setX(Point* p, int new_x) {
// p->x = new_x;
// }
// ...
// setX(&p, taint());
// ```
// Here, a `WriteSideEffectInstruction` will provide a new definition for `p->x` after the call to
// `setX`, which will be melded into `p` through a chi instruction.
exists(ChiInstruction chi | chi = iTo |
opFrom.getAnyDef() instanceof WriteSideEffectInstruction and
chi.getPartialOperand() = opFrom and
not chi.isResultConflated() and
// In a call such as `set_value(&x->val);` we don't want the memory representing `x` to receive
// dataflow by a simple step. Instead, this is handled by field flow. If we add a simple step here
// we can get field-to-object flow.
not chi.isPartialUpdate()
)
// Conflate references and values like in AST dataflow.
iTo.(ReferenceDereferenceInstruction).getSourceAddressOperand() = opFrom
or
// Flow through modeled functions
modelFlow(opFrom, iTo)
@@ -788,25 +1061,14 @@ predicate localInstructionFlow(Instruction e1, Instruction e2) {
*/
predicate localExprFlow(Expr e1, Expr e2) { localFlow(exprNode(e1), exprNode(e2)) }
/**
* Gets a field corresponding to the bit range `[startBit..endBit)` of class `c`, if any.
*/
private Field getAField(Class c, int startBit, int endBit) {
result.getDeclaringType() = c and
startBit = 8 * result.getByteOffset() and
endBit = 8 * result.getType().getSize() + startBit
or
exists(Field f, Class cInner |
f = c.getAField() and
cInner = f.getUnderlyingType() and
result = getAField(cInner, startBit - 8 * f.getByteOffset(), endBit - 8 * f.getByteOffset())
)
}
private newtype TContent =
TFieldContent(Class c, int startBit, int endBit) { exists(getAField(c, startBit, endBit)) } or
TCollectionContent() or
TArrayContent()
TFieldContent(Field f) {
// As reads and writes to union fields can create flow even though the reads and writes
// target different fields, we don't want a read (write) to create a read (write) step.
not f.getDeclaringType() instanceof Union
} or
TCollectionContent() or // Not used in C/C++
TArrayContent() // Not used in C/C++.
/**
* A description of the way data may be stored inside an object. Examples
@@ -824,18 +1086,13 @@ class Content extends TContent {
/** A reference through an instance field. */
class FieldContent extends Content, TFieldContent {
Class c;
int startBit;
int endBit;
Field f;
FieldContent() { this = TFieldContent(c, startBit, endBit) }
FieldContent() { this = TFieldContent(f) }
// Ensure that there's just 1 result for `toString`.
override string toString() { result = min(Field f | f = this.getAField() | f.toString()) }
override string toString() { result = f.toString() }
predicate hasOffset(Class cl, int start, int end) { cl = c and start = startBit and end = endBit }
Field getAField() { result = getAField(c, startBit, endBit) }
Field getField() { result = f }
}
/** A reference through an array. */

View File

@@ -0,0 +1,662 @@
/**
* Provides a language-independent implementation of static single assignment
* (SSA) form.
*/
private import SsaImplSpecific
private BasicBlock getABasicBlockPredecessor(BasicBlock bb) { getABasicBlockSuccessor(result) = bb }
/**
* Liveness analysis (based on source variables) to restrict the size of the
* SSA representation.
*/
private module Liveness {
/**
* A classification of variable references into reads (of a given kind) and
* (certain or uncertain) writes.
*/
private newtype TRefKind =
Read(boolean certain) { certain in [false, true] } or
Write(boolean certain) { certain in [false, true] }
private class RefKind extends TRefKind {
string toString() {
exists(boolean certain | this = Read(certain) and result = "read (" + certain + ")")
or
exists(boolean certain | this = Write(certain) and result = "write (" + certain + ")")
}
int getOrder() {
this = Read(_) and
result = 0
or
this = Write(_) and
result = 1
}
}
/**
* Holds if the `i`th node of basic block `bb` is a reference to `v` of kind `k`.
*/
private predicate ref(BasicBlock bb, int i, SourceVariable v, RefKind k) {
exists(boolean certain | variableRead(bb, i, v, certain) | k = Read(certain))
or
exists(boolean certain | variableWrite(bb, i, v, certain) | k = Write(certain))
}
private newtype OrderedRefIndex =
MkOrderedRefIndex(int i, int tag) {
exists(RefKind rk | ref(_, i, _, rk) | tag = rk.getOrder())
}
private OrderedRefIndex refOrd(BasicBlock bb, int i, SourceVariable v, RefKind k, int ord) {
ref(bb, i, v, k) and
result = MkOrderedRefIndex(i, ord) and
ord = k.getOrder()
}
/**
* Gets the (1-based) rank of the reference to `v` at the `i`th node of
* basic block `bb`, which has the given reference kind `k`.
*
* Reads are considered before writes when they happen at the same index.
*/
private int refRank(BasicBlock bb, int i, SourceVariable v, RefKind k) {
refOrd(bb, i, v, k, _) =
rank[result](int j, int ord, OrderedRefIndex res |
res = refOrd(bb, j, v, _, ord)
|
res order by j, ord
)
}
private int maxRefRank(BasicBlock bb, SourceVariable v) {
result = refRank(bb, _, v, _) and
not result + 1 = refRank(bb, _, v, _)
}
/**
* Gets the (1-based) rank of the first reference to `v` inside basic block `bb`
* that is either a read or a certain write.
*/
private int firstReadOrCertainWrite(BasicBlock bb, SourceVariable v) {
result =
min(int r, RefKind k |
r = refRank(bb, _, v, k) and
k != Write(false)
|
r
)
}
/**
* Holds if source variable `v` is live at the beginning of basic block `bb`.
*/
predicate liveAtEntry(BasicBlock bb, SourceVariable v) {
// The first read or certain write to `v` inside `bb` is a read
refRank(bb, _, v, Read(_)) = firstReadOrCertainWrite(bb, v)
or
// There is no certain write to `v` inside `bb`, but `v` is live at entry
// to a successor basic block of `bb`
not exists(firstReadOrCertainWrite(bb, v)) and
liveAtExit(bb, v)
}
/**
* Holds if source variable `v` is live at the end of basic block `bb`.
*/
predicate liveAtExit(BasicBlock bb, SourceVariable v) {
liveAtEntry(getABasicBlockSuccessor(bb), v)
}
/**
* Holds if variable `v` is live in basic block `bb` at index `i`.
* The rank of `i` is `rnk` as defined by `refRank()`.
*/
private predicate liveAtRank(BasicBlock bb, int i, SourceVariable v, int rnk) {
exists(RefKind kind | rnk = refRank(bb, i, v, kind) |
rnk = maxRefRank(bb, v) and
liveAtExit(bb, v)
or
ref(bb, i, v, kind) and
kind = Read(_)
or
exists(RefKind nextKind |
liveAtRank(bb, _, v, rnk + 1) and
rnk + 1 = refRank(bb, _, v, nextKind) and
nextKind != Write(true)
)
)
}
/**
* Holds if variable `v` is live after the (certain or uncertain) write at
* index `i` inside basic block `bb`.
*/
predicate liveAfterWrite(BasicBlock bb, int i, SourceVariable v) {
exists(int rnk | rnk = refRank(bb, i, v, Write(_)) | liveAtRank(bb, i, v, rnk))
}
}
private import Liveness
/**
* Holds if `df` is in the dominance frontier of `bb`.
*
* This is equivalent to:
*
* ```ql
* bb = getImmediateBasicBlockDominator*(getABasicBlockPredecessor(df)) and
* not bb = getImmediateBasicBlockDominator+(df)
* ```
*/
private predicate inDominanceFrontier(BasicBlock bb, BasicBlock df) {
bb = getABasicBlockPredecessor(df) and not bb = getImmediateBasicBlockDominator(df)
or
exists(BasicBlock prev | inDominanceFrontier(prev, df) |
bb = getImmediateBasicBlockDominator(prev) and
not bb = getImmediateBasicBlockDominator(df)
)
}
/**
* Holds if `bb` is in the dominance frontier of a block containing a
* definition of `v`.
*/
pragma[noinline]
private predicate inDefDominanceFrontier(BasicBlock bb, SourceVariable v) {
exists(BasicBlock defbb, Definition def |
def.definesAt(v, defbb, _) and
inDominanceFrontier(defbb, bb)
)
}
cached
newtype TDefinition =
TWriteDef(SourceVariable v, BasicBlock bb, int i) {
variableWrite(bb, i, v, _) and
liveAfterWrite(bb, i, v)
} or
TPhiNode(SourceVariable v, BasicBlock bb) {
inDefDominanceFrontier(bb, v) and
liveAtEntry(bb, v)
}
private module SsaDefReaches {
newtype TSsaRefKind =
SsaRead() or
SsaDef()
/**
* A classification of SSA variable references into reads and definitions.
*/
class SsaRefKind extends TSsaRefKind {
string toString() {
this = SsaRead() and
result = "SsaRead"
or
this = SsaDef() and
result = "SsaDef"
}
int getOrder() {
this = SsaRead() and
result = 0
or
this = SsaDef() and
result = 1
}
}
/**
* Holds if the `i`th node of basic block `bb` is a reference to `v`,
* either a read (when `k` is `SsaRead()`) or an SSA definition (when `k`
* is `SsaDef()`).
*
* Unlike `Liveness::ref`, this includes `phi` nodes.
*/
predicate ssaRef(BasicBlock bb, int i, SourceVariable v, SsaRefKind k) {
variableRead(bb, i, v, _) and
k = SsaRead()
or
exists(Definition def | def.definesAt(v, bb, i)) and
k = SsaDef()
}
private newtype OrderedSsaRefIndex =
MkOrderedSsaRefIndex(int i, SsaRefKind k) { ssaRef(_, i, _, k) }
private OrderedSsaRefIndex ssaRefOrd(BasicBlock bb, int i, SourceVariable v, SsaRefKind k, int ord) {
ssaRef(bb, i, v, k) and
result = MkOrderedSsaRefIndex(i, k) and
ord = k.getOrder()
}
/**
* Gets the (1-based) rank of the reference to `v` at the `i`th node of basic
* block `bb`, which has the given reference kind `k`.
*
* For example, if `bb` is a basic block with a phi node for `v` (considered
* to be at index -1), reads `v` at node 2, and defines it at node 5, we have:
*
* ```ql
* ssaRefRank(bb, -1, v, SsaDef()) = 1 // phi node
* ssaRefRank(bb, 2, v, Read()) = 2 // read at node 2
* ssaRefRank(bb, 5, v, SsaDef()) = 3 // definition at node 5
* ```
*
* Reads are considered before writes when they happen at the same index.
*/
int ssaRefRank(BasicBlock bb, int i, SourceVariable v, SsaRefKind k) {
ssaRefOrd(bb, i, v, k, _) =
rank[result](int j, int ord, OrderedSsaRefIndex res |
res = ssaRefOrd(bb, j, v, _, ord)
|
res order by j, ord
)
}
int maxSsaRefRank(BasicBlock bb, SourceVariable v) {
result = ssaRefRank(bb, _, v, _) and
not result + 1 = ssaRefRank(bb, _, v, _)
}
/**
* Holds if the SSA definition `def` reaches rank index `rnk` in its own
* basic block `bb`.
*/
predicate ssaDefReachesRank(BasicBlock bb, Definition def, int rnk, SourceVariable v) {
exists(int i |
rnk = ssaRefRank(bb, i, v, SsaDef()) and
def.definesAt(v, bb, i)
)
or
ssaDefReachesRank(bb, def, rnk - 1, v) and
rnk = ssaRefRank(bb, _, v, SsaRead())
}
/**
* Holds if the SSA definition of `v` at `def` reaches index `i` in the same
* basic block `bb`, without crossing another SSA definition of `v`.
*/
predicate ssaDefReachesReadWithinBlock(SourceVariable v, Definition def, BasicBlock bb, int i) {
exists(int rnk |
ssaDefReachesRank(bb, def, rnk, v) and
rnk = ssaRefRank(bb, i, v, SsaRead())
)
}
/**
* Holds if the SSA definition of `v` at `def` reaches uncertain SSA definition
* `redef` in the same basic block, without crossing another SSA definition of `v`.
*/
predicate ssaDefReachesUncertainDefWithinBlock(
SourceVariable v, Definition def, UncertainWriteDefinition redef
) {
exists(BasicBlock bb, int rnk, int i |
ssaDefReachesRank(bb, def, rnk, v) and
rnk = ssaRefRank(bb, i, v, SsaDef()) - 1 and
redef.definesAt(v, bb, i)
)
}
/**
* Same as `ssaRefRank()`, but restricted to a particular SSA definition `def`.
*/
int ssaDefRank(Definition def, SourceVariable v, BasicBlock bb, int i, SsaRefKind k) {
v = def.getSourceVariable() and
result = ssaRefRank(bb, i, v, k) and
(
ssaDefReachesRead(_, def, bb, i)
or
def.definesAt(_, bb, i)
)
}
/**
* Holds if the reference to `def` at index `i` in basic block `bb` is the
* last reference to `v` inside `bb`.
*/
pragma[noinline]
predicate lastSsaRef(Definition def, SourceVariable v, BasicBlock bb, int i) {
ssaDefRank(def, v, bb, i, _) = maxSsaRefRank(bb, v)
}
predicate defOccursInBlock(Definition def, BasicBlock bb, SourceVariable v) {
exists(ssaDefRank(def, v, bb, _, _))
}
pragma[noinline]
private predicate ssaDefReachesThroughBlock(Definition def, BasicBlock bb) {
ssaDefReachesEndOfBlock(bb, def, _) and
not defOccursInBlock(_, bb, def.getSourceVariable())
}
/**
* Holds if `def` is accessed in basic block `bb1` (either a read or a write),
* `bb2` is a transitive successor of `bb1`, `def` is live at the end of `bb1`,
* and the underlying variable for `def` is neither read nor written in any block
* on the path between `bb1` and `bb2`.
*/
predicate varBlockReaches(Definition def, BasicBlock bb1, BasicBlock bb2) {
defOccursInBlock(def, bb1, _) and
bb2 = getABasicBlockSuccessor(bb1)
or
exists(BasicBlock mid |
varBlockReaches(def, bb1, mid) and
ssaDefReachesThroughBlock(def, mid) and
bb2 = getABasicBlockSuccessor(mid)
)
}
/**
* Holds if `def` is accessed in basic block `bb1` (either a read or a write),
* `def` is read at index `i2` in basic block `bb2`, `bb2` is in a transitive
* successor block of `bb1`, and `def` is neither read nor written in any block
* on a path between `bb1` and `bb2`.
*/
predicate defAdjacentRead(Definition def, BasicBlock bb1, BasicBlock bb2, int i2) {
varBlockReaches(def, bb1, bb2) and
ssaRefRank(bb2, i2, def.getSourceVariable(), SsaRead()) = 1
}
}
private import SsaDefReaches
pragma[nomagic]
predicate liveThrough(BasicBlock bb, SourceVariable v) {
liveAtExit(bb, v) and
not ssaRef(bb, _, v, SsaDef())
}
/**
* NB: If this predicate is exposed, it should be cached.
*
* Holds if the SSA definition of `v` at `def` reaches the end of basic
* block `bb`, at which point it is still live, without crossing another
* SSA definition of `v`.
*/
pragma[nomagic]
predicate ssaDefReachesEndOfBlock(BasicBlock bb, Definition def, SourceVariable v) {
exists(int last | last = maxSsaRefRank(bb, v) |
ssaDefReachesRank(bb, def, last, v) and
liveAtExit(bb, v)
)
or
// The construction of SSA form ensures that each read of a variable is
// dominated by its definition. An SSA definition therefore reaches a
// control flow node if it is the _closest_ SSA definition that dominates
// the node. If two definitions dominate a node then one must dominate the
// other, so therefore the definition of _closest_ is given by the dominator
// tree. Thus, reaching definitions can be calculated in terms of dominance.
ssaDefReachesEndOfBlock(getImmediateBasicBlockDominator(bb), def, pragma[only_bind_into](v)) and
liveThrough(bb, pragma[only_bind_into](v))
}
/**
* NB: If this predicate is exposed, it should be cached.
*
* Holds if `inp` is an input to the phi node `phi` along the edge originating in `bb`.
*/
pragma[nomagic]
predicate phiHasInputFromBlock(PhiNode phi, Definition inp, BasicBlock bb) {
exists(SourceVariable v, BasicBlock bbDef |
phi.definesAt(v, bbDef, _) and
getABasicBlockPredecessor(bbDef) = bb and
ssaDefReachesEndOfBlock(bb, inp, v)
)
}
/**
* NB: If this predicate is exposed, it should be cached.
*
* Holds if the SSA definition of `v` at `def` reaches a read at index `i` in
* basic block `bb`, without crossing another SSA definition of `v`. The read
* is of kind `rk`.
*/
pragma[nomagic]
predicate ssaDefReachesRead(SourceVariable v, Definition def, BasicBlock bb, int i) {
ssaDefReachesReadWithinBlock(v, def, bb, i)
or
variableRead(bb, i, v, _) and
ssaDefReachesEndOfBlock(getABasicBlockPredecessor(bb), def, v) and
not ssaDefReachesReadWithinBlock(v, _, bb, i)
}
/**
* NB: If this predicate is exposed, it should be cached.
*
* Holds if `def` is accessed at index `i1` in basic block `bb1` (either a read
* or a write), `def` is read at index `i2` in basic block `bb2`, and there is a
* path between them without any read of `def`.
*/
pragma[nomagic]
predicate adjacentDefRead(Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2) {
exists(int rnk |
rnk = ssaDefRank(def, _, bb1, i1, _) and
rnk + 1 = ssaDefRank(def, _, bb1, i2, SsaRead()) and
variableRead(bb1, i2, _, _) and
bb2 = bb1
)
or
lastSsaRef(def, _, bb1, i1) and
defAdjacentRead(def, bb1, bb2, i2)
}
pragma[noinline]
private predicate adjacentDefRead(
Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2, SourceVariable v
) {
adjacentDefRead(def, bb1, i1, bb2, i2) and
v = def.getSourceVariable()
}
private predicate adjacentDefReachesRead(
Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2
) {
exists(SourceVariable v | adjacentDefRead(def, bb1, i1, bb2, i2, v) |
ssaRef(bb1, i1, v, SsaDef())
or
variableRead(bb1, i1, v, true)
)
or
exists(BasicBlock bb3, int i3 |
adjacentDefReachesRead(def, bb1, i1, bb3, i3) and
variableRead(bb3, i3, _, false) and
adjacentDefRead(def, bb3, i3, bb2, i2)
)
}
/**
* NB: If this predicate is exposed, it should be cached.
*
* Same as `adjacentDefRead`, but ignores uncertain reads.
*/
pragma[nomagic]
predicate adjacentDefNoUncertainReads(Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2) {
adjacentDefReachesRead(def, bb1, i1, bb2, i2) and
variableRead(bb2, i2, _, true)
}
/**
* NB: If this predicate is exposed, it should be cached.
*
* Holds if the node at index `i` in `bb` is a last reference to SSA definition
* `def`. The reference is last because it can reach another write `next`,
* without passing through another read or write.
*/
pragma[nomagic]
predicate lastRefRedef(Definition def, BasicBlock bb, int i, Definition next) {
exists(SourceVariable v |
// Next reference to `v` inside `bb` is a write
exists(int rnk, int j |
rnk = ssaDefRank(def, v, bb, i, _) and
next.definesAt(v, bb, j) and
rnk + 1 = ssaRefRank(bb, j, v, SsaDef())
)
or
// Can reach a write using one or more steps
lastSsaRef(def, v, bb, i) and
exists(BasicBlock bb2 |
varBlockReaches(def, bb, bb2) and
1 = ssaDefRank(next, v, bb2, _, SsaDef())
)
)
}
/**
* NB: If this predicate is exposed, it should be cached.
*
* Holds if `inp` is an immediately preceding definition of uncertain definition
* `def`. Since `def` is uncertain, the value from the preceding definition might
* still be valid.
*/
pragma[nomagic]
predicate uncertainWriteDefinitionInput(UncertainWriteDefinition def, Definition inp) {
lastRefRedef(inp, _, _, def)
}
private predicate adjacentDefReachesUncertainRead(
Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2
) {
adjacentDefReachesRead(def, bb1, i1, bb2, i2) and
variableRead(bb2, i2, _, false)
}
/**
* NB: If this predicate is exposed, it should be cached.
*
* Same as `lastRefRedef`, but ignores uncertain reads.
*/
pragma[nomagic]
predicate lastRefRedefNoUncertainReads(Definition def, BasicBlock bb, int i, Definition next) {
lastRefRedef(def, bb, i, next) and
not variableRead(bb, i, def.getSourceVariable(), false)
or
exists(BasicBlock bb0, int i0 |
lastRefRedef(def, bb0, i0, next) and
adjacentDefReachesUncertainRead(def, bb, i, bb0, i0)
)
}
/**
* NB: If this predicate is exposed, it should be cached.
*
* Holds if the node at index `i` in `bb` is a last reference to SSA
* definition `def`.
*
* That is, the node can reach the end of the enclosing callable, or another
* SSA definition for the underlying source variable, without passing through
* another read.
*/
pragma[nomagic]
predicate lastRef(Definition def, BasicBlock bb, int i) {
lastRefRedef(def, bb, i, _)
or
lastSsaRef(def, _, bb, i) and
(
// Can reach exit directly
bb instanceof ExitBasicBlock
or
// Can reach a block using one or more steps, where `def` is no longer live
exists(BasicBlock bb2 | varBlockReaches(def, bb, bb2) |
not defOccursInBlock(def, bb2, _) and
not ssaDefReachesEndOfBlock(bb2, def, _)
)
)
}
/**
* NB: If this predicate is exposed, it should be cached.
*
* Same as `lastRefRedef`, but ignores uncertain reads.
*/
pragma[nomagic]
predicate lastRefNoUncertainReads(Definition def, BasicBlock bb, int i) {
lastRef(def, bb, i) and
not variableRead(bb, i, def.getSourceVariable(), false)
or
exists(BasicBlock bb0, int i0 |
lastRef(def, bb0, i0) and
adjacentDefReachesUncertainRead(def, bb, i, bb0, i0)
)
}
/** A static single assignment (SSA) definition. */
class Definition extends TDefinition {
/** Gets the source variable underlying this SSA definition. */
SourceVariable getSourceVariable() { this.definesAt(result, _, _) }
/**
* Holds if this SSA definition defines `v` at index `i` in basic block `bb`.
* Phi nodes are considered to be at index `-1`, while normal variable writes
* are at the index of the control flow node they wrap.
*/
final predicate definesAt(SourceVariable v, BasicBlock bb, int i) {
this = TWriteDef(v, bb, i)
or
this = TPhiNode(v, bb) and i = -1
}
/** Gets the basic block to which this SSA definition belongs. */
final BasicBlock getBasicBlock() { this.definesAt(_, result, _) }
/** Gets a textual representation of this SSA definition. */
string toString() { none() }
}
/** An SSA definition that corresponds to a write. */
class WriteDefinition extends Definition, TWriteDef {
private SourceVariable v;
private BasicBlock bb;
private int i;
WriteDefinition() { this = TWriteDef(v, bb, i) }
override string toString() { result = "WriteDef" }
}
/** A phi node. */
class PhiNode extends Definition, TPhiNode {
override string toString() { result = "Phi" }
}
/**
* An SSA definition that represents an uncertain update of the underlying
* source variable.
*/
class UncertainWriteDefinition extends WriteDefinition {
UncertainWriteDefinition() {
exists(SourceVariable v, BasicBlock bb, int i |
this.definesAt(v, bb, i) and
variableWrite(bb, i, v, false)
)
}
}
/** Provides a set of consistency queries. */
module Consistency {
abstract class RelevantDefinition extends Definition {
abstract predicate hasLocationInfo(
string filepath, int startline, int startcolumn, int endline, int endcolumn
);
}
query predicate nonUniqueDef(RelevantDefinition def, SourceVariable v, BasicBlock bb, int i) {
ssaDefReachesRead(v, def, bb, i) and
not exists(unique(Definition def0 | ssaDefReachesRead(v, def0, bb, i)))
}
query predicate readWithoutDef(SourceVariable v, BasicBlock bb, int i) {
variableRead(bb, i, v, _) and
not ssaDefReachesRead(v, _, bb, i)
}
query predicate deadDef(RelevantDefinition def, SourceVariable v) {
v = def.getSourceVariable() and
not ssaDefReachesRead(_, def, _, _) and
not phiHasInputFromBlock(_, def, _) and
not uncertainWriteDefinitionInput(_, def)
}
}

View File

@@ -0,0 +1,18 @@
private import semmle.code.cpp.ir.IR
private import SsaInternals as Ssa
class BasicBlock = IRBlock;
class SourceVariable = Ssa::SourceVariable;
BasicBlock getImmediateBasicBlockDominator(BasicBlock bb) { result.immediatelyDominates(bb) }
BasicBlock getABasicBlockSuccessor(BasicBlock bb) { result = bb.getASuccessor() }
class ExitBasicBlock extends IRBlock {
ExitBasicBlock() { this.getLastInstruction() instanceof ExitFunctionInstruction }
}
predicate variableWrite = Ssa::variableWrite/4;
predicate variableRead = Ssa::variableRead/4;

View File

@@ -0,0 +1,639 @@
import SsaImplCommon
private import cpp as Cpp
private import semmle.code.cpp.ir.IR
private import DataFlowUtil
private import DataFlowImplCommon as DataFlowImplCommon
private import semmle.code.cpp.models.interfaces.Allocation as Alloc
private import semmle.code.cpp.models.interfaces.DataFlow as DataFlow
private module SourceVariables {
private newtype TSourceVariable =
TSourceIRVariable(IRVariable var) or
TSourceIRVariableIndirection(InitializeIndirectionInstruction init)
abstract class SourceVariable extends TSourceVariable {
IRVariable var;
abstract string toString();
}
class SourceIRVariable extends SourceVariable, TSourceIRVariable {
SourceIRVariable() { this = TSourceIRVariable(var) }
IRVariable getIRVariable() { result = var }
override string toString() { result = this.getIRVariable().toString() }
}
class SourceIRVariableIndirection extends SourceVariable, TSourceIRVariableIndirection {
InitializeIndirectionInstruction init;
SourceIRVariableIndirection() {
this = TSourceIRVariableIndirection(init) and var = init.getIRVariable()
}
IRVariable getUnderlyingIRVariable() { result = var }
override string toString() { result = "*" + this.getUnderlyingIRVariable().toString() }
}
}
import SourceVariables
cached
private newtype TDefOrUse =
TExplicitDef(Instruction store) { explicitWrite(_, store, _) } or
TInitializeParam(Instruction instr) {
instr instanceof InitializeParameterInstruction
or
instr instanceof InitializeIndirectionInstruction
} or
TExplicitUse(Operand op) { isExplicitUse(op) } or
TReturnParamIndirection(Operand op) { returnParameterIndirection(op, _) }
pragma[nomagic]
private int getRank(DefOrUse defOrUse, IRBlock block) {
defOrUse =
rank[result](int i, DefOrUse cand |
block.getInstruction(i) = toInstruction(cand)
|
cand order by i
)
}
private class DefOrUse extends TDefOrUse {
/** Gets the instruction associated with this definition, if any. */
Instruction asDef() { none() }
/** Gets the operand associated with this use, if any. */
Operand asUse() { none() }
/** Gets a textual representation of this element. */
abstract string toString();
/** Gets the block of this definition or use. */
abstract IRBlock getBlock();
/** Holds if this definition or use has rank `rank` in block `block`. */
cached
final predicate hasRankInBlock(IRBlock block, int rnk) { rnk = getRank(this, block) }
/** Gets the location of this element. */
abstract Cpp::Location getLocation();
}
private Instruction toInstruction(DefOrUse defOrUse) {
result = defOrUse.asDef()
or
result = defOrUse.asUse().getUse()
}
abstract class Def extends DefOrUse {
Instruction store;
/** Gets the instruction of this definition. */
Instruction getInstruction() { result = store }
/** Gets the variable that is defined by this definition. */
abstract SourceVariable getSourceVariable();
/** Holds if this definition is guaranteed to happen. */
abstract predicate isCertain();
override Instruction asDef() { result = this.getInstruction() }
override string toString() { result = "Def" }
override IRBlock getBlock() { result = this.getInstruction().getBlock() }
override Cpp::Location getLocation() { result = store.getLocation() }
}
private class ExplicitDef extends Def, TExplicitDef {
ExplicitDef() { this = TExplicitDef(store) }
override SourceVariable getSourceVariable() {
exists(VariableInstruction var |
explicitWrite(_, this.getInstruction(), var) and
result.(SourceIRVariable).getIRVariable() = var.getIRVariable()
)
}
override predicate isCertain() { explicitWrite(true, this.getInstruction(), _) }
}
private class ParameterDef extends Def, TInitializeParam {
ParameterDef() { this = TInitializeParam(store) }
override SourceVariable getSourceVariable() {
result.(SourceIRVariable).getIRVariable() =
store.(InitializeParameterInstruction).getIRVariable()
or
result.(SourceIRVariableIndirection).getUnderlyingIRVariable() =
store.(InitializeIndirectionInstruction).getIRVariable()
}
override predicate isCertain() { any() }
}
abstract class Use extends DefOrUse {
Operand use;
override Operand asUse() { result = use }
/** Gets the underlying operand of this use. */
Operand getOperand() { result = use }
override string toString() { result = "Use" }
/** Gets the variable that is used by this use. */
abstract SourceVariable getSourceVariable();
override IRBlock getBlock() { result = use.getUse().getBlock() }
override Cpp::Location getLocation() { result = use.getLocation() }
}
private class ExplicitUse extends Use, TExplicitUse {
ExplicitUse() { this = TExplicitUse(use) }
override SourceVariable getSourceVariable() {
exists(VariableInstruction var |
use.getDef() = var and
if use.getUse() instanceof ReadSideEffectInstruction
then result.(SourceIRVariableIndirection).getUnderlyingIRVariable() = var.getIRVariable()
else result.(SourceIRVariable).getIRVariable() = var.getIRVariable()
)
}
}
private class ReturnParameterIndirection extends Use, TReturnParamIndirection {
ReturnParameterIndirection() { this = TReturnParamIndirection(use) }
override SourceVariable getSourceVariable() {
exists(ReturnIndirectionInstruction ret |
returnParameterIndirection(use, ret) and
result.(SourceIRVariableIndirection).getUnderlyingIRVariable() = ret.getIRVariable()
)
}
}
private predicate isExplicitUse(Operand op) {
op.getDef() instanceof VariableAddressInstruction and
not exists(LoadInstruction load |
load.getSourceAddressOperand() = op and
load.getAUse().getUse() instanceof InitializeIndirectionInstruction
)
}
private predicate returnParameterIndirection(Operand op, ReturnIndirectionInstruction ret) {
ret.getSourceAddressOperand() = op
}
/**
* Holds if `iFrom` computes an address that is used by `iTo`.
*/
predicate addressFlow(Instruction iFrom, Instruction iTo) {
iTo.(CopyValueInstruction).getSourceValue() = iFrom
or
iTo.(ConvertInstruction).getUnary() = iFrom
or
iTo.(CheckedConvertOrNullInstruction).getUnary() = iFrom
or
iTo.(InheritanceConversionInstruction).getUnary() = iFrom
or
iTo.(PointerArithmeticInstruction).getLeft() = iFrom
or
iTo.(FieldAddressInstruction).getObjectAddress() = iFrom
or
// We traverse `LoadInstruction`s since we want to conclude that the
// destination of the store operation `*x = source()` is derived from `x`.
iTo.(LoadInstruction).getSourceAddress() = iFrom
or
// We want to include `ReadSideEffectInstruction`s for the same reason that we include
// `LoadInstruction`s, but only when a `WriteSideEffectInstruction` for the same index exists as well
// (as otherwise we know that the callee won't override the data). However, given an index `i`, the
// destination of the `WriteSideEffectInstruction` for `i` is identical to the source address of the
// `ReadSideEffectInstruction` for `i`. So we don't have to talk about the `ReadSideEffectInstruction`
// at all.
exists(WriteSideEffectInstruction write |
write.getPrimaryInstruction() = iTo and
write.getDestinationAddress() = iFrom
)
}
/**
* The reflexive, transitive closure of `addressFlow` that ends as the address of a
* store or read operation.
*/
cached
predicate addressFlowTC(Instruction iFrom, Instruction iTo) {
iTo = [getDestinationAddress(_), getSourceAddress(_)] and
addressFlow*(iFrom, iTo)
}
/**
* Gets the destination address of `instr` if it is a `StoreInstruction` or
* a `WriteSideEffectInstruction`.
*/
Instruction getDestinationAddress(Instruction instr) {
result =
[
instr.(StoreInstruction).getDestinationAddress(),
instr.(WriteSideEffectInstruction).getDestinationAddress()
]
}
/** Gets the source address of `instr` if it is an instruction that behaves like a `LoadInstruction`. */
Instruction getSourceAddress(Instruction instr) { result = getSourceAddressOperand(instr).getDef() }
/**
* Gets the operand that represents the source address of `instr` if it is an
* instruction that behaves like a `LoadInstruction`.
*/
Operand getSourceAddressOperand(Instruction instr) {
result =
[
instr.(LoadInstruction).getSourceAddressOperand(),
instr.(ReadSideEffectInstruction).getArgumentOperand()
]
}
/**
* Gets the source address of `node` if it's an instruction or operand that
* behaves like a `LoadInstruction`.
*/
Instruction getSourceAddressFromNode(Node node) {
result = getSourceAddress(node.asInstruction())
or
result = getSourceAddress(node.asOperand().(SideEffectOperand).getUse())
}
/** Gets the source value of `instr` if it's an instruction that behaves like a `LoadInstruction`. */
Instruction getSourceValue(Instruction instr) { result = getSourceValueOperand(instr).getDef() }
/**
* Gets the operand that represents the source value of `instr` if it's an instruction
* that behaves like a `LoadInstruction`.
*/
Operand getSourceValueOperand(Instruction instr) {
result = instr.(LoadInstruction).getSourceValueOperand()
or
result = instr.(ReadSideEffectInstruction).getSideEffectOperand()
}
/**
* Holds if `instr` is a `StoreInstruction` or a `WriteSideEffectInstruction` that writes to an address.
* The addresses is computed using `address`, and `certain` is `true` if the write is guaranteed to overwrite
* the entire variable.
*/
cached
predicate explicitWrite(boolean certain, Instruction instr, Instruction address) {
exists(StoreInstruction store |
store = instr and addressFlowTC(address, store.getDestinationAddress())
|
// Set `certain = false` if the address is derived from any instructions that prevents us from
// concluding that the entire variable is overridden.
if
addressFlowTC(any(Instruction i |
i instanceof FieldAddressInstruction or
i instanceof PointerArithmeticInstruction or
i instanceof LoadInstruction or
i instanceof InheritanceConversionInstruction
), store.getDestinationAddress())
then certain = false
else certain = true
)
or
addressFlowTC(address, instr.(WriteSideEffectInstruction).getDestinationAddress()) and
certain = false
}
cached
private module Cached {
private predicate defUseFlow(Node nodeFrom, Node nodeTo) {
exists(IRBlock bb1, int i1, IRBlock bb2, int i2, DefOrUse defOrUse, Use use |
defOrUse.hasRankInBlock(bb1, i1) and
use.hasRankInBlock(bb2, i2) and
adjacentDefRead(_, bb1, i1, bb2, i2) and
nodeFrom.asInstruction() = toInstruction(defOrUse) and
flowOutOfAddressStep(use.getOperand(), nodeTo)
)
}
private predicate fromStoreNode(StoreNodeInstr nodeFrom, Node nodeTo) {
// Def-use flow from a `StoreNode`.
exists(IRBlock bb1, int i1, IRBlock bb2, int i2, Def def, Use use |
nodeFrom.isTerminal() and
def.getInstruction() = nodeFrom.getStoreInstruction() and
def.hasRankInBlock(bb1, i1) and
adjacentDefRead(_, bb1, i1, bb2, i2) and
use.hasRankInBlock(bb2, i2) and
flowOutOfAddressStep(use.getOperand(), nodeTo)
)
or
// This final case is a bit annoying. The write side effect on an expression like `a = new A;` writes
// to a fresh address returned by `operator new`, and there's no easy way to use the shared SSA
// library to hook that up to the assignment to `a`. So instead we flow to the _first_ use of the
// value computed by `operator new` that occurs after `nodeFrom` (to avoid a loop in the
// dataflow graph).
exists(WriteSideEffectInstruction write, IRBlock bb, int i1, int i2, Operand op |
nodeFrom.getInstruction().(CallInstruction).getStaticCallTarget() instanceof
Alloc::OperatorNewAllocationFunction and
write = nodeFrom.getStoreInstruction() and
bb.getInstruction(i1) = write and
bb.getInstruction(i2) = op.getUse() and
// Flow to an instruction that occurs later in the block.
conversionFlow*(nodeFrom.getInstruction(), op.getDef()) and
nodeTo.asOperand() = op and
i2 > i1 and
// There is no previous instruction that also occurs after `nodeFrom`.
not exists(Instruction instr, int i |
bb.getInstruction(i) = instr and
conversionFlow(instr, op.getDef()) and
i1 < i and
i < i2
)
)
}
private predicate fromReadNode(ReadNode nodeFrom, Node nodeTo) {
exists(IRBlock bb1, int i1, IRBlock bb2, int i2, Use use1, Use use2 |
use1.hasRankInBlock(bb1, i1) and
use2.hasRankInBlock(bb2, i2) and
use1.getOperand().getDef() = nodeFrom.getInstruction() and
adjacentDefRead(_, bb1, i1, bb2, i2) and
flowOutOfAddressStep(use2.getOperand(), nodeTo)
)
}
private predicate fromPhiNode(SsaPhiNode nodeFrom, Node nodeTo) {
exists(PhiNode phi, Use use, IRBlock block, int rnk |
phi = nodeFrom.getPhiNode() and
adjacentDefRead(phi, _, _, block, rnk) and
use.hasRankInBlock(block, rnk) and
flowOutOfAddressStep(use.getOperand(), nodeTo)
)
}
private predicate toPhiNode(Node nodeFrom, SsaPhiNode nodeTo) {
// Flow to phi nodes
exists(Def def, IRBlock block, int rnk |
def.hasRankInBlock(block, rnk) and
nodeTo.hasInputAtRankInBlock(block, rnk)
|
exists(StoreNodeInstr storeNode |
storeNode = nodeFrom and
storeNode.isTerminal() and
def.getInstruction() = storeNode.getStoreInstruction()
)
or
def.getInstruction() = nodeFrom.asInstruction()
)
or
// Phi -> phi flow
nodeTo.hasInputAtRankInBlock(_, _, nodeFrom.(SsaPhiNode).getPhiNode())
}
/**
* Holds if `nodeFrom` is a read or write, and `nTo` is the next subsequent read of the variable
* written (or read) by `storeOrRead`.
*/
cached
predicate ssaFlow(Node nodeFrom, Node nodeTo) {
// Def-use/use-use flow from an `InstructionNode`.
defUseFlow(nodeFrom, nodeTo)
or
// Def-use flow from a `StoreNode`.
fromStoreNode(nodeFrom, nodeTo)
or
// Use-use flow from a `ReadNode`.
fromReadNode(nodeFrom, nodeTo)
or
fromPhiNode(nodeFrom, nodeTo)
or
toPhiNode(nodeFrom, nodeTo)
or
// When we want to transfer flow out of a `StoreNode` we perform two steps:
// 1. Find the next use of the address being stored to
// 2. Find the `LoadInstruction` that loads the address
// When the address being stored into doesn't have a `LoadInstruction` associated with it because it's
// passed into a `CallInstruction` we transfer flow to the `ReadSideEffect`, which will then flow into
// the callee. We then pickup the flow from the `InitializeIndirectionInstruction` and use the shared
// SSA library to determine where the next use of the address that received the flow is.
exists(Node init, Node mid |
nodeFrom.asInstruction().(InitializeIndirectionInstruction).getIRVariable() =
init.asInstruction().(InitializeParameterInstruction).getIRVariable() and
// No need for the flow if the next use is the instruction that returns the flow out of the callee.
not mid.asInstruction() instanceof ReturnIndirectionInstruction and
// Find the next use of the address
ssaFlow(init, mid) and
// And flow to the next load of that address
flowOutOfAddressStep([mid.asInstruction().getAUse(), mid.asOperand()], nodeTo)
)
}
/**
* Holds if `iTo` is a conversion-like instruction that copies
* the value computed by `iFrom`.
*
* This predicate is used by `fromStoreNode` to find the next use of a pointer that
* points to freshly allocated memory.
*/
private predicate conversionFlow(Instruction iFrom, Instruction iTo) {
iTo.(CopyValueInstruction).getSourceValue() = iFrom
or
iTo.(ConvertInstruction).getUnary() = iFrom
or
iTo.(CheckedConvertOrNullInstruction).getUnary() = iFrom
or
iTo.(InheritanceConversionInstruction).getUnary() = iFrom
}
pragma[noinline]
private predicate callTargetHasInputOutput(
CallInstruction call, DataFlow::FunctionInput input, DataFlow::FunctionOutput output
) {
exists(DataFlow::DataFlowFunction func |
call.getStaticCallTarget() = func and
func.hasDataFlow(input, output)
)
}
/**
* The role of `flowOutOfAddressStep` is to select the node for which we want dataflow to end up in
* after the shared SSA library's `adjacentDefRead` predicate has determined that `operand` is the
* next use of some variable.
*
* More precisely, this predicate holds if `operand` is an operand that represents an address, and:
* - `nodeTo` is the next load of that address, or
* - `nodeTo` is a `ReadNode` that uses the definition of `operand` to start a sequence of reads, or
* - `nodeTo` is the outer-most `StoreNode` that uses the address represented by `operand`. We obtain
* use-use flow in this case since `StoreNodeFlow::flowOutOf` will then provide flow to the next of
* of `operand`.
*
* There is one final (slightly annoying) case: When `operand` is a an argument to a modeled function
* without any `ReadSideEffect` (such as `std::move`). Here, the address flows from the argument to
* the return value, which might then be read later.
*/
private predicate flowOutOfAddressStep(Operand operand, Node nodeTo) {
// Flow into a read node
exists(ReadNode readNode | readNode = nodeTo |
readNode.isInitial() and
operand.getDef() = readNode.getInstruction()
)
or
exists(StoreNodeInstr storeNode, Instruction def |
storeNode = nodeTo and
def = operand.getDef()
|
storeNode.isTerminal() and
not addressFlow(def, _) and
// Only transfer flow to a store node if it doesn't immediately overwrite the address
// we've just written to.
explicitWrite(false, storeNode.getStoreInstruction(), def)
)
or
// The destination of a store operation has undergone lvalue-to-rvalue conversion and is now a
// right-hand-side of a store operation.
// Find the next use of the variable in that store operation, and recursively find the load of that
// pointer. For example, consider this case:
//
// ```cpp
// int x = source();
// int* p = &x;
// sink(*p);
// ```
//
// if we want to find the load of the address of `x`, we see that the pointer is stored into `p`,
// and we then need to recursively look for the load of `p`.
exists(
Def def, StoreInstruction store, IRBlock block1, int rnk1, Use use, IRBlock block2, int rnk2
|
store = def.getInstruction() and
store.getSourceValueOperand() = operand and
def.hasRankInBlock(block1, rnk1) and
use.hasRankInBlock(block2, rnk2) and
adjacentDefRead(_, block1, rnk1, block2, rnk2)
|
// The shared SSA library has determined that `use` is the next use of the operand
// so we find the next load of that use (but only if there is no `PostUpdateNode`) we
// need to flow into first.
not StoreNodeFlow::flowInto(store, _) and
flowOutOfAddressStep(use.getOperand(), nodeTo)
or
// It may also be the case that `store` gives rise to another store step. So let's make sure that
// we also take those into account.
StoreNodeFlow::flowInto(store, nodeTo)
)
or
// As we find the next load of an address, we might come across another use of the same variable.
// In that case, we recursively find the next use of _that_ operand, and continue searching for
// the next load of that operand. For example, consider this case:
//
// ```cpp
// int x = source();
// use(&x);
// int* p = &x;
// sink(*p);
// ```
//
// The next use of `x` after its definition is `use(&x)`, but there is a later load of the address
// of `x` that we want to flow to. So we use the shared SSA library to find the next load.
not operand = getSourceAddressOperand(_) and
exists(Use use1, Use use2, IRBlock block1, int rnk1, IRBlock block2, int rnk2 |
use1.getOperand() = operand and
use1.hasRankInBlock(block1, rnk1) and
// Don't flow to the next use if this use is part of a store operation that totally
// overrides a variable.
not explicitWrite(true, _, use1.getOperand().getDef()) and
adjacentDefRead(_, block1, rnk1, block2, rnk2) and
use2.hasRankInBlock(block2, rnk2) and
flowOutOfAddressStep(use2.getOperand(), nodeTo)
)
or
operand = getSourceAddressOperand(nodeTo.asInstruction())
or
exists(ReturnIndirectionInstruction ret |
ret.getSourceAddressOperand() = operand and
ret = nodeTo.asInstruction()
)
or
exists(ReturnValueInstruction ret |
ret.getReturnAddressOperand() = operand and
nodeTo.asInstruction() = ret
)
or
exists(CallInstruction call, int index, ReadSideEffectInstruction read |
call.getArgumentOperand(index) = operand and
read = getSideEffectFor(call, index) and
nodeTo.asOperand() = read.getSideEffectOperand()
)
or
exists(CopyInstruction copy |
not exists(getSourceAddressOperand(copy)) and
copy.getSourceValueOperand() = operand and
flowOutOfAddressStep(copy.getAUse(), nodeTo)
)
or
exists(ConvertInstruction convert |
convert.getUnaryOperand() = operand and
flowOutOfAddressStep(convert.getAUse(), nodeTo)
)
or
exists(CheckedConvertOrNullInstruction convert |
convert.getUnaryOperand() = operand and
flowOutOfAddressStep(convert.getAUse(), nodeTo)
)
or
exists(InheritanceConversionInstruction convert |
convert.getUnaryOperand() = operand and
flowOutOfAddressStep(convert.getAUse(), nodeTo)
)
or
exists(PointerArithmeticInstruction arith |
arith.getLeftOperand() = operand and
flowOutOfAddressStep(arith.getAUse(), nodeTo)
)
or
// Flow through a modeled function that has parameter -> return value flow.
exists(
CallInstruction call, int index, DataFlow::FunctionInput input,
DataFlow::FunctionOutput output
|
callTargetHasInputOutput(call, input, output) and
call.getArgumentOperand(index) = operand and
not getSideEffectFor(call, index) instanceof ReadSideEffectInstruction and
input.isParameter(index) and
output.isReturnValue() and
flowOutOfAddressStep(call.getAUse(), nodeTo)
)
}
}
import Cached
/**
* Holds if the `i`'th write in block `bb` writes to the variable `v`.
* `certain` is `true` if the write is guaranteed to overwrite the entire variable.
*/
predicate variableWrite(IRBlock bb, int i, SourceVariable v, boolean certain) {
DataFlowImplCommon::forceCachingInSameStage() and
exists(Def def |
def.hasRankInBlock(bb, i) and
v = def.getSourceVariable() and
(if def.isCertain() then certain = true else certain = false)
)
}
/**
* Holds if the `i`'th read in block `bb` reads to the variable `v`.
* `certain` is `true` if the read is guaranteed. For C++, this is always the case.
*/
predicate variableRead(IRBlock bb, int i, SourceVariable v, boolean certain) {
exists(Use use |
use.hasRankInBlock(bb, i) and
v = use.getSourceVariable() and
certain = true
)
}

View File

@@ -44,8 +44,6 @@ private predicate instructionToOperandTaintStep(Instruction fromInstr, Operand t
fromInstr = readInstr.getArgumentDef() and
toOperand = readInstr.getSideEffectOperand()
)
or
toOperand.(LoadOperand).getAnyDef() = fromInstr
}
/**
@@ -84,8 +82,6 @@ private predicate operandToInstructionTaintStep(Operand opFrom, Instruction inst
instrTo.(FieldAddressInstruction).getField().getDeclaringType() instanceof Union
)
or
instrTo.(LoadInstruction).getSourceAddressOperand() = opFrom
or
// Flow from an element to an array or union that contains it.
instrTo.(ChiInstruction).getPartialOperand() = opFrom and
not instrTo.isResultConflated() and

View File

@@ -762,11 +762,21 @@ class ReturnValueInstruction extends ReturnInstruction {
*/
final LoadOperand getReturnValueOperand() { result = this.getAnOperand() }
/**
* Gets the operand that provides the address of the value being returned by the function.
*/
final AddressOperand getReturnAddressOperand() { result = this.getAnOperand() }
/**
* Gets the instruction whose result provides the value being returned by the function, if an
* exact definition is available.
*/
final Instruction getReturnValue() { result = this.getReturnValueOperand().getDef() }
/**
* Gets the instruction whose result provides the address of the value being returned by the function.
*/
final Instruction getReturnAddress() { result = this.getReturnAddressOperand().getDef() }
}
/**

View File

@@ -20,6 +20,14 @@ private import internal.OperandInternal
private class TStageOperand =
TRegisterOperand or TNonSSAMemoryOperand or TPhiOperand or TChiOperand;
/**
* A known location. Testing `loc instanceof KnownLocation` will account for non existing locations, as
* opposed to testing `not loc isntanceof UnknownLocation`
*/
private class KnownLocation extends Language::Location {
KnownLocation() { not this instanceof Language::UnknownLocation }
}
/**
* An operand of an `Instruction`. The operand represents a use of the result of one instruction
* (the defining instruction) in another instruction (the use instruction)
@@ -45,8 +53,10 @@ class Operand extends TStageOperand {
/**
* Gets the location of the source code for this operand.
* By default this is where the operand is used, but some subclasses may override this
* using `getAnyDef()` if it makes more sense.
*/
final Language::Location getLocation() { result = this.getUse().getLocation() }
Language::Location getLocation() { result = this.getUse().getLocation() }
/**
* Gets the function that contains this operand.
@@ -269,6 +279,10 @@ class RegisterOperand extends NonPhiOperand, TRegisterOperand {
final override string toString() { result = tag.toString() }
// most `RegisterOperands` have a more meaningful location at the definition
// the only exception are specific cases of `ThisArgumentOperand`
override Language::Location getLocation() { result = this.getAnyDef().getLocation() }
final override Instruction getAnyDef() { result = defInstr }
final override Overlap getDefinitionOverlap() {
@@ -401,11 +415,19 @@ class ArgumentOperand extends RegisterOperand {
}
/**
* An operand representing the implicit 'this' argument to a member function
* An operand representing the implicit `this` argument to a member function
* call.
*/
class ThisArgumentOperand extends ArgumentOperand {
override ThisArgumentOperandTag tag;
// in most cases the def location makes more sense, but in some corner cases it
// has an unknown location: in those cases we fall back to the use location
override Language::Location getLocation() {
if this.getAnyDef().getLocation() instanceof KnownLocation
then result = this.getAnyDef().getLocation()
else result = this.getUse().getLocation()
}
}
/**

View File

@@ -762,11 +762,21 @@ class ReturnValueInstruction extends ReturnInstruction {
*/
final LoadOperand getReturnValueOperand() { result = this.getAnOperand() }
/**
* Gets the operand that provides the address of the value being returned by the function.
*/
final AddressOperand getReturnAddressOperand() { result = this.getAnOperand() }
/**
* Gets the instruction whose result provides the value being returned by the function, if an
* exact definition is available.
*/
final Instruction getReturnValue() { result = this.getReturnValueOperand().getDef() }
/**
* Gets the instruction whose result provides the address of the value being returned by the function.
*/
final Instruction getReturnAddress() { result = this.getReturnAddressOperand().getDef() }
}
/**

View File

@@ -20,6 +20,14 @@ private import internal.OperandInternal
private class TStageOperand =
TRegisterOperand or TNonSSAMemoryOperand or TPhiOperand or TChiOperand;
/**
* A known location. Testing `loc instanceof KnownLocation` will account for non existing locations, as
* opposed to testing `not loc isntanceof UnknownLocation`
*/
private class KnownLocation extends Language::Location {
KnownLocation() { not this instanceof Language::UnknownLocation }
}
/**
* An operand of an `Instruction`. The operand represents a use of the result of one instruction
* (the defining instruction) in another instruction (the use instruction)
@@ -45,8 +53,10 @@ class Operand extends TStageOperand {
/**
* Gets the location of the source code for this operand.
* By default this is where the operand is used, but some subclasses may override this
* using `getAnyDef()` if it makes more sense.
*/
final Language::Location getLocation() { result = this.getUse().getLocation() }
Language::Location getLocation() { result = this.getUse().getLocation() }
/**
* Gets the function that contains this operand.
@@ -269,6 +279,10 @@ class RegisterOperand extends NonPhiOperand, TRegisterOperand {
final override string toString() { result = tag.toString() }
// most `RegisterOperands` have a more meaningful location at the definition
// the only exception are specific cases of `ThisArgumentOperand`
override Language::Location getLocation() { result = this.getAnyDef().getLocation() }
final override Instruction getAnyDef() { result = defInstr }
final override Overlap getDefinitionOverlap() {
@@ -401,11 +415,19 @@ class ArgumentOperand extends RegisterOperand {
}
/**
* An operand representing the implicit 'this' argument to a member function
* An operand representing the implicit `this` argument to a member function
* call.
*/
class ThisArgumentOperand extends ArgumentOperand {
override ThisArgumentOperandTag tag;
// in most cases the def location makes more sense, but in some corner cases it
// has an unknown location: in those cases we fall back to the use location
override Language::Location getLocation() {
if this.getAnyDef().getLocation() instanceof KnownLocation
then result = this.getAnyDef().getLocation()
else result = this.getUse().getLocation()
}
}
/**

View File

@@ -762,11 +762,21 @@ class ReturnValueInstruction extends ReturnInstruction {
*/
final LoadOperand getReturnValueOperand() { result = this.getAnOperand() }
/**
* Gets the operand that provides the address of the value being returned by the function.
*/
final AddressOperand getReturnAddressOperand() { result = this.getAnOperand() }
/**
* Gets the instruction whose result provides the value being returned by the function, if an
* exact definition is available.
*/
final Instruction getReturnValue() { result = this.getReturnValueOperand().getDef() }
/**
* Gets the instruction whose result provides the address of the value being returned by the function.
*/
final Instruction getReturnAddress() { result = this.getReturnAddressOperand().getDef() }
}
/**

View File

@@ -20,6 +20,14 @@ private import internal.OperandInternal
private class TStageOperand =
TRegisterOperand or TNonSSAMemoryOperand or TPhiOperand or TChiOperand;
/**
* A known location. Testing `loc instanceof KnownLocation` will account for non existing locations, as
* opposed to testing `not loc isntanceof UnknownLocation`
*/
private class KnownLocation extends Language::Location {
KnownLocation() { not this instanceof Language::UnknownLocation }
}
/**
* An operand of an `Instruction`. The operand represents a use of the result of one instruction
* (the defining instruction) in another instruction (the use instruction)
@@ -45,8 +53,10 @@ class Operand extends TStageOperand {
/**
* Gets the location of the source code for this operand.
* By default this is where the operand is used, but some subclasses may override this
* using `getAnyDef()` if it makes more sense.
*/
final Language::Location getLocation() { result = this.getUse().getLocation() }
Language::Location getLocation() { result = this.getUse().getLocation() }
/**
* Gets the function that contains this operand.
@@ -269,6 +279,10 @@ class RegisterOperand extends NonPhiOperand, TRegisterOperand {
final override string toString() { result = tag.toString() }
// most `RegisterOperands` have a more meaningful location at the definition
// the only exception are specific cases of `ThisArgumentOperand`
override Language::Location getLocation() { result = this.getAnyDef().getLocation() }
final override Instruction getAnyDef() { result = defInstr }
final override Overlap getDefinitionOverlap() {
@@ -401,11 +415,19 @@ class ArgumentOperand extends RegisterOperand {
}
/**
* An operand representing the implicit 'this' argument to a member function
* An operand representing the implicit `this` argument to a member function
* call.
*/
class ThisArgumentOperand extends ArgumentOperand {
override ThisArgumentOperandTag tag;
// in most cases the def location makes more sense, but in some corner cases it
// has an unknown location: in those cases we fall back to the use location
override Language::Location getLocation() {
if this.getAnyDef().getLocation() instanceof KnownLocation
then result = this.getAnyDef().getLocation()
else result = this.getUse().getLocation()
}
}
/**

View File

@@ -34,6 +34,16 @@ private class IteratorByTraits extends Iterator {
IteratorByTraits() { exists(IteratorTraits it | it.getIteratorType() = this) }
}
/**
* The C++ standard includes an `std::iterator_traits` specialization for pointer types. When
* this specialization is included in the database, a pointer type `T*` will be an instance
* of the `IteratorByTraits` class. However, if the `T*` specialization is not in the database,
* we need to explicitly include them with this class.
*/
private class IteratorByPointer extends Iterator instanceof PointerType {
IteratorByPointer() { not this instanceof IteratorByTraits }
}
/**
* A type which has the typedefs expected for an iterator.
*/

5
cpp/ql/src/CHANGELOG.md Normal file
View File

@@ -0,0 +1,5 @@
## 0.0.4
### New Queries
* A new query `cpp/non-https-url` has been added for C/C++. The query flags uses of `http` URLs that might be better replaced with `https`.

View File

@@ -29,7 +29,7 @@ class SqliteFunctionCall extends FunctionCall {
}
predicate sqlite_encryption_used() {
any(StringLiteral l).getValue().toLowerCase().regexpMatch("pragma key.*") or
any(StringLiteral l).getValue().toLowerCase().matches("pragma key%") or
any(StringLiteral l).getValue().toLowerCase().matches("%attach%database%key%") or
any(FunctionCall fc).getTarget().getName().matches("sqlite%\\_key\\_%")
}

View File

@@ -0,0 +1,9 @@
void openUrl(char *url)
{
// ...
}
openUrl("http://example.com"); // BAD
openUrl("https://example.com"); // GOOD: Opening a connection to a URL using HTTPS enforces SSL.

View File

@@ -0,0 +1,35 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>Constructing URLs with the HTTP protocol can lead to unsecured connections.</p>
</overview>
<recommendation>
<p>When you construct a URL, ensure that you use an HTTPS URL rather than an HTTP URL. Then, any connections that are made using that URL are secure SSL connections.</p>
</recommendation>
<example>
<p>The following example shows two ways of opening a connection using a URL. When the connection is
opened using an HTTP URL rather than an HTTPS URL, the connection is unsecured. When the connection is opened using an HTTPS URL, the connection is a secure SSL connection.</p>
<sample src="UseOfHttp.cpp" />
</example>
<references>
<li>
OWASP:
<a href="https://cheatsheetseries.owasp.org/cheatsheets/Transport_Layer_Protection_Cheat_Sheet.html">Transport Layer Protection Cheat Sheet</a>.
</li>
<li>
OWASP Top 10:
<a href="https://owasp.org/Top10/A08_2021-Software_and_Data_Integrity_Failures/">A08:2021 - Software and Data Integrity Failures</a>.
</li>
</references>
</qhelp>

View File

@@ -0,0 +1,90 @@
/**
* @name Failure to use HTTPS URLs
* @description Non-HTTPS connections can be intercepted by third parties.
* @kind path-problem
* @problem.severity warning
* @precision medium
* @id cpp/non-https-url
* @tags security
* external/cwe/cwe-319
* external/cwe/cwe-345
*/
import cpp
import semmle.code.cpp.dataflow.TaintTracking
import DataFlow::PathGraph
/**
* A string matching private host names of IPv4 and IPv6, which only matches
* the host portion therefore checking for port is not necessary.
* Several examples are localhost, reserved IPv4 IP addresses including
* 127.0.0.1, 10.x.x.x, 172.16.x,x, 192.168.x,x, and reserved IPv6 addresses
* including [0:0:0:0:0:0:0:1] and [::1]
*/
class PrivateHostName extends string {
bindingset[this]
PrivateHostName() {
this.regexpMatch("(?i)localhost(?:[:/?#].*)?|127\\.0\\.0\\.1(?:[:/?#].*)?|10(?:\\.[0-9]+){3}(?:[:/?#].*)?|172\\.16(?:\\.[0-9]+){2}(?:[:/?#].*)?|192.168(?:\\.[0-9]+){2}(?:[:/?#].*)?|\\[?0:0:0:0:0:0:0:1\\]?(?:[:/?#].*)?|\\[?::1\\]?(?:[:/?#].*)?")
}
}
/**
* A string containing an HTTP URL not in a private domain.
*/
class HttpStringLiteral extends StringLiteral {
HttpStringLiteral() {
exists(string s | this.getValue() = s |
s = "http"
or
exists(string tail |
tail = s.regexpCapture("http://(.*)", 1) and not tail instanceof PrivateHostName
) and
not TaintTracking::localExprTaint(any(StringLiteral p |
p.getValue() instanceof PrivateHostName
), this.getParent*())
)
}
}
/**
* Taint tracking configuration for HTTP connections.
*/
class HttpStringToUrlOpenConfig extends TaintTracking::Configuration {
HttpStringToUrlOpenConfig() { this = "HttpStringToUrlOpenConfig" }
override predicate isSource(DataFlow::Node src) {
// Sources are strings containing an HTTP URL not in a private domain.
src.asExpr() instanceof HttpStringLiteral
}
override predicate isSink(DataFlow::Node sink) {
// Sinks can be anything that demonstrates the string is likely to be
// accessed as a URL, for example using it in a network access. Some
// URLs are only ever displayed or used for data processing.
exists(FunctionCall fc |
fc.getTarget()
.hasGlobalOrStdName([
"system", "gethostbyname", "gethostbyname2", "gethostbyname_r", "getaddrinfo",
"X509_load_http", "X509_CRL_load_http"
]) and
sink.asExpr() = fc.getArgument(0)
or
fc.getTarget().hasGlobalOrStdName(["send", "URLDownloadToFile", "URLDownloadToCacheFile"]) and
sink.asExpr() = fc.getArgument(1)
or
fc.getTarget().hasGlobalOrStdName(["curl_easy_setopt", "getnameinfo"]) and
sink.asExpr() = fc.getArgument(2)
or
fc.getTarget().hasGlobalOrStdName(["ShellExecute", "ShellExecuteA", "ShellExecuteW"]) and
sink.asExpr() = fc.getArgument(3)
)
}
}
from
HttpStringToUrlOpenConfig config, DataFlow::PathNode source, DataFlow::PathNode sink,
HttpStringLiteral str
where
config.hasFlowPath(source, sink) and
str = source.getNode().asExpr()
select str, source, sink, "A URL may be constructed with the HTTP protocol."

View File

@@ -0,0 +1,5 @@
## 0.0.4
### New Queries
* A new query `cpp/non-https-url` has been added for C/C++. The query flags uses of `http` URLs that might be better replaced with `https`.

View File

@@ -0,0 +1,2 @@
---
lastReleaseVersion: 0.0.4

View File

@@ -0,0 +1,24 @@
...
chroot("/myFold/myTmp"); // BAD
...
chdir("/myFold/myTmp"); // BAD
...
int fd = open("/myFold/myTmp", O_RDONLY | O_DIRECTORY);
fchdir(fd); // BAD
...
if (chdir("/myFold/myTmp") == -1) {
exit(-1);
}
if (chroot("/myFold/myTmp") == -1) { // GOOD
exit(-1);
}
...
if (chdir("/myFold/myTmp") == -1) { // GOOD
exit(-1);
}
...
int fd = open("/myFold/myTmp", O_RDONLY | O_DIRECTORY);
if(fchdir(fd) == -1) { // GOOD
exit(-1);
}
...

View File

@@ -0,0 +1,23 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>Working with changing directories, without checking the return value or pinning the directory, may not be safe. Requires the attention of developers.</p>
</overview>
<example>
<p>The following example demonstrates erroneous and corrected work with changing working directories.</p>
<sample src="IncorrectChangingWorkingDirectory.cpp" />
</example>
<references>
<li>
CERT C Coding Standard:
<a href="https://wiki.sei.cmu.edu/confluence/display/c/POS05-C.+Limit+access+to+files+by+creating+a+jail">POS05-C. Limit access to files by creating a jail.</a>
</li>
</references>
</qhelp>

View File

@@ -0,0 +1,69 @@
/**
* @name Find work with changing working directories, with security errors.
* @description Not validating the return value or pinning the directory can be unsafe.
* @kind problem
* @id cpp/work-with-changing-working-directories
* @problem.severity warning
* @precision medium
* @tags correctness
* security
* external/cwe/cwe-243
* external/cwe/cwe-252
*/
import cpp
import semmle.code.cpp.commons.Exclusions
/** Holds if a `fc` function call is available before or after a `chdir` function call. */
predicate inExistsChdir(FunctionCall fcp) {
exists(FunctionCall fctmp |
(
fctmp.getTarget().hasGlobalOrStdName("chdir") or
fctmp.getTarget().hasGlobalOrStdName("fchdir")
) and
(
fcp.getBasicBlock().getASuccessor*() = fctmp.getBasicBlock() or
fctmp.getBasicBlock().getASuccessor*() = fcp.getBasicBlock()
)
)
}
/** Holds if a `fc` function call is available before or after a function call containing a `chdir` call. */
predicate outExistsChdir(FunctionCall fcp) {
exists(FunctionCall fctmp |
exists(FunctionCall fctmp2 |
(
fctmp2.getTarget().hasGlobalOrStdName("chdir") or
fctmp2.getTarget().hasGlobalOrStdName("fchdir")
) and
// we are looking for a call containing calls chdir and fchdir
fctmp2.getEnclosingStmt().getParentStmt*() = fctmp.getTarget().getEntryPoint().getChildStmt*()
) and
(
fcp.getBasicBlock().getASuccessor*() = fctmp.getBasicBlock() or
fctmp.getBasicBlock().getASuccessor*() = fcp.getBasicBlock()
)
)
}
from FunctionCall fc, string msg
where
fc.getTarget().hasGlobalOrStdName("chroot") and
not inExistsChdir(fc) and
not outExistsChdir(fc) and
// in this section I want to exclude calls to functions containing chroot that have a direct path to chdir, or to a function containing chdir
exists(FunctionCall fctmp |
fc.getEnclosingStmt().getParentStmt*() = fctmp.getTarget().getEntryPoint().getChildStmt*() and
not inExistsChdir(fctmp) and
not outExistsChdir(fctmp)
) and
msg = "Creation of 'chroot' jail without changing the working directory"
or
(
fc.getTarget().hasGlobalOrStdName("chdir") or
fc.getTarget().hasGlobalOrStdName("fchdir")
) and
fc instanceof ExprInVoidContext and
not isFromMacroDefinition(fc) and
msg = "Unchecked return value for call to '" + fc.getTarget().getName() + "'."
select fc, msg

View File

@@ -0,0 +1,14 @@
...
fp = fopen("/tmp/name.tmp","w"); // BAD
...
char filename = tmpnam(NULL);
fp = fopen(filename,"w"); // BAD
...
strcat (filename, "/tmp/name.XXXXXX");
fd = mkstemp(filename);
if ( fd < 0 ) {
return error;
}
fp = fdopen(fd,"w") // GOOD
...

View File

@@ -0,0 +1,23 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>Working with a file, without checking its existence and its rights, as well as working with names that can be predicted, may not be safe. Requires the attention of developers.</p>
</overview>
<example>
<p>The following example demonstrates erroneous and corrected work with file.</p>
<sample src="InsecureTemporaryFile.cpp" />
</example>
<references>
<li>
CERT C Coding Standard:
<a href="https://wiki.sei.cmu.edu/confluence/display/c/CON33-C.+Avoid+race+conditions+when+using+library+functions">CON33-C. Avoid race conditions when using library functions</a>.
</li>
</references>
</qhelp>

View File

@@ -0,0 +1,112 @@
/**
* @name Insecure generation of filenames.
* @description Using a predictable filename when creating a temporary file can lead to an attacker-controlled input.
* @kind problem
* @id cpp/insecure-generation-of-filename
* @problem.severity warning
* @precision medium
* @tags correctness
* security
* external/cwe/cwe-377
*/
import cpp
import semmle.code.cpp.valuenumbering.GlobalValueNumbering
/** Holds for a function `f` that has an argument at index `apos` used to read the file. */
predicate numberArgumentRead(Function f, int apos) {
f.hasGlobalOrStdName("fgets") and apos = 2
or
f.hasGlobalOrStdName("fread") and apos = 3
or
f.hasGlobalOrStdName("read") and apos = 0
or
f.hasGlobalOrStdName("fscanf") and apos = 0
}
/** Holds for a function `f` that has an argument at index `apos` used to write to file */
predicate numberArgumentWrite(Function f, int apos) {
f.hasGlobalOrStdName("fprintf") and apos = 0
or
f.hasGlobalOrStdName("fputs") and apos = 1
or
f.hasGlobalOrStdName("write") and apos = 0
or
f.hasGlobalOrStdName("fwrite") and apos = 3
or
f.hasGlobalOrStdName("fflush") and apos = 0
}
from FunctionCall fc, string msg
where
// search for functions for generating a name, without a guarantee of the absence of a file during the period of work with it.
(
fc.getTarget().hasGlobalOrStdName("tmpnam") or
fc.getTarget().hasGlobalOrStdName("tmpnam_s") or
fc.getTarget().hasGlobalOrStdName("tmpnam_r")
) and
not exists(FunctionCall fctmp |
(
fctmp.getTarget().hasGlobalOrStdName("mktemp") or
fctmp.getTarget().hasGlobalOrStdName("mkstemp") or
fctmp.getTarget().hasGlobalOrStdName("mkstemps") or
fctmp.getTarget().hasGlobalOrStdName("mkdtemp")
) and
(
fc.getBasicBlock().getASuccessor*() = fctmp.getBasicBlock() or
fctmp.getBasicBlock().getASuccessor*() = fc.getBasicBlock()
)
) and
msg =
"Finding the name of a file that does not exist does not mean that it will not be exist at the next operation."
or
// finding places to work with a file without setting permissions, but with predictable names.
(
fc.getTarget().hasGlobalOrStdName("fopen") or
fc.getTarget().hasGlobalOrStdName("open")
) and
fc.getNumberOfArguments() = 2 and
exists(FunctionCall fctmp, int i |
numberArgumentWrite(fctmp.getTarget(), i) and
globalValueNumber(fc) = globalValueNumber(fctmp.getArgument(i))
) and
not exists(FunctionCall fctmp, int i |
numberArgumentRead(fctmp.getTarget(), i) and
globalValueNumber(fc) = globalValueNumber(fctmp.getArgument(i))
) and
exists(FunctionCall fctmp |
(
fctmp.getTarget().hasGlobalOrStdName("strcat") or
fctmp.getTarget().hasGlobalOrStdName("strcpy")
) and
globalValueNumber(fc.getArgument(0)) = globalValueNumber(fctmp.getAnArgument())
or
fctmp.getTarget().hasGlobalOrStdName("getenv") and
globalValueNumber(fc.getArgument(0)) = globalValueNumber(fctmp)
or
(
fctmp.getTarget().hasGlobalOrStdName("asprintf") or
fctmp.getTarget().hasGlobalOrStdName("vasprintf") or
fctmp.getTarget().hasGlobalOrStdName("xasprintf") or
fctmp.getTarget().hasGlobalOrStdName("xvasprintf ")
) and
exists(Variable vrtmp |
vrtmp = fc.getArgument(0).(VariableAccess).getTarget() and
vrtmp = fctmp.getArgument(0).(AddressOfExpr).getAddressable().(Variable) and
not vrtmp instanceof Field
)
) and
not exists(FunctionCall fctmp |
(
fctmp.getTarget().hasGlobalOrStdName("umask") or
fctmp.getTarget().hasGlobalOrStdName("fchmod") or
fctmp.getTarget().hasGlobalOrStdName("chmod")
) and
(
fc.getBasicBlock().getASuccessor*() = fctmp.getBasicBlock() or
fctmp.getBasicBlock().getASuccessor*() = fc.getBasicBlock()
)
) and
msg =
"Creating a file for writing without evaluating its existence and setting permissions can be unsafe."
select fc, msg

View File

@@ -1,5 +1,6 @@
name: codeql/cpp-queries
version: 0.0.2
version: 0.0.5-dev
groups: cpp
dependencies:
codeql/cpp-all: "*"
codeql/suite-helpers: "*"

View File

@@ -0,0 +1,2 @@
| test.cpp:12:7:12:12 | call to chroot | Creation of 'chroot' jail without changing the working directory |
| test.cpp:29:3:29:7 | call to chdir | Unchecked return value for call to 'chdir'. |

View File

@@ -0,0 +1 @@
experimental/Security/CWE/CWE-243/IncorrectChangingWorkingDirectory.ql

View File

@@ -0,0 +1,46 @@
typedef int FILE;
#define size_t int
size_t fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream);
FILE *fopen(const char *filename, const char *mode);
int fread(char *buf, int size, int count, FILE *fp);
int fclose(FILE *fp);
int chroot(char *path);
int chdir(char *path);
void exit(int status);
int funTest1(){
if (chroot("/myFold/myTmp") == -1) { // BAD
exit(-1);
}
return 0;
}
int funTest2(){
if (chdir("/myFold/myTmp") == -1) { // GOOD
exit(-1);
}
if (chroot("/myFold/myTmp") == -1) { // GOOD
exit(-1);
}
return 0;
}
int funTest3(){
chdir("/myFold/myTmp"); // BAD
return 0;
}
int main(int argc, char *argv[])
{
if(argc = 0) {
funTest3();
return 2;
}
if(argc = 1)
funTest1();
else
funTest2();
FILE *fp = fopen(argv[1], "w");
fwrite("12345", 5, 1, fp);
fclose(fp);
return 0;
}

View File

@@ -0,0 +1,2 @@
| test.cpp:16:20:16:25 | call to tmpnam | Finding the name of a file that does not exist does not mean that it will not be exist at the next operation. |
| test.cpp:42:8:42:12 | call to fopen | Creating a file for writing without evaluating its existence and setting permissions can be unsafe. |

View File

@@ -0,0 +1 @@
experimental/Security/CWE/CWE-377/InsecureTemporaryFile.ql

View File

@@ -0,0 +1,68 @@
typedef int FILE;
#define NULL (0)
FILE *fopen(char *filename, const char *mode);
FILE *fdopen(int handle, char *mode);
char * tmpnam(char * name);
int mkstemp(char * name);
char * strcat(char *str1, const char *str2);
int umask(int pmode);
int chmod(char * filename,int pmode);
int fprintf(FILE *fp,const char *fmt, ...);
int fclose(FILE *stream);
int funcTest1()
{
FILE *fp;
char *filename = tmpnam(NULL); // BAD
fp = fopen(filename,"w");
fprintf(fp,"%s\n","data to file");
fclose(fp);
return 0;
}
int funcTest2()
{
FILE *fp;
int fd;
char filename[80];
strcat (filename, "/tmp/name.XXXXXX");
fd = mkstemp(filename);
if ( fd < 0 ) {
return 1;
}
fp = fdopen(fd,"w"); // GOOD
return 0;
}
int funcTest3()
{
FILE *fp;
char filename[80];
strcat(filename, "/tmp/tmp.name");
fp = fopen(filename,"w"); // BAD
fprintf(fp,"%s\n","data to file");
fclose(fp);
return 0;
}
int funcTest4()
{
FILE *fp;
char filename[80];
umask(0022);
strcat(filename, "/tmp/tmp.name");
fp = fopen(filename,"w"); // GOOD
chmod(filename,0666);
fprintf(fp,"%s\n","data to file");
fclose(fp);
return 0;
}
int main(int argc, char *argv[])
{
funcTest1();
funcTest2();
funcTest3();
funcTest4();
return 0;
}

View File

@@ -4,8 +4,8 @@ using SinkFunction = void (*)(int);
void notSink(int notSinkParam);
void callsSink(int sinkParam) {
sink(sinkParam); // $ ast,ir=31:28 ast,ir=32:31 ast,ir=34:22 MISSING: ast,ir=28
void callsSink(int sinkParam) { // $ ir-path=31:23 ir-path=32:26 ir-path=34:17
sink(sinkParam); // $ ast=31:28 ast=32:31 ast=34:22 ir-sink
}
struct {
@@ -25,13 +25,13 @@ void assignGlobals() {
};
void testStruct() {
globalStruct.sinkPtr(atoi(getenv("TAINTED"))); // $ MISSING: ast,ir
globalStruct.sinkPtr(atoi(getenv("TAINTED"))); // $ MISSING: ir-path,ast
globalStruct.notSinkPtr(atoi(getenv("TAINTED"))); // clean
globalUnion.sinkPtr(atoi(getenv("TAINTED"))); // $ ast,ir
globalUnion.notSinkPtr(atoi(getenv("TAINTED"))); // $ ast,ir
globalUnion.sinkPtr(atoi(getenv("TAINTED"))); // $ ast ir-path
globalUnion.notSinkPtr(atoi(getenv("TAINTED"))); // $ ast ir-path
globalSinkPtr(atoi(getenv("TAINTED"))); // $ ast,ir
globalSinkPtr(atoi(getenv("TAINTED"))); // $ ast ir-path
}
class B {
@@ -48,19 +48,19 @@ class D2 : public D1 {
class D3 : public D2 {
public:
void f(const char* p) override {
sink(p); // $ ast,ir=58:10 ast,ir=60:17 ast,ir=61:28 ast,ir=62:29 ast,ir=63:33 SPURIOUS: ast,ir=73:30
void f(const char* p) override { // $ ir-path=58:10 ir-path=60:17 ir-path=61:28 ir-path=62:29 ir-path=63:33 SPURIOUS: ir-path=73:30
sink(p); // $ ast=58:10 ast=60:17 ast=61:28 ast=62:29 ast=63:33 ir-sink SPURIOUS: ast=73:30
}
};
void test_dynamic_cast() {
B* b = new D3();
b->f(getenv("VAR")); // $ ast,ir
b->f(getenv("VAR")); // $ ast ir-path
((D2*)b)->f(getenv("VAR")); // $ ast,ir
static_cast<D2*>(b)->f(getenv("VAR")); // $ ast,ir
dynamic_cast<D2*>(b)->f(getenv("VAR")); // $ ast,ir
reinterpret_cast<D2*>(b)->f(getenv("VAR")); // $ ast,ir
((D2*)b)->f(getenv("VAR")); // $ ast ir-path
static_cast<D2*>(b)->f(getenv("VAR")); // $ ast ir-path
dynamic_cast<D2*>(b)->f(getenv("VAR")); // $ ast ir-path
reinterpret_cast<D2*>(b)->f(getenv("VAR")); // $ ast ir-path
B* b2 = new D2();
b2->f(getenv("VAR"));
@@ -70,5 +70,5 @@ void test_dynamic_cast() {
dynamic_cast<D2*>(b2)->f(getenv("VAR"));
reinterpret_cast<D2*>(b2)->f(getenv("VAR"));
dynamic_cast<D3*>(b2)->f(getenv("VAR")); // $ SPURIOUS: ast,ir
dynamic_cast<D3*>(b2)->f(getenv("VAR")); // $ SPURIOUS: ast ir-path
}

View File

@@ -7,9 +7,10 @@ import cpp
import semmle.code.cpp.security.TaintTrackingImpl as ASTTaintTracking
import semmle.code.cpp.ir.dataflow.DefaultTaintTracking as IRDefaultTaintTracking
import IRDefaultTaintTracking::TaintedWithPath as TaintedWithPath
import TaintedWithPath::Private
import TestUtilities.InlineExpectationsTest
predicate isSink(Element sink) {
predicate isSinkArgument(Element sink) {
exists(FunctionCall call |
call.getTarget().getName() = "sink" and
sink = call.getAnArgument()
@@ -19,43 +20,49 @@ predicate isSink(Element sink) {
predicate astTaint(Expr source, Element sink) { ASTTaintTracking::tainted(source, sink) }
class SourceConfiguration extends TaintedWithPath::TaintTrackingConfiguration {
override predicate isSink(Element e) { any() }
override predicate isSink(Element e) { isSinkArgument(e) }
}
predicate irTaint(Expr source, Element sink) {
TaintedWithPath::taintedWithPath(source, sink, _, _)
predicate irTaint(Element source, TaintedWithPath::PathNode predNode, string tag) {
exists(TaintedWithPath::PathNode sinkNode |
TaintedWithPath::taintedWithPath(source, _, _, sinkNode) and
predNode = getAPredecessor*(sinkNode) and
// Make sure the path is actually reachable from this predecessor.
// Otherwise, we could pick `predNode` to be b when `source` is
// `source1` in this dataflow graph:
// source1 ---> a ---> c ---> sinkNode
// ^
// source2 ---> b --/
source = getElementFromPathNode(getAPredecessor*(predNode)) and
if predNode = sinkNode then tag = "ir-sink" else tag = "ir-path"
)
}
class IRDefaultTaintTrackingTest extends InlineExpectationsTest {
IRDefaultTaintTrackingTest() { this = "IRDefaultTaintTrackingTest" }
override string getARelevantTag() { result = "ir" }
override string getARelevantTag() { result = ["ir-path", "ir-sink"] }
override predicate hasActualResult(Location location, string element, string tag, string value) {
exists(Expr source, Element tainted, int n |
tag = "ir" and
irTaint(source, tainted) and
(
isSink(tainted)
or
exists(Element sink |
isSink(sink) and
irTaint(tainted, sink)
)
) and
n = strictcount(Expr otherSource | irTaint(otherSource, tainted)) and
(
n = 1 and value = ""
or
// If there is more than one source for this sink
// we specify the source location explicitly.
n > 1 and
exists(Element source, Element elem, TaintedWithPath::PathNode node, int n |
irTaint(source, node, tag) and
elem = getElementFromPathNode(node) and
n = count(int startline | getAPredecessor(node).hasLocationInfo(_, startline, _, _, _)) and
location = elem.getLocation() and
element = elem.toString()
|
// Zero predecessors means it's a source, and 1 predecessor means it has a unique predecessor.
// In either of these cases we leave out the location.
n = [0, 1] and value = ""
or
// If there is more than one predecessor for this node
// we specify the source location explicitly.
n > 1 and
exists(TaintedWithPath::PathNode pred | pred = getAPredecessor(node) |
value =
source.getLocation().getStartLine().toString() + ":" +
source.getLocation().getStartColumn()
) and
location = tainted.getLocation() and
element = tainted.toString()
getElementFromPathNode(pred).getLocation().getStartLine().toString() + ":" +
getElementFromPathNode(pred).getLocation().getStartColumn()
)
)
}
}
@@ -70,10 +77,10 @@ class ASTTaintTrackingTest extends InlineExpectationsTest {
tag = "ast" and
astTaint(source, tainted) and
(
isSink(tainted)
isSinkArgument(tainted)
or
exists(Element sink |
isSink(sink) and
isSinkArgument(sink) and
astTaint(tainted, sink)
)
) and

View File

@@ -13,8 +13,8 @@ struct S {
}
};
void calls_sink_with_argv(const char* a) {
sink(a); // $ ast,ir=96:26 ast,ir=98:18
void calls_sink_with_argv(const char* a) { // $ ir-path=96:26 ir-path=102:26
sink(a); // $ ast=96:26 ast=98:18 ir-sink
}
extern int i;
@@ -26,8 +26,8 @@ public:
class DerivedCallsSink : public BaseWithPureVirtual {
public:
void f(const char* p) override {
sink(p); // $ ir ast=108:10 SPURIOUS: ast=111:10
void f(const char* p) override { // $ ir-path
sink(p); // $ ast=108:10 ir-sink SPURIOUS: ast=111:10
}
};
@@ -38,8 +38,8 @@ public:
class DerivedCallsSinkDiamond1 : virtual public BaseWithPureVirtual {
public:
void f(const char* p) override {
sink(p); // $ ast,ir
void f(const char* p) override { // $ ir-path
sink(p); // $ ast ir-sink
}
};
@@ -49,23 +49,23 @@ public:
};
class DerivesMultiple : public DerivedCallsSinkDiamond1, public DerivedDoesNotCallSinkDiamond2 {
void f(const char* p) override {
DerivedCallsSinkDiamond1::f(p);
void f(const char* p) override { // $ ir-path=53:37 ir-path=115:11
DerivedCallsSinkDiamond1::f(p); // $ ir-path
}
};
template<typename T>
class CRTP {
public:
void f(const char* p) {
static_cast<T*>(this)->g(p);
void f(const char* p) { // $ ir-path
static_cast<T*>(this)->g(p); // $ ir-path
}
};
class CRTPCallsSink : public CRTP<CRTPCallsSink> {
public:
void g(const char* p) {
sink(p); // $ ast,ir
void g(const char* p) { // $ ir-path
sink(p); // $ ast ir-sink
}
};
@@ -78,8 +78,8 @@ class Derived2 : public Derived1 {
class Derived3 : public Derived2 {
public:
void f(const char* p) override {
sink(p); // $ ast,ir=124:19 ast,ir=126:43 ast,ir=128:44
void f(const char* p) override { // $ ir-path=124:19 ir-path=126:43 ir-path=128:44
sink(p); // $ ast=124:19 ast=126:43 ast=128:44 ir-sink
}
};
@@ -89,41 +89,41 @@ class CRTPDoesNotCallSink : public CRTP<CRTPDoesNotCallSink> {
};
int main(int argc, char *argv[]) {
sink(argv[0]); // $ ast,ir
sink(argv[0]); // $ ast,ir-path,ir-sink
sink(reinterpret_cast<int>(argv)); // $ ast,ir
sink(reinterpret_cast<int>(argv)); // $ ast,ir-sink
calls_sink_with_argv(argv[1]); // $ ast,ir
calls_sink_with_argv(argv[1]); // $ ast,ir-path
char*** p = &argv; // $ ast,ir
char*** p = &argv; // $ ast,ir-path
sink(*p[0]); // $ ast,ir
sink(*p[0]); // $ ast ir-sink=96:26 ir-sink=98:18
calls_sink_with_argv(*p[i]); // $ MISSING: ast,ir
calls_sink_with_argv(*p[i]); // $ ir-path=96:26 ir-path=98:18 MISSING:ast
sink(*(argv + 1)); // $ ast,ir
sink(*(argv + 1)); // $ ast ir-path ir-sink
BaseWithPureVirtual* b = new DerivedCallsSink;
b->f(argv[1]); // $ ast,ir
b->f(argv[1]); // $ ast,ir-path
b = new DerivedDoesNotCallSink;
b->f(argv[0]); // $ SPURIOUS: ast
BaseWithPureVirtual* b2 = new DerivesMultiple;
b2->f(argv[i]); // $ ast,ir
b2->f(argv[i]); // $ ast,ir-path
CRTP<CRTPDoesNotCallSink> crtp_not_call_sink;
crtp_not_call_sink.f(argv[0]); // clean
CRTP<CRTPCallsSink> crtp_calls_sink;
crtp_calls_sink.f(argv[0]); // $ ast,ir
crtp_calls_sink.f(argv[0]); // $ ast,ir-path
Derived1* calls_sink = new Derived3;
calls_sink->f(argv[1]); // $ ast,ir
calls_sink->f(argv[1]); // $ ast,ir-path
static_cast<Derived2*>(calls_sink)->f(argv[1]); // $ ast,ir
static_cast<Derived2*>(calls_sink)->f(argv[1]); // $ ast,ir-path
dynamic_cast<Derived2*>(calls_sink)->f(argv[1]); // $ ast,ir
dynamic_cast<Derived2*>(calls_sink)->f(argv[1]); // $ ast,ir-path
}

View File

@@ -190,9 +190,9 @@ void test_pointers1()
sink(ptr1); // $ ast MISSING: ir
sink(ptr2); // $ SPURIOUS: ast
sink(*ptr2); // $ ast MISSING: ir
sink(ptr3); // $ ast MISSING: ir
sink(ptr4); // $ SPURIOUS: ast
sink(*ptr4); // $ ast MISSING: ir
sink(ptr3); // $ ast,ir
sink(ptr4); // $ SPURIOUS: ast,ir
sink(*ptr4); // $ ast,ir
}
void test_pointers2()
@@ -210,8 +210,8 @@ void test_pointers2()
sink(buffer); // $ MISSING: ast,ir
sink(ptr1); // $ ast MISSING: ir
sink(ptr2); // $ SPURIOUS: ast
sink(*ptr2); // $ ast MISSING: ir
sink(ptr2); // $ SPURIOUS: ast,ir
sink(*ptr2); // $ ast,ir
sink(ptr3); // $ MISSING: ast,ir
sink(ptr4); // clean
sink(*ptr4); // $ MISSING: ast,ir
@@ -254,8 +254,8 @@ int test_readv_and_writev(iovec* iovs) {
sink(*iovs); // $ast,ir
char* p = (char*)iovs[1].iov_base;
sink(p); // $ ir MISSING: ast
sink(*p); // $ ir MISSING: ast
sink(p); // $ MISSING: ast,ir
sink(*p); // $ MISSING: ast,ir
writev(0, iovs, 16); // $ remote
}

View File

@@ -89,12 +89,12 @@ void test_stringstream()
sink(ss1);
sink(ss2); // $ ir MISSING: ast
sink(ss3); // $ MISSING: ast,ir
sink(ss3); // $ ir MISSING: ast
sink(ss4); // $ ir MISSING: ast
sink(ss5); // $ ir MISSING: ast
sink(ss1.str());
sink(ss2.str()); // $ ir MISSING: ast
sink(ss3.str()); // $ MISSING: ast,ir
sink(ss3.str()); // $ ir MISSING: ast
sink(ss4.str()); // $ ir MISSING: ast
sink(ss5.str()); // $ ir MISSING: ast
}

View File

@@ -26,62 +26,592 @@ unreachableNodeCCtx
localCallNodes
postIsNotPre
postHasUniquePre
| test.cpp:373:5:373:20 | Store | PostUpdateNode should have one pre-update node but has 0. |
uniquePostUpdate
postIsInSameCallable
reverseRead
argHasPostUpdate
postWithInFlow
| BarrierGuard.cpp:49:3:49:17 | Chi | PostUpdateNode should not be the target of local flow. |
| BarrierGuard.cpp:60:3:60:18 | Chi | PostUpdateNode should not be the target of local flow. |
| clang.cpp:28:3:28:34 | Chi | PostUpdateNode should not be the target of local flow. |
| clang.cpp:34:22:34:27 | Chi | PostUpdateNode should not be the target of local flow. |
| clang.cpp:34:32:34:37 | Chi | PostUpdateNode should not be the target of local flow. |
| clang.cpp:39:32:39:37 | Chi | PostUpdateNode should not be the target of local flow. |
| clang.cpp:39:42:39:47 | Chi | PostUpdateNode should not be the target of local flow. |
| clang.cpp:43:35:43:40 | Chi | PostUpdateNode should not be the target of local flow. |
| clang.cpp:43:51:43:51 | Chi | PostUpdateNode should not be the target of local flow. |
| clang.cpp:49:25:49:30 | Chi | PostUpdateNode should not be the target of local flow. |
| clang.cpp:49:35:49:40 | Chi | PostUpdateNode should not be the target of local flow. |
| clang.cpp:50:3:50:26 | Chi | PostUpdateNode should not be the target of local flow. |
| example.c:17:19:17:22 | Chi | PostUpdateNode should not be the target of local flow. |
| example.c:17:21:17:21 | Chi | PostUpdateNode should not be the target of local flow. |
| example.c:24:2:24:30 | Chi | PostUpdateNode should not be the target of local flow. |
| example.c:24:13:24:30 | Chi | PostUpdateNode should not be the target of local flow. |
| example.c:26:2:26:25 | Chi | PostUpdateNode should not be the target of local flow. |
| file://:0:0:0:0 | Chi | PostUpdateNode should not be the target of local flow. |
| file://:0:0:0:0 | Chi | PostUpdateNode should not be the target of local flow. |
| file://:0:0:0:0 | Chi | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:13:12:13:12 | Chi | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:13:15:13:15 | Chi | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:28:10:31:2 | Chi | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:28:10:31:2 | Chi | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:43:3:43:14 | Chi | PostUpdateNode should not be the target of local flow. |
| ref.cpp:11:5:11:13 | Chi | PostUpdateNode should not be the target of local flow. |
| ref.cpp:20:5:20:13 | Chi | PostUpdateNode should not be the target of local flow. |
| ref.cpp:22:7:22:13 | Chi | PostUpdateNode should not be the target of local flow. |
| ref.cpp:24:7:24:13 | Chi | PostUpdateNode should not be the target of local flow. |
| ref.cpp:29:5:29:18 | Chi | PostUpdateNode should not be the target of local flow. |
| ref.cpp:31:7:31:13 | Chi | PostUpdateNode should not be the target of local flow. |
| ref.cpp:39:7:39:13 | Chi | PostUpdateNode should not be the target of local flow. |
| ref.cpp:44:5:44:18 | Chi | PostUpdateNode should not be the target of local flow. |
| ref.cpp:46:7:46:13 | Chi | PostUpdateNode should not be the target of local flow. |
| ref.cpp:48:7:48:13 | Chi | PostUpdateNode should not be the target of local flow. |
| ref.cpp:75:5:75:17 | Chi | PostUpdateNode should not be the target of local flow. |
| ref.cpp:83:5:83:17 | Chi | PostUpdateNode should not be the target of local flow. |
| ref.cpp:87:7:87:17 | Chi | PostUpdateNode should not be the target of local flow. |
| ref.cpp:89:7:89:17 | Chi | PostUpdateNode should not be the target of local flow. |
| ref.cpp:94:5:94:22 | Chi | PostUpdateNode should not be the target of local flow. |
| ref.cpp:96:7:96:17 | Chi | PostUpdateNode should not be the target of local flow. |
| ref.cpp:104:7:104:17 | Chi | PostUpdateNode should not be the target of local flow. |
| ref.cpp:109:5:109:22 | Chi | PostUpdateNode should not be the target of local flow. |
| ref.cpp:113:7:113:17 | Chi | PostUpdateNode should not be the target of local flow. |
| ref.cpp:115:7:115:17 | Chi | PostUpdateNode should not be the target of local flow. |
| test.cpp:91:3:91:18 | Chi | PostUpdateNode should not be the target of local flow. |
| test.cpp:115:3:115:17 | Chi | PostUpdateNode should not be the target of local flow. |
| test.cpp:120:3:120:10 | Chi | PostUpdateNode should not be the target of local flow. |
| test.cpp:125:3:125:11 | Chi | PostUpdateNode should not be the target of local flow. |
| test.cpp:359:5:359:20 | Chi | PostUpdateNode should not be the target of local flow. |
| test.cpp:373:5:373:20 | Chi | PostUpdateNode should not be the target of local flow. |
| test.cpp:373:5:373:20 | Store | PostUpdateNode should not be the target of local flow. |
| test.cpp:465:3:465:15 | Chi | PostUpdateNode should not be the target of local flow. |
| BarrierGuard.cpp:49:6:49:6 | x [post update] | PostUpdateNode should not be the target of local flow. |
| BarrierGuard.cpp:60:3:60:4 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| BarrierGuard.cpp:60:7:60:7 | x [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:8:20:8:29 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:22:8:22:20 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:22:8:22:20 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:22:9:22:20 | sourceArray1 [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:26:8:26:24 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:26:8:26:24 | sourceStruct1_ptr [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:26:8:26:24 | sourceStruct1_ptr [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:28:3:28:19 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:28:22:28:23 | m1 [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:30:8:30:24 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:30:8:30:24 | sourceStruct1_ptr [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:30:8:30:24 | sourceStruct1_ptr [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:34:19:34:41 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:34:19:34:41 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:39:16:39:21 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:39:30:39:51 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:39:30:39:51 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:43:26:43:53 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:43:26:43:53 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:49:7:49:16 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:49:22:49:44 | PointerAdd [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:49:22:49:44 | PointerAdd [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:50:3:50:12 | array to pointer conversion [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:50:3:50:12 | stackArray [post update] | PostUpdateNode should not be the target of local flow. |
| clang.cpp:50:3:50:15 | access to array [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:6:29:6:37 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:7:29:7:37 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:9:30:9:45 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:10:30:10:45 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:15:8:15:8 | Argument this [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:15:8:15:8 | ConvertToNonVirtualBase [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:15:8:15:8 | this [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:16:30:16:45 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:17:31:17:39 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:21:8:21:8 | Argument this [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:21:8:21:8 | ConvertToNonVirtualBase [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:21:8:21:8 | this [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:22:30:22:45 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:24:31:24:39 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:29:8:29:13 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:29:29:29:34 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:31:8:31:13 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:31:8:31:13 | topPtr [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:31:8:31:13 | topPtr [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:32:8:32:13 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:32:8:32:13 | topPtr [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:32:8:32:13 | topPtr [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:33:3:33:8 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:33:3:33:8 | topPtr [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:33:3:33:8 | topPtr [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:35:8:35:13 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:35:8:35:13 | topPtr [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:35:8:35:13 | topPtr [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:36:8:36:13 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:36:8:36:13 | topPtr [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:36:8:36:13 | topPtr [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:37:3:37:8 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:37:3:37:8 | topPtr [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:37:3:37:8 | topPtr [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:39:8:39:13 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:39:8:39:13 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:39:8:39:13 | topRef [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:39:8:39:13 | topRef [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:40:8:40:13 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:40:8:40:13 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:40:8:40:13 | topRef [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:40:8:40:13 | topRef [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:41:3:41:8 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:41:3:41:8 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:41:3:41:8 | topRef [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:41:3:41:8 | topRef [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:43:8:43:13 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:43:8:43:13 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:43:8:43:13 | topRef [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:43:8:43:13 | topRef [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:44:8:44:13 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:44:8:44:13 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:44:8:44:13 | topRef [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:44:8:44:13 | topRef [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:45:3:45:8 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:45:3:45:8 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:45:3:45:8 | topRef [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:45:3:45:8 | topRef [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:51:3:51:22 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:55:8:55:19 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:55:8:55:19 | globalBottom [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:55:8:55:19 | globalBottom [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:56:8:56:19 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:56:8:56:19 | globalMiddle [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:56:8:56:19 | globalMiddle [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:58:8:58:23 | call to readGlobalBottom [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:58:8:58:23 | call to readGlobalBottom [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:60:3:60:14 | globalBottom [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:60:18:60:29 | Call [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:60:18:60:29 | new [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:60:18:60:29 | new [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:61:3:61:14 | globalMiddle [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:61:18:61:29 | Call [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:61:18:61:29 | new [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:61:18:61:29 | new [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:65:3:65:22 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:65:10:65:21 | Call [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:65:10:65:21 | new [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:65:10:65:21 | new [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:69:3:69:5 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:69:3:69:5 | top [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:69:3:69:5 | top [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:73:3:73:5 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:73:3:73:5 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:73:3:73:5 | top [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:73:3:73:5 | top [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:77:21:77:34 | call to allocateBottom [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:77:21:77:34 | call to allocateBottom [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:78:23:78:39 | (reference to) [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:78:23:78:39 | * ... [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:78:23:78:39 | * ... [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:78:24:78:37 | call to allocateBottom [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:80:8:80:8 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:81:3:81:3 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:81:3:81:3 | x [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:81:3:81:3 | x [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:85:3:85:13 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:89:3:89:10 | call to identity [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:89:3:89:10 | call to identity [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:89:12:89:17 | (Middle *)... [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:89:12:89:17 | (Top *)... [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:89:12:89:17 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:89:12:89:17 | bottom [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:89:12:89:17 | bottom [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:90:3:90:10 | call to identity [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:90:3:90:10 | call to identity [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:90:12:90:14 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:90:12:90:14 | top [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:90:12:90:14 | top [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:100:3:100:18 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:105:5:105:17 | maybeCallSink [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:113:30:113:38 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:117:31:117:46 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:127:10:127:15 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:127:31:127:36 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:129:10:129:15 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:129:10:129:15 | topPtr [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:129:10:129:15 | topPtr [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:130:10:130:15 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:130:10:130:15 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:130:10:130:15 | topRef [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:130:10:130:15 | topRef [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:148:3:148:3 | u [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:148:5:148:5 | f [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:168:3:168:4 | u2 [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:168:6:168:6 | u [post update] | PostUpdateNode should not be the target of local flow. |
| dispatch.cpp:168:8:168:8 | f [post update] | PostUpdateNode should not be the target of local flow. |
| example.c:17:19:17:22 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| example.c:17:19:17:22 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| example.c:24:9:24:9 | x [post update] | PostUpdateNode should not be the target of local flow. |
| example.c:24:20:24:20 | y [post update] | PostUpdateNode should not be the target of local flow. |
| example.c:26:9:26:9 | x [post update] | PostUpdateNode should not be the target of local flow. |
| example.c:26:18:26:24 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| example.c:26:18:26:24 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| example.c:26:19:26:24 | coords [post update] | PostUpdateNode should not be the target of local flow. |
| example.c:28:14:28:25 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| example.c:28:14:28:25 | (void *)... [post update] | PostUpdateNode should not be the target of local flow. |
| example.c:28:22:28:25 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| example.c:28:23:28:25 | pos [post update] | PostUpdateNode should not be the target of local flow. |
| globals.cpp:5:9:5:13 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| globals.cpp:13:5:13:19 | flowTestGlobal1 [post update] | PostUpdateNode should not be the target of local flow. |
| globals.cpp:23:5:23:19 | flowTestGlobal2 [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:8:6:8:6 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:9:6:9:6 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:10:6:10:6 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:11:6:11:6 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| 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: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: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. |
| lambdas.cpp:23:3:23:14 | v [post update] | PostUpdateNode should not be the target of local flow. |
| 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: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. |
| lambdas.cpp:40:13:40:13 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:43:3:43:3 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:43:3:43:3 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:43:3:43:3 | c [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:45:4:45:4 | (reference to) [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:45:4:45:4 | t [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:45:4:45:4 | t [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:45:7:45:7 | (reference to) [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:45:7:45:7 | u [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:45:7:45:7 | u [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:45:10:45:10 | (reference to) [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:45:10:45:10 | w [post update] | PostUpdateNode should not be the target of local flow. |
| lambdas.cpp:45:10:45:10 | w [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:11:5:11:7 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:11:5:11:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:11:5:11:7 | lhs [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:16:12:16:14 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:16:12:16:14 | (reference to) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:16:12:16:14 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:16:12:16:14 | lhs [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:16:12:16:14 | lhs [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:20:5:20:7 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:20:5:20:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:20:5:20:7 | lhs [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:22:7:22:9 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:22:7:22:9 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:22:7:22:9 | lhs [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:24:7:24:9 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:24:7:24:9 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:24:7:24:9 | lhs [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:29:5:29:7 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:29:5:29:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:29:5:29:7 | out [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:31:7:31:9 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:31:7:31:9 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:31:7:31:9 | out [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:37:21:37:23 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:37:21:37:23 | (reference to) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:37:21:37:23 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:37:21:37:23 | out [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:37:21:37:23 | out [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:39:7:39:9 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:39:7:39:9 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:39:7:39:9 | out [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:44:5:44:7 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:44:5:44:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:44:5:44:7 | out [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:46:7:46:9 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:46:7:46:9 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:46:7:46:9 | out [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:48:7:48:9 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:48:7:48:9 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:48:7:48:9 | out [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:55:19:55:20 | (reference to) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:55:19:55:20 | x1 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:55:19:55:20 | x1 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:58:15:58:16 | (reference to) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:58:15:58:16 | x2 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:58:15:58:16 | x2 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:61:26:61:27 | (reference to) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:61:26:61:27 | x3 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:61:26:61:27 | x3 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:64:15:64:16 | (reference to) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:64:15:64:16 | x4 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:64:15:64:16 | x4 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:75:5:75:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:75:5:75:7 | lhs [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:75:9:75:11 | val [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:79:12:79:14 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:79:12:79:14 | (reference to) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:79:12:79:14 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:79:12:79:14 | lhs [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:79:12:79:14 | lhs [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:83:5:83:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:83:5:83:7 | lhs [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:83:9:83:11 | val [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:87:7:87:9 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:87:7:87:9 | lhs [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:87:11:87:13 | val [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:89:7:89:9 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:89:7:89:9 | lhs [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:89:11:89:13 | val [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:94:5:94:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:94:5:94:7 | out [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:94:9:94:11 | val [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:96:7:96:9 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:96:7:96:9 | out [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:96:11:96:13 | val [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:102:21:102:23 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:102:21:102:23 | (reference to) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:102:21:102:23 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:102:21:102:23 | out [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:102:21:102:23 | out [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:104:7:104:9 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:104:7:104:9 | out [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:104:11:104:13 | val [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:109:5:109:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:109:5:109:7 | out [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:109:9:109:11 | val [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:113:7:113:9 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:113:7:113:9 | out [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:113:11:113:13 | val [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:115:7:115:9 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:115:7:115:9 | out [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:115:11:115:13 | val [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:122:19:122:20 | (reference to) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:122:19:122:20 | x1 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:122:19:122:20 | x1 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:125:15:125:16 | (reference to) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:125:15:125:16 | x2 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:125:15:125:16 | x2 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:128:26:128:27 | (reference to) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:128:26:128:27 | x3 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:128:26:128:27 | x3 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:131:15:131:16 | (reference to) [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:131:15:131:16 | x4 [post update] | PostUpdateNode should not be the target of local flow. |
| ref.cpp:131:15:131:16 | x4 [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:6:7:6:8 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:8:3:8:4 | t2 [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:12:5:12:6 | t2 [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:17:3:17:4 | t1 [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:23:12:23:12 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:23:27:23:27 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:24:5:24:6 | t1 [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:41:9:41:10 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:41:17:41:18 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:42:9:42:9 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:43:10:43:20 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:43:10:43:20 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:45:5:45:5 | t [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:45:9:45:19 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:45:9:45:19 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:50:9:50:10 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:50:24:50:24 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:52:7:52:7 | t [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:54:7:54:7 | t [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:67:14:67:15 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:68:8:68:9 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:69:8:69:9 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:70:14:70:15 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:77:3:77:4 | u1 [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:80:7:80:8 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:84:8:84:18 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:85:3:85:4 | i1 [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:91:3:91:9 | (reference dereference) [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:91:3:91:9 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:91:3:91:9 | source1 [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:100:9:100:9 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:101:10:101:12 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:102:5:102:5 | t [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:107:9:107:9 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:108:10:108:12 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:109:5:109:5 | t [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:115:3:115:6 | * ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:115:4:115:6 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:115:4:115:6 | out [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:116:3:116:11 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:120:3:120:6 | * ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:120:4:120:6 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:120:4:120:6 | out [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:121:3:121:11 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:125:3:125:6 | * ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:125:4:125:6 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:125:4:125:6 | out [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:126:3:126:11 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:134:3:134:11 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:138:7:138:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:139:7:139:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:145:3:145:11 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:149:7:149:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:151:7:151:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:156:7:156:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:158:3:158:11 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:162:7:162:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:164:7:164:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:171:7:171:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:172:3:172:11 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:176:7:176:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:177:7:177:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:190:5:190:13 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:194:9:194:9 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:194:13:194:27 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:194:13:194:27 | this [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:194:13:194:27 | this [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:195:9:195:15 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:196:9:196:9 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:201:9:201:15 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:203:5:203:19 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:207:9:207:9 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:207:13:207:33 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:207:13:207:33 | this [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:207:13:207:33 | this [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:209:9:209:9 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:209:13:209:33 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:209:13:209:33 | this [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:209:13:209:33 | this [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:214:9:214:15 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:215:9:215:9 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:217:5:217:13 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:221:9:221:9 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:221:13:221:34 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:221:13:221:34 | this [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:221:13:221:34 | this [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:223:9:223:9 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:223:13:223:34 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:223:13:223:34 | this [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:223:13:223:34 | this [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:230:9:230:9 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:231:9:231:15 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:232:5:232:19 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:236:9:236:9 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:236:13:236:24 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:236:13:236:24 | this [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:236:13:236:24 | this [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:237:9:237:9 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:245:7:245:12 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:245:7:245:12 | this [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:245:7:245:12 | this [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:246:7:246:16 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:246:7:246:16 | this [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:246:7:246:16 | this [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:250:11:250:11 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:251:7:251:12 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:251:7:251:12 | this [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:251:7:251:12 | this [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:255:11:255:17 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:256:7:256:12 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:256:7:256:12 | this [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:256:7:256:12 | this [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:265:11:265:11 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:265:15:265:20 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:265:15:265:20 | this [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:265:15:265:20 | this [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:267:7:267:7 | x [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:267:11:267:20 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:267:11:267:20 | this [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:267:11:267:20 | this [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:272:11:272:11 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:273:7:273:23 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:273:14:273:19 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:273:14:273:19 | this [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:273:14:273:19 | this [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:277:11:277:17 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:278:7:278:29 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:278:14:278:19 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:278:14:278:19 | this [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:278:14:278:19 | this [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:282:11:282:11 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:283:7:283:15 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:288:13:288:13 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:288:17:288:22 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:288:17:288:22 | this [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:288:17:288:22 | this [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:290:9:290:9 | x [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:290:13:290:22 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:290:13:290:22 | this [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:290:13:290:22 | this [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:295:13:295:13 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:295:17:295:22 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:295:17:295:22 | this [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:295:17:295:22 | this [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:296:9:296:17 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:300:13:300:19 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:300:23:300:28 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:300:23:300:28 | this [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:300:23:300:28 | this [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:301:9:301:23 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:305:13:305:13 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:306:9:306:17 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:314:2:314:2 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:314:2:314:2 | this [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:314:2:314:2 | this [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:317:6:317:6 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:317:10:317:10 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:317:10:317:10 | this [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:317:10:317:10 | this [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:319:6:319:6 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:319:10:319:10 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:319:10:319:10 | this [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:319:10:319:10 | this [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:321:2:321:2 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:321:2:321:2 | this [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:321:2:321:2 | this [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:324:2:324:10 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:333:5:333:13 | globalVar [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:347:5:347:13 | globalVar [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:359:5:359:9 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:359:5:359:9 | field [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:364:5:364:14 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:364:5:364:14 | this [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:364:5:364:14 | this [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:373:5:373:9 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:373:5:373:9 | field [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:374:5:374:20 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:374:5:374:20 | this [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:374:5:374:20 | this [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:383:7:383:9 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:384:10:384:13 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:384:10:384:13 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:384:10:384:13 | (void *)... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:384:11:384:13 | tmp [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:389:7:389:9 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:390:8:390:14 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:391:10:391:13 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:391:10:391:13 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:391:10:391:13 | (void *)... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:391:11:391:13 | tmp [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:400:10:400:13 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:400:10:400:13 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:400:10:400:13 | (void *)... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:400:11:400:13 | tmp [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:406:8:406:14 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:407:10:407:13 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:407:10:407:13 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:407:10:407:13 | (void *)... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:407:11:407:13 | tmp [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:417:16:417:20 | (reference to) [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:417:16:417:20 | local [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:417:16:417:20 | local [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:423:20:423:25 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:423:20:423:25 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:423:21:423:25 | local [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:429:20:429:24 | array to pointer conversion [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:429:20:429:24 | local [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:429:20:429:24 | local [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:436:18:436:23 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:436:18:436:23 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:436:19:436:23 | local [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:442:18:442:22 | array to pointer conversion [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:442:18:442:22 | local [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:442:18:442:22 | local [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:453:7:453:11 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:456:7:456:9 | tmp [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:458:7:458:9 | tmp [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:465:3:465:4 | * ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:465:4:465:4 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:465:4:465:4 | p [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:469:7:469:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:470:21:470:22 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:470:21:470:22 | & ... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:470:22:470:22 | x [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:481:21:481:21 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:481:21:481:30 | (void *)... [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:481:21:481:30 | content [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:481:24:481:30 | FieldAddress [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:481:24:481:30 | content [post update] | PostUpdateNode should not be the target of local flow. |
| test.cpp:482:8:482:16 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| true_upon_entry.cpp:9:7:9:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| true_upon_entry.cpp:10:12:10:12 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| true_upon_entry.cpp:10:27:10:27 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| true_upon_entry.cpp:11:5:11:5 | x [post update] | PostUpdateNode should not be the target of local flow. |
| true_upon_entry.cpp:17:7:17:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| true_upon_entry.cpp:18:12:18:12 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| true_upon_entry.cpp:18:35:18:35 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| true_upon_entry.cpp:19:5:19:5 | x [post update] | PostUpdateNode should not be the target of local flow. |
| true_upon_entry.cpp:25:7:25:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| true_upon_entry.cpp:26:12:26:12 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| true_upon_entry.cpp:26:27:26:27 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| true_upon_entry.cpp:27:5:27:5 | x [post update] | PostUpdateNode should not be the target of local flow. |
| true_upon_entry.cpp:33:7:33:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| true_upon_entry.cpp:34:12:34:12 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| true_upon_entry.cpp:34:27:34:27 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| true_upon_entry.cpp:37:5:37:5 | x [post update] | PostUpdateNode should not be the target of local flow. |
| true_upon_entry.cpp:43:7:43:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| true_upon_entry.cpp:44:12:44:12 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| true_upon_entry.cpp:44:27:44:27 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| true_upon_entry.cpp:47:5:47:5 | x [post update] | PostUpdateNode should not be the target of local flow. |
| true_upon_entry.cpp:54:7:54:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| true_upon_entry.cpp:55:12:55:12 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| true_upon_entry.cpp:55:30:55:30 | y [post update] | PostUpdateNode should not be the target of local flow. |
| true_upon_entry.cpp:55:38:55:38 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| true_upon_entry.cpp:62:7:62:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| true_upon_entry.cpp:63:12:63:12 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| true_upon_entry.cpp:63:30:63:30 | y [post update] | PostUpdateNode should not be the target of local flow. |
| true_upon_entry.cpp:63:38:63:38 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| true_upon_entry.cpp:64:5:64:5 | x [post update] | PostUpdateNode should not be the target of local flow. |
| true_upon_entry.cpp:70:7:70:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| true_upon_entry.cpp:76:12:76:12 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| true_upon_entry.cpp:76:30:76:30 | x [post update] | PostUpdateNode should not be the target of local flow. |
| true_upon_entry.cpp:76:38:76:38 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| true_upon_entry.cpp:83:7:83:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| true_upon_entry.cpp:84:12:84:12 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| true_upon_entry.cpp:84:20:84:20 | y [post update] | PostUpdateNode should not be the target of local flow. |
| true_upon_entry.cpp:84:38:84:38 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| true_upon_entry.cpp:90:7:90:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| true_upon_entry.cpp:91:12:91:12 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| true_upon_entry.cpp:91:20:91:20 | x [post update] | PostUpdateNode should not be the target of local flow. |
| true_upon_entry.cpp:91:38:91:38 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| true_upon_entry.cpp:97:7:97:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| true_upon_entry.cpp:98:7:98:7 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| true_upon_entry.cpp:101:18:101:18 | VariableAddress [post update] | PostUpdateNode should not be the target of local flow. |
| true_upon_entry.cpp:102:5:102:5 | x [post update] | PostUpdateNode should not be the target of local flow. |

View File

@@ -18,7 +18,7 @@ void test_lambdas()
sink(a()); // $ ast,ir
auto b = [&] {
sink(t); // $ ast MISSING: ir
sink(t); // $ ast,ir
sink(u);
v = source(); // (v is reference captured)
};

View File

@@ -1,3 +1,4 @@
| example.c:15:37:15:37 | b | example.c:15:37:15:37 | b |
| example.c:15:37:15:37 | b | example.c:19:6:19:6 | b |
| example.c:15:44:15:46 | pos | example.c:24:24:24:26 | pos |
| example.c:15:44:15:46 | pos | example.c:28:23:28:25 | pos |
@@ -70,8 +71,10 @@
| test.cpp:391:11:391:13 | tmp | test.cpp:391:10:391:13 | & ... |
| test.cpp:391:17:391:23 | source1 | test.cpp:391:10:391:13 | ref arg & ... |
| test.cpp:391:17:391:23 | source1 | test.cpp:391:16:391:23 | & ... |
| test.cpp:480:67:480:67 | s | test.cpp:480:67:480:67 | s |
| test.cpp:480:67:480:67 | s | test.cpp:481:21:481:21 | s |
| test.cpp:480:67:480:67 | s | test.cpp:482:20:482:20 | s |
| test.cpp:481:21:481:21 | s [post update] | test.cpp:480:67:480:67 | s |
| test.cpp:481:21:481:21 | s [post update] | test.cpp:482:20:482:20 | s |
| test.cpp:481:24:481:30 | ref arg content | test.cpp:482:23:482:29 | content |
| test.cpp:482:23:482:29 | content | test.cpp:483:9:483:17 | p_content |

View File

@@ -100,14 +100,14 @@ void local_references(int &source1, int clean1) {
int t = source();
int &ref = t;
t = clean1;
sink(ref); // $ SPURIOUS: ast
sink(ref); // $ SPURIOUS: ast,ir
}
{
int t = clean1;
int &ref = t;
t = source();
sink(ref); // $ ir MISSING: ast
sink(ref); // $ MISSING: ast,ir
}
}
@@ -346,7 +346,7 @@ namespace FlowThroughGlobals {
int taintAndCall() {
globalVar = source();
calledAfterTaint();
sink(globalVar); // $ ast MISSING: ir
sink(globalVar); // $ ast,ir
}
}
@@ -355,21 +355,21 @@ namespace FlowThroughGlobals {
class FlowThroughFields {
int field = 0;
int taintField() {
void taintField() {
field = source();
}
int f() {
void f() {
sink(field); // tainted or clean? Not sure.
taintField();
sink(field); // $ ast MISSING: ir
}
int calledAfterTaint() {
sink(field); // $ ast,ir
}
int taintAndCall() {
void calledAfterTaint() {
sink(field); // $ ast,ir
}
void taintAndCall() {
field = source();
calledAfterTaint();
sink(field); // $ ast,ir

View File

@@ -46,7 +46,7 @@ public:
{
C *c = new C();
B *b = B::make(c);
sink(b->c); // $ast MISSING: ir
sink(b->c); // $ast,ir
}
void f2()
@@ -54,7 +54,7 @@ public:
B *b = new B();
b->set(new C1());
sink(b->get()); // $ ast ir=55:12
sink((new B(new C()))->get()); // $ ast ir
sink((new B(new C()))->get()); // $ ast,ir
}
void f3()
@@ -63,7 +63,7 @@ public:
B *b2;
b2 = setOnB(b1, new C2());
sink(b1->c); // no flow
sink(b2->c); // $ ast MISSING: ir
sink(b2->c); // $ ast ir=64:21
}
void f4()
@@ -72,7 +72,7 @@ public:
B *b2;
b2 = setOnBWrap(b1, new C2());
sink(b1->c); // no flow
sink(b2->c); // $ ast MISSING: ir
sink(b2->c); // $ ast ir=73:25
}
B *setOnBWrap(B *b1, C *c)
@@ -117,7 +117,7 @@ public:
}
if (C1 *c1 = dynamic_cast<C1 *>(cc))
{
sink(c1->a); // $ SPURIOUS: ast
sink(c1->a); // $ SPURIOUS: ast,ir
}
}
@@ -150,7 +150,7 @@ public:
B *b = new B();
D *d = new D(b, r());
sink(d->b); // $ ast,ir=143:25 ast,ir=150:12
sink(d->b->c); // $ ast MISSING: ir
sink(d->b->c); // $ ast,ir
sink(b->c); // $ ast,ir
}
@@ -162,11 +162,11 @@ public:
MyList *l3 = new MyList(nullptr, l2);
sink(l3->head); // no flow, b is nested beneath at least one ->next
sink(l3->next->head); // no flow
sink(l3->next->next->head); // $ ast MISSING: ir
sink(l3->next->next->head); // $ ast,ir
sink(l3->next->next->next->head); // no flow
for (MyList *l = l3; l != nullptr; l = l->next)
{
sink(l->head); // $ ast MISSING: ir
sink(l->head); // $ ast,ir
}
}

View File

@@ -6,7 +6,7 @@ class B
Elem *e = new Elem();
Box1 *b1 = new Box1(e, nullptr);
Box2 *b2 = new Box2(b1);
sink(b2->box1->elem1); // $ ast MISSING: ir
sink(b2->box1->elem1); // $ ast,ir
sink(b2->box1->elem2); // no flow
}
@@ -16,7 +16,7 @@ class B
Box1 *b1 = new B::Box1(nullptr, e);
Box2 *b2 = new Box2(b1);
sink(b2->box1->elem1); // no flow
sink(b2->box1->elem2); // $ ast MISSING: ir
sink(b2->box1->elem2); // $ ast,ir
}
static void sink(void *o) {}

View File

@@ -1,10 +1,10 @@
void sink(...);
class C
{
class Elem
{
};
private:
Elem *s1 = new Elem();
const Elem *s2 = new Elem();
@@ -26,12 +26,10 @@ public:
void func()
{
sink(s1); // $ast ir
sink(s1); // $ast,ir
sink(s2); // $ MISSING: ast,ir
sink(s3); // $ast ir
sink(s3); // $ast MISSING: ir
sink(s4); // $ MISSING: ast,ir
}
static void sink(const void *o) {}
};
const C::Elem *C::s4 = new Elem();

View File

@@ -19,7 +19,7 @@ public:
};
static void sinkWrap(Box2* b2) {
sink(b2->getBox1()->getElem()); // $ast=28:15 ast=35:15 ast=42:15 ast=49:15 MISSING: ir
sink(b2->getBox1()->getElem()); // $ast,ir=28:15 ast,ir=35:15 ast,ir=42:15 ast,ir=49:15
}
Box2* boxfield;
@@ -61,6 +61,6 @@ public:
private:
void f5b() {
sink(boxfield->box->elem); // $ ast MISSING: ir
sink(boxfield->box->elem); // $ ast,ir
}
};

View File

@@ -18,7 +18,7 @@ void sink(char *b);
void handlePacket(packet *p)
{
sink(p->data.buffer); // $ ast MISSING: ir
sink(p->data.buffer); // $ ast,ir
}
void f(buf* b)
@@ -28,7 +28,7 @@ void f(buf* b)
argument_source(raw);
argument_source(b->buffer);
argument_source(p.data.buffer);
sink(raw); // $ ast MISSING: ir
sink(b->buffer); // $ ast MISSING: ir
sink(raw); // $ ast,ir
sink(b->buffer); // $ ast,ir
handlePacket(&p);
}

View File

@@ -18,7 +18,7 @@ class IRConf extends Configuration {
override predicate isSink(Node sink) {
exists(Call c |
c.getTarget().hasName("sink") and
c.getAnArgument() = sink.asConvertedExpr()
c.getAnArgument() = [sink.asExpr(), sink.asConvertedExpr()]
)
}

View File

@@ -35,12 +35,12 @@ void assignAfterAlias() {
S s1 = { 0, 0 };
S &ref1 = s1;
ref1.m1 = user_input();
sink(s1.m1); // $ ir MISSING: ast
sink(s1.m1); // $ MISSING: ast,ir
S s2 = { 0, 0 };
S &ref2 = s2;
s2.m1 = user_input();
sink(ref2.m1); // $ ir MISSING: ast
sink(ref2.m1); // $ MISSING: ast,ir
}
void assignAfterCopy() {
@@ -77,14 +77,14 @@ void pointerIntermediate() {
Wrapper w = { { 0, 0 } };
S *s = &w.s;
s->m1 = user_input();
sink(w.s.m1); // $ ir MISSING: ast
sink(w.s.m1); // $ MISSING: ast,ir
}
void referenceIntermediate() {
Wrapper w = { { 0, 0 } };
S &s = w.s;
s.m1 = user_input();
sink(w.s.m1); // $ ir MISSING: ast
sink(w.s.m1); // $ MISSING: ast,ir
}
void nestedAssign() {
@@ -99,7 +99,7 @@ void addressOfField() {
S s_copy = s;
int* px = &s_copy.m1;
sink(*px); // $ ir MISSING: ast
sink(*px); // $ MISSING: ast,ir
}
void taint_a_ptr(int* pa) {
@@ -119,7 +119,7 @@ struct S_with_pointer {
void pointer_deref(int* xs) {
taint_a_ptr(xs);
sink(xs[0]); // $ ir MISSING: ast
sink(xs[0]); // $ MISSING: ast,ir
}
void pointer_deref_sub(int* xs) {
@@ -129,18 +129,18 @@ void pointer_deref_sub(int* xs) {
void pointer_many_addrof_and_deref(int* xs) {
taint_a_ptr(xs);
sink(*&*&*xs); // $ ir MISSING: ast
sink(*&*&*xs); // $ MISSING: ast,ir
}
void pointer_unary_plus(int* xs) {
taint_a_ptr(+xs);
sink(*+xs); // $ ir MISSING: ast
sink(*+xs); // $ MISSING: ast,ir
}
void pointer_member_index(S_with_pointer s) {
taint_a_ptr(s.data);
// `s.data` is points to all-aliased-memory
sink(s.data[0]); // $ MISSING: ir,ast
sink(s.data[0]); // $ ir MISSING: ast
}
void member_array_different_field(S_with_pointer* s) {
@@ -156,13 +156,13 @@ struct S_with_array {
void pointer_member_deref() {
S_with_array s;
taint_a_ptr(s.data);
sink(*s.data); // $ ast MISSING: ir
sink(*s.data); // $ ast,ir
}
void array_member_deref() {
S_with_array s;
taint_a_ptr(s.data);
sink(s.data[0]); // $ ast MISSING: ir
sink(s.data[0]); // $ ast,ir
}
struct S2 {

View File

@@ -5,7 +5,7 @@ void local_array() {
void *arr[10] = { 0 };
arr[0] = user_input();
sink(arr[0]); // $ ast,ir
sink(arr[1]); // $ SPURIOUS: ast
sink(arr[1]); // $ SPURIOUS: ast,ir
sink(*arr); // $ ast,ir
sink(*&arr[0]); // $ ast,ir
}
@@ -14,7 +14,7 @@ void local_array_convoluted_assign() {
void *arr[10] = { 0 };
*&arr[0] = user_input();
sink(arr[0]); // $ ast,ir
sink(arr[1]); // $ SPURIOUS: ast
sink(arr[1]); // $ SPURIOUS: ast,ir
}
struct inner {
@@ -35,17 +35,17 @@ struct outer {
void nested_array_1(outer o) {
o.nested.arr[1].data = user_input();
sink(o.nested.arr[1].data); // $ ast,ir
sink(o.nested.arr[0].data); // $ SPURIOUS: ast
sink(o.nested.arr[0].data); // $ SPURIOUS: ast,ir
}
void nested_array_2(outer o) {
o.indirect->arr[1].data = user_input();
sink(o.indirect->arr[1].data); // $ ast MISSING: ir
sink(o.indirect->arr[0].data); // $ SPURIOUS: ast
sink(o.indirect->arr[1].data); // $ ast,ir
sink(o.indirect->arr[0].data); // $ SPURIOUS: ast,ir
}
void nested_array_3(outer o) {
o.indirect->ptr[1].data = user_input();
sink(o.indirect->ptr[1].data); // $ MISSING: ir,ast
sink(o.indirect->ptr[0].data);
sink(o.indirect->ptr[1].data); // $ ir MISSING: ast
sink(o.indirect->ptr[0].data); // $ SPURIOUS: ir
}

View File

@@ -108,11 +108,11 @@ void test_outer_with_ptr(Outer *pouter) {
taint_a_ptr(&pouter->a);
sink(outer.inner_nested.a); // $ ast,ir
sink(outer.inner_ptr->a); // $ ast MISSING: ir
sink(outer.inner_ptr->a); // $ ast,ir
sink(outer.a); // $ ast,ir
sink(pouter->inner_nested.a); // $ ast,ir
sink(pouter->inner_ptr->a); // $ast MISSING: ir
sink(pouter->inner_ptr->a); // $ast,ir
sink(pouter->a); // $ ast,ir
}
@@ -128,10 +128,10 @@ void test_outer_with_ref(Outer *pouter) {
taint_a_ref(pouter->a);
sink(outer.inner_nested.a); // $ ast,ir
sink(outer.inner_ptr->a); // $ ast MISSING: ir
sink(outer.inner_ptr->a); // $ ast,ir
sink(outer.a); // $ ast,ir
sink(pouter->inner_nested.a); // $ ast,ir
sink(pouter->inner_ptr->a); // $ ast MISSING: ir
sink(pouter->inner_ptr->a); // $ ast,ir
sink(pouter->a); // $ ast,ir
}

View File

@@ -8,7 +8,7 @@ struct A {
void pointer_without_allocation(const A& ra) {
*ra.p = user_input();
sink(*ra.p); // $ MISSING: ast,ir
sink(*ra.p); // $ ir MISSING: ast
}
void argument_source(void*);
@@ -17,7 +17,7 @@ void sink(void*);
void pointer_without_allocation_2() {
char *raw;
argument_source(raw);
sink(raw); // $ ast MISSING: ir
sink(raw); // $ ast,ir
}
A* makeA() {
@@ -27,14 +27,14 @@ A* makeA() {
void no_InitializeDynamicAllocation_instruction() {
A* pa = makeA();
pa->x = user_input();
sink(pa->x); // $ ast MISSING: ir
sink(pa->x); // $ ast,ir
}
void fresh_or_arg(A* arg, bool unknown) {
A* pa;
pa = unknown ? arg : new A;
pa->x = user_input();
sink(pa->x); // $ ast MISSING: ir
sink(pa->x); // $ ast,ir
}
struct LinkedList {
@@ -52,11 +52,11 @@ void too_many_indirections() {
LinkedList* ll = new LinkedList;
ll->next = new LinkedList;
ll->next->y = user_input();
sink(ll->next->y); // $ ast MISSING: ir
sink(ll->next->y); // $ ast,ir
}
void too_many_indirections_2(LinkedList* next) {
LinkedList* ll = new LinkedList(next);
ll->next->y = user_input();
sink(ll->next->y); // $ ast MISSING: ir
sink(ll->next->y); // $ ast,ir
}

View File

@@ -3,8 +3,8 @@ uniqueEnclosingCallable
| C.cpp:9:14:9:23 | new | Node should have one enclosing callable but has 0. |
| C.cpp:10:20:10:29 | 0 | Node should have one enclosing callable but has 0. |
| C.cpp:10:20:10:29 | new | Node should have one enclosing callable but has 0. |
| C.cpp:37:24:37:33 | 0 | Node should have one enclosing callable but has 0. |
| C.cpp:37:24:37:33 | new | Node should have one enclosing callable but has 0. |
| C.cpp:35:24:35:33 | 0 | Node should have one enclosing callable but has 0. |
| C.cpp:35:24:35:33 | new | Node should have one enclosing callable but has 0. |
uniqueType
uniqueNodeLocation
missingLocation

File diff suppressed because it is too large Load Diff

View File

@@ -1,152 +1,93 @@
| A.cpp:25:13:25:13 | c | AST only |
| A.cpp:27:28:27:28 | c | AST only |
| A.cpp:31:20:31:20 | c | AST only |
| A.cpp:40:5:40:6 | cc | AST only |
| A.cpp:41:5:41:6 | ct | AST only |
| A.cpp:42:10:42:12 | & ... | AST only |
| A.cpp:43:10:43:12 | & ... | AST only |
| A.cpp:48:20:48:20 | c | AST only |
| A.cpp:49:10:49:10 | b | AST only |
| A.cpp:49:13:49:13 | c | AST only |
| A.cpp:55:5:55:5 | b | AST only |
| A.cpp:56:10:56:10 | b | AST only |
| A.cpp:56:13:56:15 | call to get | AST only |
| A.cpp:57:28:57:30 | call to get | AST only |
| A.cpp:64:10:64:15 | this | AST only |
| A.cpp:64:17:64:18 | b1 | AST only |
| A.cpp:65:10:65:11 | b1 | AST only |
| A.cpp:65:14:65:14 | c | AST only |
| A.cpp:66:10:66:11 | b2 | AST only |
| A.cpp:66:14:66:14 | c | AST only |
| A.cpp:73:10:73:19 | this | AST only |
| A.cpp:73:21:73:22 | b1 | AST only |
| A.cpp:74:10:74:11 | b1 | AST only |
| A.cpp:74:14:74:14 | c | AST only |
| A.cpp:75:10:75:11 | b2 | AST only |
| A.cpp:75:14:75:14 | c | AST only |
| A.cpp:81:10:81:15 | this | AST only |
| A.cpp:81:17:81:18 | b1 | AST only |
| A.cpp:81:21:81:21 | c | AST only |
| A.cpp:82:12:82:12 | this | AST only |
| A.cpp:87:9:87:9 | this | AST only |
| A.cpp:90:7:90:8 | b2 | AST only |
| A.cpp:90:15:90:15 | c | AST only |
| A.cpp:31:14:31:21 | new | IR only |
| A.cpp:40:15:40:21 | 0 | IR only |
| A.cpp:41:15:41:21 | new | IR only |
| A.cpp:41:15:41:21 | new | IR only |
| A.cpp:47:12:47:18 | new | IR only |
| A.cpp:54:12:54:18 | new | IR only |
| A.cpp:55:12:55:19 | new | IR only |
| A.cpp:55:12:55:19 | new | IR only |
| A.cpp:57:11:57:24 | new | IR only |
| A.cpp:57:11:57:24 | new | IR only |
| A.cpp:57:17:57:23 | new | IR only |
| A.cpp:57:17:57:23 | new | IR only |
| A.cpp:62:13:62:19 | new | IR only |
| A.cpp:64:21:64:28 | new | IR only |
| A.cpp:64:21:64:28 | new | IR only |
| A.cpp:71:13:71:19 | new | IR only |
| A.cpp:73:25:73:32 | new | IR only |
| A.cpp:73:25:73:32 | new | IR only |
| A.cpp:89:15:89:21 | new | IR only |
| A.cpp:99:14:99:21 | new | IR only |
| A.cpp:100:9:100:9 | a | AST only |
| A.cpp:101:5:101:6 | this | AST only |
| A.cpp:101:8:101:9 | c1 | AST only |
| A.cpp:107:12:107:13 | c1 | AST only |
| A.cpp:107:16:107:16 | a | AST only |
| A.cpp:120:12:120:13 | c1 | AST only |
| A.cpp:120:16:120:16 | a | AST only |
| A.cpp:126:5:126:5 | b | AST only |
| A.cpp:131:5:131:6 | this | AST only |
| A.cpp:131:8:131:8 | b | AST only |
| A.cpp:132:10:132:10 | b | AST only |
| A.cpp:132:13:132:13 | c | AST only |
| A.cpp:116:12:116:19 | new | IR only |
| A.cpp:126:12:126:18 | new | IR only |
| A.cpp:126:12:126:18 | new | IR only |
| A.cpp:130:12:130:18 | new | IR only |
| A.cpp:142:10:142:10 | c | AST only |
| A.cpp:142:14:142:20 | new | IR only |
| A.cpp:143:13:143:13 | b | AST only |
| A.cpp:151:18:151:18 | b | AST only |
| A.cpp:151:21:151:21 | this | AST only |
| A.cpp:152:10:152:10 | d | AST only |
| A.cpp:152:13:152:13 | b | AST only |
| A.cpp:153:10:153:10 | d | AST only |
| A.cpp:153:13:153:13 | b | AST only |
| A.cpp:153:16:153:16 | c | AST only |
| A.cpp:154:10:154:10 | b | AST only |
| A.cpp:154:13:154:13 | c | AST only |
| A.cpp:160:29:160:29 | b | AST only |
| A.cpp:161:38:161:39 | l1 | AST only |
| A.cpp:162:38:162:39 | l2 | AST only |
| A.cpp:163:10:163:11 | l3 | AST only |
| A.cpp:163:14:163:17 | head | AST only |
| A.cpp:164:10:164:11 | l3 | AST only |
| A.cpp:164:14:164:17 | next | AST only |
| A.cpp:164:20:164:23 | head | AST only |
| A.cpp:165:10:165:11 | l3 | AST only |
| A.cpp:165:14:165:17 | next | AST only |
| A.cpp:165:20:165:23 | next | AST only |
| A.cpp:165:26:165:29 | head | AST only |
| A.cpp:166:10:166:11 | l3 | AST only |
| A.cpp:166:14:166:17 | next | AST only |
| A.cpp:166:20:166:23 | next | AST only |
| A.cpp:166:26:166:29 | next | AST only |
| A.cpp:166:32:166:35 | head | AST only |
| A.cpp:169:12:169:12 | l | AST only |
| A.cpp:169:15:169:18 | head | AST only |
| A.cpp:143:25:143:31 | new | IR only |
| A.cpp:150:12:150:18 | new | IR only |
| A.cpp:151:12:151:24 | new | IR only |
| A.cpp:159:12:159:18 | new | IR only |
| A.cpp:160:18:160:60 | new | IR only |
| A.cpp:160:32:160:59 | new | IR only |
| A.cpp:160:32:160:59 | new | IR only |
| A.cpp:160:43:160:49 | 0 | IR only |
| A.cpp:160:52:160:58 | 0 | IR only |
| A.cpp:161:18:161:40 | new | IR only |
| A.cpp:161:29:161:35 | 0 | IR only |
| A.cpp:162:18:162:40 | new | IR only |
| A.cpp:162:29:162:35 | 0 | IR only |
| A.cpp:183:7:183:10 | head | AST only |
| A.cpp:184:13:184:16 | next | AST only |
| B.cpp:7:25:7:25 | e | AST only |
| B.cpp:8:25:8:26 | b1 | AST only |
| B.cpp:9:10:9:11 | b2 | AST only |
| B.cpp:9:14:9:17 | box1 | AST only |
| B.cpp:9:20:9:24 | elem1 | AST only |
| B.cpp:10:10:10:11 | b2 | AST only |
| B.cpp:10:14:10:17 | box1 | AST only |
| B.cpp:10:20:10:24 | elem2 | AST only |
| B.cpp:16:37:16:37 | e | AST only |
| B.cpp:17:25:17:26 | b1 | AST only |
| B.cpp:18:10:18:11 | b2 | AST only |
| B.cpp:18:14:18:17 | box1 | AST only |
| B.cpp:18:20:18:24 | elem1 | AST only |
| B.cpp:19:10:19:11 | b2 | AST only |
| B.cpp:19:14:19:17 | box1 | AST only |
| B.cpp:19:20:19:24 | elem2 | AST only |
| B.cpp:7:16:7:35 | new | IR only |
| B.cpp:7:28:7:34 | 0 | IR only |
| B.cpp:8:16:8:27 | new | IR only |
| B.cpp:16:16:16:38 | new | IR only |
| B.cpp:16:28:16:34 | 0 | IR only |
| B.cpp:17:16:17:27 | new | IR only |
| B.cpp:35:13:35:17 | elem1 | AST only |
| B.cpp:36:13:36:17 | elem2 | AST only |
| B.cpp:46:13:46:16 | box1 | AST only |
| C.cpp:19:5:19:5 | c | AST only |
| C.cpp:18:12:18:18 | new | IR only |
| C.cpp:24:11:24:12 | s3 | AST only |
| C.cpp:30:10:30:11 | s2 | IR only |
| C.cpp:30:10:30:11 | this | IR only |
| C.cpp:32:10:32:11 | s4 | IR only |
| D.cpp:9:21:9:24 | elem | AST only |
| D.cpp:11:29:11:32 | elem | AST only |
| D.cpp:16:21:16:23 | box | AST only |
| D.cpp:18:29:18:31 | box | AST only |
| D.cpp:22:10:22:11 | b2 | AST only |
| D.cpp:22:14:22:20 | call to getBox1 | AST only |
| D.cpp:22:25:22:31 | call to getElem | AST only |
| D.cpp:30:5:30:5 | b | AST only |
| D.cpp:30:8:30:10 | box | AST only |
| D.cpp:29:15:29:41 | new | IR only |
| D.cpp:29:24:29:40 | new | IR only |
| D.cpp:29:24:29:40 | new | IR only |
| D.cpp:29:33:29:39 | 0 | IR only |
| D.cpp:30:13:30:16 | elem | AST only |
| D.cpp:31:14:31:14 | b | AST only |
| D.cpp:37:5:37:5 | b | AST only |
| D.cpp:37:8:37:10 | box | AST only |
| D.cpp:37:21:37:21 | e | AST only |
| D.cpp:38:14:38:14 | b | AST only |
| D.cpp:44:5:44:5 | b | AST only |
| D.cpp:44:8:44:14 | call to getBox1 | AST only |
| D.cpp:36:15:36:41 | new | IR only |
| D.cpp:36:24:36:40 | new | IR only |
| D.cpp:36:24:36:40 | new | IR only |
| D.cpp:36:33:36:39 | 0 | IR only |
| D.cpp:43:15:43:41 | new | IR only |
| D.cpp:43:24:43:40 | new | IR only |
| D.cpp:43:24:43:40 | new | IR only |
| D.cpp:43:33:43:39 | 0 | IR only |
| D.cpp:44:19:44:22 | elem | AST only |
| D.cpp:45:14:45:14 | b | AST only |
| D.cpp:51:5:51:5 | b | AST only |
| D.cpp:51:8:51:14 | call to getBox1 | AST only |
| D.cpp:51:27:51:27 | e | AST only |
| D.cpp:52:14:52:14 | b | AST only |
| D.cpp:50:15:50:41 | new | IR only |
| D.cpp:50:24:50:40 | new | IR only |
| D.cpp:50:24:50:40 | new | IR only |
| D.cpp:50:33:50:39 | 0 | IR only |
| D.cpp:57:5:57:12 | boxfield | AST only |
| D.cpp:58:5:58:12 | boxfield | AST only |
| D.cpp:58:5:58:12 | this | AST only |
| D.cpp:58:15:58:17 | box | AST only |
| D.cpp:57:16:57:42 | new | IR only |
| D.cpp:57:25:57:41 | new | IR only |
| D.cpp:57:25:57:41 | new | IR only |
| D.cpp:57:34:57:40 | 0 | IR only |
| D.cpp:58:20:58:23 | elem | AST only |
| D.cpp:59:5:59:7 | this | AST only |
| D.cpp:64:10:64:17 | boxfield | AST only |
| D.cpp:64:10:64:17 | this | AST only |
| D.cpp:64:20:64:22 | box | AST only |
| D.cpp:64:25:64:28 | elem | AST only |
| E.cpp:21:10:21:10 | p | AST only |
| E.cpp:21:13:21:16 | data | AST only |
| E.cpp:21:18:21:23 | buffer | AST only |
| E.cpp:28:21:28:23 | raw | AST only |
| E.cpp:29:21:29:21 | b | AST only |
| E.cpp:29:24:29:29 | buffer | AST only |
| E.cpp:30:21:30:21 | p | AST only |
| E.cpp:30:23:30:26 | data | AST only |
| E.cpp:30:28:30:33 | buffer | AST only |
| E.cpp:31:10:31:12 | raw | AST only |
| E.cpp:32:10:32:10 | b | AST only |
| E.cpp:32:13:32:18 | buffer | AST only |
| E.cpp:33:18:33:19 | & ... | AST only |
| aliasing.cpp:9:6:9:7 | m1 | AST only |
| aliasing.cpp:13:5:13:6 | m1 | AST only |
| aliasing.cpp:17:5:17:6 | m1 | AST only |
| aliasing.cpp:25:17:25:19 | & ... | AST only |
| aliasing.cpp:26:19:26:20 | s2 | AST only |
| aliasing.cpp:37:8:37:9 | m1 | AST only |
| aliasing.cpp:42:6:42:7 | m1 | AST only |
| aliasing.cpp:49:9:49:10 | m1 | AST only |
@@ -155,291 +96,52 @@
| aliasing.cpp:72:5:72:6 | m1 | AST only |
| aliasing.cpp:79:6:79:7 | m1 | AST only |
| aliasing.cpp:86:5:86:6 | m1 | AST only |
| aliasing.cpp:92:3:92:3 | w | AST only |
| aliasing.cpp:92:7:92:8 | m1 | AST only |
| aliasing.cpp:98:5:98:6 | m1 | AST only |
| aliasing.cpp:106:3:106:5 | * ... | AST only |
| aliasing.cpp:111:15:111:19 | & ... | AST only |
| aliasing.cpp:121:15:121:16 | xs | AST only |
| aliasing.cpp:126:15:126:20 | ... - ... | AST only |
| aliasing.cpp:131:15:131:16 | xs | AST only |
| aliasing.cpp:136:15:136:17 | + ... | AST only |
| aliasing.cpp:141:15:141:15 | s | AST only |
| aliasing.cpp:141:17:141:20 | data | AST only |
| aliasing.cpp:147:15:147:22 | & ... | AST only |
| aliasing.cpp:158:15:158:15 | s | AST only |
| aliasing.cpp:158:17:158:20 | data | AST only |
| aliasing.cpp:164:15:164:15 | s | AST only |
| aliasing.cpp:164:17:164:20 | data | AST only |
| aliasing.cpp:175:15:175:22 | & ... | AST only |
| aliasing.cpp:175:16:175:17 | s2 | AST only |
| aliasing.cpp:181:15:181:22 | & ... | AST only |
| aliasing.cpp:181:16:181:17 | s2 | AST only |
| aliasing.cpp:187:15:187:22 | & ... | AST only |
| aliasing.cpp:187:16:187:17 | s2 | AST only |
| aliasing.cpp:194:15:194:22 | & ... | AST only |
| aliasing.cpp:194:16:194:17 | s2 | AST only |
| aliasing.cpp:200:15:200:24 | & ... | AST only |
| aliasing.cpp:200:16:200:18 | ps2 | AST only |
| aliasing.cpp:205:15:205:24 | & ... | AST only |
| aliasing.cpp:205:16:205:18 | ps2 | AST only |
| arrays.cpp:6:3:6:8 | access to array | AST only |
| arrays.cpp:6:3:6:23 | arr | IR only |
| arrays.cpp:7:8:7:13 | access to array | IR only |
| arrays.cpp:8:8:8:13 | access to array | IR only |
| arrays.cpp:9:8:9:11 | * ... | IR only |
| arrays.cpp:10:8:10:15 | * ... | IR only |
| arrays.cpp:15:3:15:10 | * ... | AST only |
| arrays.cpp:36:3:36:3 | o | AST only |
| arrays.cpp:36:5:36:10 | nested | AST only |
| arrays.cpp:16:8:16:13 | access to array | IR only |
| arrays.cpp:17:8:17:13 | access to array | IR only |
| arrays.cpp:36:19:36:22 | data | AST only |
| arrays.cpp:37:8:37:8 | o | AST only |
| arrays.cpp:37:8:37:22 | access to array | AST only |
| arrays.cpp:37:10:37:15 | nested | AST only |
| arrays.cpp:37:24:37:27 | data | AST only |
| arrays.cpp:38:8:38:8 | o | AST only |
| arrays.cpp:38:8:38:22 | access to array | AST only |
| arrays.cpp:38:10:38:15 | nested | AST only |
| arrays.cpp:38:24:38:27 | data | AST only |
| arrays.cpp:42:3:42:3 | o | AST only |
| arrays.cpp:42:3:42:20 | access to array | AST only |
| arrays.cpp:42:5:42:12 | indirect | AST only |
| arrays.cpp:42:22:42:25 | data | AST only |
| arrays.cpp:43:8:43:8 | o | AST only |
| arrays.cpp:43:8:43:25 | access to array | AST only |
| arrays.cpp:43:10:43:17 | indirect | AST only |
| arrays.cpp:43:27:43:30 | data | AST only |
| arrays.cpp:44:8:44:8 | o | AST only |
| arrays.cpp:44:8:44:25 | access to array | AST only |
| arrays.cpp:44:10:44:17 | indirect | AST only |
| arrays.cpp:44:27:44:30 | data | AST only |
| arrays.cpp:48:3:48:3 | o | AST only |
| arrays.cpp:48:3:48:20 | access to array | AST only |
| arrays.cpp:48:5:48:12 | indirect | AST only |
| arrays.cpp:48:22:48:25 | data | AST only |
| arrays.cpp:49:8:49:8 | o | AST only |
| arrays.cpp:49:8:49:25 | access to array | AST only |
| arrays.cpp:49:10:49:17 | indirect | AST only |
| arrays.cpp:49:27:49:30 | data | AST only |
| arrays.cpp:50:8:50:8 | o | AST only |
| arrays.cpp:50:8:50:25 | access to array | AST only |
| arrays.cpp:50:10:50:17 | indirect | AST only |
| arrays.cpp:50:27:50:30 | data | AST only |
| by_reference.cpp:12:8:12:8 | a | AST only |
| by_reference.cpp:16:11:16:11 | a | AST only |
| by_reference.cpp:20:5:20:8 | this | AST only |
| by_reference.cpp:20:23:20:27 | value | AST only |
| by_reference.cpp:24:19:24:22 | this | AST only |
| by_reference.cpp:24:25:24:29 | value | AST only |
| by_reference.cpp:40:12:40:15 | this | AST only |
| by_reference.cpp:50:3:50:3 | s | AST only |
| by_reference.cpp:50:17:50:26 | call to user_input | AST only |
| by_reference.cpp:51:8:51:8 | s | AST only |
| by_reference.cpp:51:10:51:20 | call to getDirectly | AST only |
| by_reference.cpp:56:3:56:3 | s | AST only |
| by_reference.cpp:56:19:56:28 | call to user_input | AST only |
| by_reference.cpp:57:8:57:8 | s | AST only |
| by_reference.cpp:57:10:57:22 | call to getIndirectly | AST only |
| by_reference.cpp:62:3:62:3 | s | AST only |
| by_reference.cpp:62:25:62:34 | call to user_input | AST only |
| by_reference.cpp:63:8:63:8 | s | AST only |
| by_reference.cpp:63:10:63:28 | call to getThroughNonMember | AST only |
| by_reference.cpp:68:17:68:18 | & ... | AST only |
| by_reference.cpp:68:21:68:30 | call to user_input | AST only |
| by_reference.cpp:69:8:69:20 | call to nonMemberGetA | AST only |
| by_reference.cpp:84:10:84:10 | a | AST only |
| by_reference.cpp:88:9:88:9 | a | AST only |
| by_reference.cpp:92:3:92:5 | * ... | AST only |
| by_reference.cpp:96:3:96:4 | pa | AST only |
| by_reference.cpp:102:21:102:39 | & ... | AST only |
| by_reference.cpp:103:21:103:25 | outer | AST only |
| by_reference.cpp:103:27:103:35 | inner_ptr | AST only |
| by_reference.cpp:104:15:104:22 | & ... | AST only |
| by_reference.cpp:106:21:106:41 | & ... | AST only |
| by_reference.cpp:107:21:107:26 | pouter | AST only |
| by_reference.cpp:107:29:107:37 | inner_ptr | AST only |
| by_reference.cpp:108:15:108:24 | & ... | AST only |
| by_reference.cpp:110:8:110:12 | outer | AST only |
| by_reference.cpp:110:14:110:25 | inner_nested | AST only |
| by_reference.cpp:110:27:110:27 | a | AST only |
| by_reference.cpp:111:8:111:12 | outer | AST only |
| by_reference.cpp:111:14:111:22 | inner_ptr | AST only |
| by_reference.cpp:111:25:111:25 | a | AST only |
| by_reference.cpp:112:8:112:12 | outer | AST only |
| by_reference.cpp:112:14:112:14 | a | AST only |
| by_reference.cpp:114:8:114:13 | pouter | AST only |
| by_reference.cpp:114:16:114:27 | inner_nested | AST only |
| by_reference.cpp:114:29:114:29 | a | AST only |
| by_reference.cpp:115:8:115:13 | pouter | AST only |
| by_reference.cpp:115:16:115:24 | inner_ptr | AST only |
| by_reference.cpp:115:27:115:27 | a | AST only |
| by_reference.cpp:116:8:116:13 | pouter | AST only |
| by_reference.cpp:116:16:116:16 | a | AST only |
| by_reference.cpp:122:27:122:38 | inner_nested | AST only |
| by_reference.cpp:123:21:123:36 | * ... | AST only |
| by_reference.cpp:123:22:123:26 | outer | AST only |
| by_reference.cpp:124:21:124:21 | a | AST only |
| by_reference.cpp:126:29:126:40 | inner_nested | AST only |
| by_reference.cpp:127:21:127:38 | * ... | AST only |
| by_reference.cpp:127:22:127:27 | pouter | AST only |
| by_reference.cpp:128:23:128:23 | a | AST only |
| by_reference.cpp:130:8:130:12 | outer | AST only |
| by_reference.cpp:130:14:130:25 | inner_nested | AST only |
| by_reference.cpp:130:27:130:27 | a | AST only |
| by_reference.cpp:131:8:131:12 | outer | AST only |
| by_reference.cpp:131:14:131:22 | inner_ptr | AST only |
| by_reference.cpp:131:25:131:25 | a | AST only |
| by_reference.cpp:132:8:132:12 | outer | AST only |
| by_reference.cpp:132:14:132:14 | a | AST only |
| by_reference.cpp:134:8:134:13 | pouter | AST only |
| by_reference.cpp:134:16:134:27 | inner_nested | AST only |
| by_reference.cpp:134:29:134:29 | a | AST only |
| by_reference.cpp:135:8:135:13 | pouter | AST only |
| by_reference.cpp:135:16:135:24 | inner_ptr | AST only |
| by_reference.cpp:135:27:135:27 | a | AST only |
| by_reference.cpp:136:8:136:13 | pouter | AST only |
| by_reference.cpp:136:16:136:16 | a | AST only |
| complex.cpp:11:22:11:23 | a_ | AST only |
| complex.cpp:12:22:12:23 | b_ | AST only |
| complex.cpp:42:8:42:8 | b | AST only |
| complex.cpp:42:16:42:16 | f | AST only |
| complex.cpp:43:8:43:8 | b | AST only |
| complex.cpp:43:16:43:16 | f | AST only |
| complex.cpp:53:3:53:4 | b1 | AST only |
| complex.cpp:53:12:53:12 | f | AST only |
| complex.cpp:54:3:54:4 | b2 | AST only |
| complex.cpp:54:12:54:12 | f | AST only |
| complex.cpp:55:3:55:4 | b3 | AST only |
| complex.cpp:55:12:55:12 | f | AST only |
| complex.cpp:56:3:56:4 | b3 | AST only |
| complex.cpp:56:12:56:12 | f | AST only |
| complex.cpp:59:7:59:8 | b1 | AST only |
| complex.cpp:62:7:62:8 | b2 | AST only |
| complex.cpp:65:7:65:8 | b3 | AST only |
| complex.cpp:68:7:68:8 | b4 | AST only |
| conflated.cpp:10:3:10:7 | * ... | AST only |
| conflated.cpp:10:4:10:5 | ra | AST only |
| conflated.cpp:19:19:19:21 | raw | AST only |
| conflated.cpp:20:8:20:10 | raw | AST only |
| conflated.cpp:29:3:29:4 | pa | AST only |
| conflated.cpp:29:7:29:7 | x | AST only |
| conflated.cpp:36:3:36:4 | pa | AST only |
| conflated.cpp:36:7:36:7 | x | AST only |
| conflated.cpp:53:7:53:10 | next | AST only |
| conflated.cpp:54:3:54:4 | ll | AST only |
| conflated.cpp:54:7:54:10 | next | AST only |
| conflated.cpp:54:13:54:13 | y | AST only |
| conflated.cpp:59:35:59:38 | next | AST only |
| conflated.cpp:60:3:60:4 | ll | AST only |
| conflated.cpp:60:7:60:10 | next | AST only |
| conflated.cpp:59:20:59:39 | new | IR only |
| conflated.cpp:60:13:60:13 | y | AST only |
| constructors.cpp:20:24:20:25 | a_ | AST only |
| constructors.cpp:21:24:21:25 | b_ | AST only |
| constructors.cpp:28:10:28:10 | f | AST only |
| constructors.cpp:29:10:29:10 | f | AST only |
| constructors.cpp:40:9:40:9 | f | AST only |
| constructors.cpp:43:9:43:9 | g | AST only |
| constructors.cpp:46:9:46:9 | h | AST only |
| constructors.cpp:49:9:49:9 | i | AST only |
| qualifiers.cpp:9:36:9:36 | a | AST only |
| qualifiers.cpp:12:56:12:56 | a | AST only |
| qualifiers.cpp:13:57:13:57 | a | AST only |
| qualifiers.cpp:22:5:22:9 | outer | AST only |
| qualifiers.cpp:22:11:22:18 | call to getInner | AST only |
| qualifiers.cpp:22:23:22:23 | a | AST only |
| qualifiers.cpp:23:10:23:14 | outer | AST only |
| qualifiers.cpp:23:16:23:20 | inner | AST only |
| qualifiers.cpp:23:23:23:23 | a | AST only |
| qualifiers.cpp:27:5:27:9 | outer | AST only |
| qualifiers.cpp:27:11:27:18 | call to getInner | AST only |
| qualifiers.cpp:27:28:27:37 | call to user_input | AST only |
| qualifiers.cpp:28:10:28:14 | outer | AST only |
| qualifiers.cpp:28:16:28:20 | inner | AST only |
| qualifiers.cpp:28:23:28:23 | a | AST only |
| qualifiers.cpp:32:17:32:21 | outer | AST only |
| qualifiers.cpp:32:23:32:30 | call to getInner | AST only |
| qualifiers.cpp:32:35:32:44 | call to user_input | AST only |
| qualifiers.cpp:33:10:33:14 | outer | AST only |
| qualifiers.cpp:33:16:33:20 | inner | AST only |
| qualifiers.cpp:33:23:33:23 | a | AST only |
| qualifiers.cpp:37:19:37:35 | * ... | AST only |
| qualifiers.cpp:37:20:37:24 | outer | AST only |
| qualifiers.cpp:37:38:37:47 | call to user_input | AST only |
| qualifiers.cpp:38:10:38:14 | outer | AST only |
| qualifiers.cpp:38:16:38:20 | inner | AST only |
| qualifiers.cpp:38:23:38:23 | a | AST only |
| qualifiers.cpp:42:6:42:22 | * ... | AST only |
| qualifiers.cpp:42:7:42:11 | outer | AST only |
| qualifiers.cpp:42:25:42:25 | a | AST only |
| qualifiers.cpp:43:10:43:14 | outer | AST only |
| qualifiers.cpp:43:16:43:20 | inner | AST only |
| qualifiers.cpp:43:23:43:23 | a | AST only |
| qualifiers.cpp:47:6:47:11 | & ... | AST only |
| qualifiers.cpp:47:15:47:22 | call to getInner | AST only |
| qualifiers.cpp:47:27:47:27 | a | AST only |
| qualifiers.cpp:48:10:48:14 | outer | AST only |
| qualifiers.cpp:48:16:48:20 | inner | AST only |
| qualifiers.cpp:48:23:48:23 | a | AST only |
| realistic.cpp:26:5:26:10 | offset | AST only |
| realistic.cpp:42:20:42:20 | o | AST only |
| realistic.cpp:49:9:49:11 | foo | AST only |
| realistic.cpp:49:20:49:22 | baz | AST only |
| realistic.cpp:53:9:53:11 | foo | AST only |
| realistic.cpp:53:9:53:18 | access to array | AST only |
| realistic.cpp:53:20:53:22 | baz | AST only |
| realistic.cpp:53:25:53:33 | userInput | AST only |
| realistic.cpp:53:35:53:43 | bufferLen | AST only |
| realistic.cpp:54:16:54:18 | foo | AST only |
| realistic.cpp:54:16:54:25 | access to array | AST only |
| realistic.cpp:54:27:54:29 | baz | AST only |
| realistic.cpp:54:32:54:40 | userInput | AST only |
| realistic.cpp:54:42:54:47 | buffer | AST only |
| realistic.cpp:60:16:60:18 | dst | AST only |
| realistic.cpp:61:21:61:23 | foo | AST only |
| realistic.cpp:61:21:61:30 | access to array | AST only |
| realistic.cpp:61:32:61:34 | baz | AST only |
| realistic.cpp:61:37:61:45 | userInput | AST only |
| realistic.cpp:61:47:61:55 | bufferLen | AST only |
| realistic.cpp:65:21:65:23 | foo | AST only |
| realistic.cpp:65:21:65:30 | access to array | AST only |
| realistic.cpp:65:32:65:34 | baz | AST only |
| realistic.cpp:65:37:65:45 | userInput | AST only |
| realistic.cpp:65:47:65:52 | buffer | AST only |
| realistic.cpp:66:21:66:23 | dst | AST only |
| simple.cpp:20:24:20:25 | a_ | AST only |
| simple.cpp:21:24:21:25 | b_ | AST only |
| simple.cpp:28:10:28:10 | f | AST only |
| simple.cpp:29:10:29:10 | f | AST only |
| simple.cpp:39:5:39:5 | f | AST only |
| simple.cpp:40:5:40:5 | g | AST only |
| simple.cpp:41:5:41:5 | h | AST only |
| simple.cpp:42:5:42:5 | h | AST only |
| simple.cpp:45:9:45:9 | f | AST only |
| simple.cpp:48:9:48:9 | g | AST only |
| simple.cpp:51:9:51:9 | h | AST only |
| simple.cpp:54:9:54:9 | i | AST only |
| simple.cpp:65:7:65:7 | i | AST only |
| simple.cpp:83:9:83:10 | this | AST only |
| simple.cpp:83:12:83:13 | f1 | AST only |
| simple.cpp:84:14:84:20 | this | AST only |
| simple.cpp:92:7:92:7 | i | AST only |
| struct_init.c:15:8:15:9 | ab | AST only |
| struct_init.c:15:12:15:12 | a | AST only |
| struct_init.c:16:8:16:9 | ab | AST only |
| struct_init.c:16:12:16:12 | b | AST only |
| struct_init.c:22:8:22:9 | ab | AST only |
| struct_init.c:22:11:22:11 | a | AST only |
| struct_init.c:23:8:23:9 | ab | AST only |
| struct_init.c:23:11:23:11 | b | AST only |
| struct_init.c:24:10:24:12 | & ... | AST only |
| struct_init.c:31:8:31:12 | outer | AST only |
| struct_init.c:31:14:31:21 | nestedAB | AST only |
| struct_init.c:31:23:31:23 | a | AST only |
| struct_init.c:32:8:32:12 | outer | AST only |
| struct_init.c:32:14:32:21 | nestedAB | AST only |
| struct_init.c:32:23:32:23 | b | AST only |
| struct_init.c:33:8:33:12 | outer | AST only |
| struct_init.c:33:14:33:22 | pointerAB | AST only |
| struct_init.c:33:25:33:25 | a | AST only |
| struct_init.c:34:8:34:12 | outer | AST only |
| struct_init.c:34:14:34:22 | pointerAB | AST only |
| struct_init.c:34:25:34:25 | b | AST only |
| struct_init.c:36:10:36:24 | & ... | AST only |
| struct_init.c:46:10:46:14 | outer | AST only |
| struct_init.c:46:16:46:24 | pointerAB | AST only |

View File

@@ -1,22 +1,208 @@
| A.cpp:25:7:25:10 | this |
| A.cpp:27:22:27:25 | this |
| A.cpp:31:14:31:21 | new |
| A.cpp:31:20:31:20 | c |
| A.cpp:40:5:40:6 | cc |
| A.cpp:40:15:40:21 | 0 |
| A.cpp:41:5:41:6 | ct |
| A.cpp:41:15:41:21 | new |
| A.cpp:42:10:42:12 | & ... |
| A.cpp:43:10:43:12 | & ... |
| A.cpp:47:12:47:18 | new |
| A.cpp:48:20:48:20 | c |
| A.cpp:49:10:49:10 | b |
| A.cpp:49:13:49:13 | c |
| A.cpp:54:12:54:18 | new |
| A.cpp:55:5:55:5 | b |
| A.cpp:55:12:55:19 | new |
| A.cpp:56:10:56:10 | b |
| A.cpp:56:13:56:15 | call to get |
| A.cpp:57:11:57:24 | new |
| A.cpp:57:17:57:23 | new |
| A.cpp:57:28:57:30 | call to get |
| A.cpp:62:13:62:19 | new |
| A.cpp:64:10:64:15 | this |
| A.cpp:64:17:64:18 | b1 |
| A.cpp:64:21:64:28 | new |
| A.cpp:65:10:65:11 | b1 |
| A.cpp:65:14:65:14 | c |
| A.cpp:66:10:66:11 | b2 |
| A.cpp:66:14:66:14 | c |
| A.cpp:71:13:71:19 | new |
| A.cpp:73:10:73:19 | this |
| A.cpp:73:21:73:22 | b1 |
| A.cpp:73:25:73:32 | new |
| A.cpp:74:10:74:11 | b1 |
| A.cpp:74:14:74:14 | c |
| A.cpp:75:10:75:11 | b2 |
| A.cpp:75:14:75:14 | c |
| A.cpp:81:10:81:15 | this |
| A.cpp:81:17:81:18 | b1 |
| A.cpp:81:21:81:21 | c |
| A.cpp:82:12:82:12 | this |
| A.cpp:87:9:87:9 | this |
| A.cpp:89:15:89:21 | new |
| A.cpp:90:7:90:8 | b2 |
| A.cpp:90:15:90:15 | c |
| A.cpp:99:14:99:21 | new |
| A.cpp:100:5:100:6 | c1 |
| A.cpp:101:5:101:6 | this |
| A.cpp:101:8:101:9 | c1 |
| A.cpp:107:12:107:13 | c1 |
| A.cpp:107:16:107:16 | a |
| A.cpp:116:12:116:19 | new |
| A.cpp:120:12:120:13 | c1 |
| A.cpp:120:16:120:16 | a |
| A.cpp:126:5:126:5 | b |
| A.cpp:126:12:126:18 | new |
| A.cpp:130:12:130:18 | new |
| A.cpp:131:5:131:6 | this |
| A.cpp:131:8:131:8 | b |
| A.cpp:132:10:132:10 | b |
| A.cpp:132:13:132:13 | c |
| A.cpp:142:7:142:7 | b |
| A.cpp:142:14:142:20 | new |
| A.cpp:143:7:143:10 | this |
| A.cpp:143:25:143:31 | new |
| A.cpp:150:12:150:18 | new |
| A.cpp:151:12:151:24 | new |
| A.cpp:151:18:151:18 | b |
| A.cpp:151:21:151:21 | this |
| A.cpp:152:10:152:10 | d |
| A.cpp:152:13:152:13 | b |
| A.cpp:153:10:153:10 | d |
| A.cpp:153:13:153:13 | b |
| A.cpp:153:16:153:16 | c |
| A.cpp:154:10:154:10 | b |
| A.cpp:154:13:154:13 | c |
| A.cpp:159:12:159:18 | new |
| A.cpp:160:18:160:60 | new |
| A.cpp:160:29:160:29 | b |
| A.cpp:160:32:160:59 | new |
| A.cpp:160:43:160:49 | 0 |
| A.cpp:160:52:160:58 | 0 |
| A.cpp:161:18:161:40 | new |
| A.cpp:161:29:161:35 | 0 |
| A.cpp:161:38:161:39 | l1 |
| A.cpp:162:18:162:40 | new |
| A.cpp:162:29:162:35 | 0 |
| A.cpp:162:38:162:39 | l2 |
| A.cpp:163:10:163:11 | l3 |
| A.cpp:163:14:163:17 | head |
| A.cpp:164:10:164:11 | l3 |
| A.cpp:164:14:164:17 | next |
| A.cpp:164:20:164:23 | head |
| A.cpp:165:10:165:11 | l3 |
| A.cpp:165:14:165:17 | next |
| A.cpp:165:20:165:23 | next |
| A.cpp:165:26:165:29 | head |
| A.cpp:166:10:166:11 | l3 |
| A.cpp:166:14:166:17 | next |
| A.cpp:166:20:166:23 | next |
| A.cpp:166:26:166:29 | next |
| A.cpp:166:32:166:35 | head |
| A.cpp:169:12:169:12 | l |
| A.cpp:169:15:169:18 | head |
| A.cpp:183:7:183:10 | this |
| A.cpp:184:7:184:10 | this |
| B.cpp:7:16:7:35 | new |
| B.cpp:7:25:7:25 | e |
| B.cpp:7:28:7:34 | 0 |
| B.cpp:8:16:8:27 | new |
| B.cpp:8:25:8:26 | b1 |
| B.cpp:9:10:9:11 | b2 |
| B.cpp:9:14:9:17 | box1 |
| B.cpp:9:20:9:24 | elem1 |
| B.cpp:10:10:10:11 | b2 |
| B.cpp:10:14:10:17 | box1 |
| B.cpp:10:20:10:24 | elem2 |
| B.cpp:16:16:16:38 | new |
| B.cpp:16:28:16:34 | 0 |
| B.cpp:16:37:16:37 | e |
| B.cpp:17:16:17:27 | new |
| B.cpp:17:25:17:26 | b1 |
| B.cpp:18:10:18:11 | b2 |
| B.cpp:18:14:18:17 | box1 |
| B.cpp:18:20:18:24 | elem1 |
| B.cpp:19:10:19:11 | b2 |
| B.cpp:19:14:19:17 | box1 |
| B.cpp:19:20:19:24 | elem2 |
| B.cpp:35:7:35:10 | this |
| B.cpp:36:7:36:10 | this |
| B.cpp:46:7:46:10 | this |
| C.cpp:18:12:18:18 | new |
| C.cpp:19:5:19:5 | c |
| C.cpp:24:5:24:8 | this |
| C.cpp:29:10:29:11 | s1 |
| C.cpp:29:10:29:11 | this |
| C.cpp:30:10:30:11 | s2 |
| C.cpp:30:10:30:11 | this |
| C.cpp:31:10:31:11 | s3 |
| C.cpp:31:10:31:11 | this |
| C.cpp:32:10:32:11 | s4 |
| D.cpp:9:21:9:24 | this |
| D.cpp:11:29:11:32 | this |
| D.cpp:16:21:16:23 | this |
| D.cpp:18:29:18:31 | this |
| D.cpp:22:10:22:11 | b2 |
| D.cpp:22:14:22:20 | call to getBox1 |
| D.cpp:22:25:22:31 | call to getElem |
| D.cpp:29:15:29:41 | new |
| D.cpp:29:24:29:40 | new |
| D.cpp:29:33:29:39 | 0 |
| D.cpp:30:5:30:5 | b |
| D.cpp:30:8:30:10 | box |
| D.cpp:31:14:31:14 | b |
| D.cpp:36:15:36:41 | new |
| D.cpp:36:24:36:40 | new |
| D.cpp:36:33:36:39 | 0 |
| D.cpp:37:5:37:5 | b |
| D.cpp:37:8:37:10 | box |
| D.cpp:37:21:37:21 | e |
| D.cpp:38:14:38:14 | b |
| D.cpp:43:15:43:41 | new |
| D.cpp:43:24:43:40 | new |
| D.cpp:43:33:43:39 | 0 |
| D.cpp:44:5:44:5 | b |
| D.cpp:44:8:44:14 | call to getBox1 |
| D.cpp:45:14:45:14 | b |
| D.cpp:50:15:50:41 | new |
| D.cpp:50:24:50:40 | new |
| D.cpp:50:33:50:39 | 0 |
| D.cpp:51:5:51:5 | b |
| D.cpp:51:8:51:14 | call to getBox1 |
| D.cpp:51:27:51:27 | e |
| D.cpp:52:14:52:14 | b |
| D.cpp:57:5:57:12 | this |
| D.cpp:57:16:57:42 | new |
| D.cpp:57:25:57:41 | new |
| D.cpp:57:34:57:40 | 0 |
| D.cpp:58:5:58:12 | boxfield |
| D.cpp:58:5:58:12 | this |
| D.cpp:58:15:58:17 | box |
| D.cpp:59:5:59:7 | this |
| D.cpp:64:10:64:17 | boxfield |
| D.cpp:64:10:64:17 | this |
| D.cpp:64:20:64:22 | box |
| D.cpp:64:25:64:28 | elem |
| E.cpp:21:10:21:10 | p |
| E.cpp:21:13:21:16 | data |
| E.cpp:21:18:21:23 | buffer |
| E.cpp:28:21:28:23 | raw |
| E.cpp:29:21:29:21 | b |
| E.cpp:29:24:29:29 | buffer |
| E.cpp:30:21:30:21 | p |
| E.cpp:30:23:30:26 | data |
| E.cpp:30:28:30:33 | buffer |
| E.cpp:31:10:31:12 | raw |
| E.cpp:32:10:32:10 | b |
| E.cpp:32:13:32:18 | buffer |
| E.cpp:33:18:33:19 | & ... |
| aliasing.cpp:9:3:9:3 | s |
| aliasing.cpp:13:3:13:3 | s |
| aliasing.cpp:17:3:17:3 | s |
| aliasing.cpp:25:17:25:19 | & ... |
| aliasing.cpp:26:19:26:20 | s2 |
| aliasing.cpp:37:3:37:6 | ref1 |
| aliasing.cpp:42:3:42:4 | s2 |
| aliasing.cpp:49:3:49:7 | copy1 |
@@ -25,48 +211,299 @@
| aliasing.cpp:72:3:72:3 | s |
| aliasing.cpp:79:3:79:3 | s |
| aliasing.cpp:86:3:86:3 | s |
| aliasing.cpp:92:3:92:3 | w |
| aliasing.cpp:92:5:92:5 | s |
| aliasing.cpp:98:3:98:3 | s |
| aliasing.cpp:111:15:111:19 | & ... |
| aliasing.cpp:111:16:111:16 | s |
| aliasing.cpp:121:15:121:16 | xs |
| aliasing.cpp:126:15:126:20 | ... - ... |
| aliasing.cpp:131:15:131:16 | xs |
| aliasing.cpp:136:15:136:17 | + ... |
| aliasing.cpp:141:15:141:15 | s |
| aliasing.cpp:141:17:141:20 | data |
| aliasing.cpp:147:15:147:22 | & ... |
| aliasing.cpp:147:16:147:19 | access to array |
| aliasing.cpp:158:15:158:15 | s |
| aliasing.cpp:158:17:158:20 | data |
| aliasing.cpp:164:15:164:15 | s |
| aliasing.cpp:164:17:164:20 | data |
| aliasing.cpp:175:15:175:22 | & ... |
| aliasing.cpp:175:16:175:17 | s2 |
| aliasing.cpp:175:19:175:19 | s |
| aliasing.cpp:181:15:181:22 | & ... |
| aliasing.cpp:181:16:181:17 | s2 |
| aliasing.cpp:181:19:181:19 | s |
| aliasing.cpp:187:15:187:22 | & ... |
| aliasing.cpp:187:16:187:17 | s2 |
| aliasing.cpp:187:19:187:19 | s |
| aliasing.cpp:194:15:194:22 | & ... |
| aliasing.cpp:194:16:194:17 | s2 |
| aliasing.cpp:194:19:194:19 | s |
| aliasing.cpp:200:15:200:24 | & ... |
| aliasing.cpp:200:16:200:18 | ps2 |
| aliasing.cpp:200:21:200:21 | s |
| aliasing.cpp:205:15:205:24 | & ... |
| aliasing.cpp:205:16:205:18 | ps2 |
| aliasing.cpp:205:21:205:21 | s |
| arrays.cpp:6:3:6:5 | arr |
| arrays.cpp:7:8:7:13 | access to array |
| arrays.cpp:8:8:8:13 | access to array |
| arrays.cpp:9:8:9:11 | * ... |
| arrays.cpp:10:8:10:15 | * ... |
| arrays.cpp:16:8:16:13 | access to array |
| arrays.cpp:17:8:17:13 | access to array |
| arrays.cpp:36:3:36:3 | o |
| arrays.cpp:36:3:36:17 | access to array |
| arrays.cpp:36:5:36:10 | nested |
| arrays.cpp:37:8:37:8 | o |
| arrays.cpp:37:8:37:22 | access to array |
| arrays.cpp:37:10:37:15 | nested |
| arrays.cpp:37:24:37:27 | data |
| arrays.cpp:38:8:38:8 | o |
| arrays.cpp:38:8:38:22 | access to array |
| arrays.cpp:38:10:38:15 | nested |
| arrays.cpp:38:24:38:27 | data |
| arrays.cpp:42:3:42:3 | o |
| arrays.cpp:42:3:42:20 | access to array |
| arrays.cpp:42:5:42:12 | indirect |
| arrays.cpp:43:8:43:8 | o |
| arrays.cpp:43:8:43:25 | access to array |
| arrays.cpp:43:10:43:17 | indirect |
| arrays.cpp:43:27:43:30 | data |
| arrays.cpp:44:8:44:8 | o |
| arrays.cpp:44:8:44:25 | access to array |
| arrays.cpp:44:10:44:17 | indirect |
| arrays.cpp:44:27:44:30 | data |
| arrays.cpp:48:3:48:3 | o |
| arrays.cpp:48:3:48:20 | access to array |
| arrays.cpp:48:5:48:12 | indirect |
| arrays.cpp:49:8:49:8 | o |
| arrays.cpp:49:8:49:25 | access to array |
| arrays.cpp:49:10:49:17 | indirect |
| arrays.cpp:49:27:49:30 | data |
| arrays.cpp:50:8:50:8 | o |
| arrays.cpp:50:8:50:25 | access to array |
| arrays.cpp:50:10:50:17 | indirect |
| arrays.cpp:50:27:50:30 | data |
| by_reference.cpp:12:5:12:5 | s |
| by_reference.cpp:16:5:16:8 | this |
| by_reference.cpp:20:5:20:8 | this |
| by_reference.cpp:20:23:20:27 | value |
| by_reference.cpp:24:19:24:22 | this |
| by_reference.cpp:24:25:24:29 | value |
| by_reference.cpp:50:3:50:3 | s |
| by_reference.cpp:50:17:50:26 | call to user_input |
| by_reference.cpp:51:10:51:20 | call to getDirectly |
| by_reference.cpp:56:3:56:3 | s |
| by_reference.cpp:56:19:56:28 | call to user_input |
| by_reference.cpp:57:10:57:22 | call to getIndirectly |
| by_reference.cpp:62:3:62:3 | s |
| by_reference.cpp:62:25:62:34 | call to user_input |
| by_reference.cpp:63:10:63:28 | call to getThroughNonMember |
| by_reference.cpp:68:17:68:18 | & ... |
| by_reference.cpp:68:21:68:30 | call to user_input |
| by_reference.cpp:69:8:69:20 | call to nonMemberGetA |
| by_reference.cpp:84:3:84:7 | inner |
| by_reference.cpp:88:3:88:7 | inner |
| by_reference.cpp:102:21:102:39 | & ... |
| by_reference.cpp:102:22:102:26 | outer |
| by_reference.cpp:103:21:103:25 | outer |
| by_reference.cpp:103:27:103:35 | inner_ptr |
| by_reference.cpp:104:15:104:22 | & ... |
| by_reference.cpp:104:16:104:20 | outer |
| by_reference.cpp:106:21:106:41 | & ... |
| by_reference.cpp:106:22:106:27 | pouter |
| by_reference.cpp:107:21:107:26 | pouter |
| by_reference.cpp:107:29:107:37 | inner_ptr |
| by_reference.cpp:108:15:108:24 | & ... |
| by_reference.cpp:108:16:108:21 | pouter |
| by_reference.cpp:110:8:110:12 | outer |
| by_reference.cpp:110:14:110:25 | inner_nested |
| by_reference.cpp:110:27:110:27 | a |
| by_reference.cpp:111:8:111:12 | outer |
| by_reference.cpp:111:14:111:22 | inner_ptr |
| by_reference.cpp:111:25:111:25 | a |
| by_reference.cpp:112:8:112:12 | outer |
| by_reference.cpp:112:14:112:14 | a |
| by_reference.cpp:114:8:114:13 | pouter |
| by_reference.cpp:114:16:114:27 | inner_nested |
| by_reference.cpp:114:29:114:29 | a |
| by_reference.cpp:115:8:115:13 | pouter |
| by_reference.cpp:115:16:115:24 | inner_ptr |
| by_reference.cpp:115:27:115:27 | a |
| by_reference.cpp:116:8:116:13 | pouter |
| by_reference.cpp:116:16:116:16 | a |
| by_reference.cpp:122:21:122:25 | outer |
| by_reference.cpp:122:27:122:38 | inner_nested |
| by_reference.cpp:123:21:123:36 | * ... |
| by_reference.cpp:123:22:123:26 | outer |
| by_reference.cpp:124:15:124:19 | outer |
| by_reference.cpp:124:21:124:21 | a |
| by_reference.cpp:126:21:126:26 | pouter |
| by_reference.cpp:126:29:126:40 | inner_nested |
| by_reference.cpp:127:21:127:38 | * ... |
| by_reference.cpp:127:22:127:27 | pouter |
| by_reference.cpp:128:15:128:20 | pouter |
| by_reference.cpp:128:23:128:23 | a |
| by_reference.cpp:130:8:130:12 | outer |
| by_reference.cpp:130:14:130:25 | inner_nested |
| by_reference.cpp:130:27:130:27 | a |
| by_reference.cpp:131:8:131:12 | outer |
| by_reference.cpp:131:14:131:22 | inner_ptr |
| by_reference.cpp:131:25:131:25 | a |
| by_reference.cpp:132:8:132:12 | outer |
| by_reference.cpp:132:14:132:14 | a |
| by_reference.cpp:134:8:134:13 | pouter |
| by_reference.cpp:134:16:134:27 | inner_nested |
| by_reference.cpp:134:29:134:29 | a |
| by_reference.cpp:135:8:135:13 | pouter |
| by_reference.cpp:135:16:135:24 | inner_ptr |
| by_reference.cpp:135:27:135:27 | a |
| by_reference.cpp:136:8:136:13 | pouter |
| by_reference.cpp:136:16:136:16 | a |
| complex.cpp:11:22:11:23 | this |
| complex.cpp:12:22:12:23 | this |
| complex.cpp:42:8:42:8 | b |
| complex.cpp:42:10:42:14 | inner |
| complex.cpp:42:16:42:16 | f |
| complex.cpp:43:8:43:8 | b |
| complex.cpp:43:10:43:14 | inner |
| complex.cpp:43:16:43:16 | f |
| complex.cpp:53:3:53:4 | b1 |
| complex.cpp:53:6:53:10 | inner |
| complex.cpp:53:12:53:12 | f |
| complex.cpp:54:3:54:4 | b2 |
| complex.cpp:54:6:54:10 | inner |
| complex.cpp:54:12:54:12 | f |
| complex.cpp:55:3:55:4 | b3 |
| complex.cpp:55:6:55:10 | inner |
| complex.cpp:55:12:55:12 | f |
| complex.cpp:56:3:56:4 | b3 |
| complex.cpp:56:6:56:10 | inner |
| complex.cpp:56:12:56:12 | f |
| complex.cpp:59:7:59:8 | b1 |
| complex.cpp:62:7:62:8 | b2 |
| complex.cpp:65:7:65:8 | b3 |
| complex.cpp:68:7:68:8 | b4 |
| conflated.cpp:10:4:10:5 | ra |
| conflated.cpp:19:19:19:21 | raw |
| conflated.cpp:20:8:20:10 | raw |
| conflated.cpp:29:3:29:4 | pa |
| conflated.cpp:36:3:36:4 | pa |
| conflated.cpp:53:3:53:4 | ll |
| conflated.cpp:54:3:54:4 | ll |
| conflated.cpp:54:7:54:10 | next |
| conflated.cpp:59:20:59:39 | new |
| conflated.cpp:59:35:59:38 | next |
| conflated.cpp:60:3:60:4 | ll |
| conflated.cpp:60:7:60:10 | next |
| constructors.cpp:20:24:20:25 | this |
| constructors.cpp:21:24:21:25 | this |
| constructors.cpp:28:10:28:10 | f |
| constructors.cpp:29:10:29:10 | f |
| constructors.cpp:40:9:40:9 | f |
| constructors.cpp:43:9:43:9 | g |
| constructors.cpp:46:9:46:9 | h |
| constructors.cpp:49:9:49:9 | i |
| qualifiers.cpp:9:30:9:33 | this |
| qualifiers.cpp:12:49:12:53 | inner |
| qualifiers.cpp:13:51:13:55 | inner |
| qualifiers.cpp:22:5:22:9 | outer |
| qualifiers.cpp:22:11:22:18 | call to getInner |
| qualifiers.cpp:23:10:23:14 | outer |
| qualifiers.cpp:23:16:23:20 | inner |
| qualifiers.cpp:23:23:23:23 | a |
| qualifiers.cpp:27:5:27:9 | outer |
| qualifiers.cpp:27:11:27:18 | call to getInner |
| qualifiers.cpp:27:28:27:37 | call to user_input |
| qualifiers.cpp:28:10:28:14 | outer |
| qualifiers.cpp:28:16:28:20 | inner |
| qualifiers.cpp:28:23:28:23 | a |
| qualifiers.cpp:32:17:32:21 | outer |
| qualifiers.cpp:32:23:32:30 | call to getInner |
| qualifiers.cpp:32:35:32:44 | call to user_input |
| qualifiers.cpp:33:10:33:14 | outer |
| qualifiers.cpp:33:16:33:20 | inner |
| qualifiers.cpp:33:23:33:23 | a |
| qualifiers.cpp:37:19:37:35 | * ... |
| qualifiers.cpp:37:20:37:24 | outer |
| qualifiers.cpp:37:38:37:47 | call to user_input |
| qualifiers.cpp:38:10:38:14 | outer |
| qualifiers.cpp:38:16:38:20 | inner |
| qualifiers.cpp:38:23:38:23 | a |
| qualifiers.cpp:42:6:42:22 | * ... |
| qualifiers.cpp:42:7:42:11 | outer |
| qualifiers.cpp:43:10:43:14 | outer |
| qualifiers.cpp:43:16:43:20 | inner |
| qualifiers.cpp:43:23:43:23 | a |
| qualifiers.cpp:47:6:47:11 | & ... |
| qualifiers.cpp:47:15:47:22 | call to getInner |
| qualifiers.cpp:48:10:48:14 | outer |
| qualifiers.cpp:48:16:48:20 | inner |
| qualifiers.cpp:48:23:48:23 | a |
| realistic.cpp:42:20:42:20 | o |
| realistic.cpp:49:9:49:11 | foo |
| realistic.cpp:49:9:49:18 | access to array |
| realistic.cpp:53:9:53:11 | foo |
| realistic.cpp:53:9:53:18 | access to array |
| realistic.cpp:53:20:53:22 | baz |
| realistic.cpp:53:25:53:33 | userInput |
| realistic.cpp:54:16:54:18 | foo |
| realistic.cpp:54:16:54:25 | access to array |
| realistic.cpp:54:27:54:29 | baz |
| realistic.cpp:54:32:54:40 | userInput |
| realistic.cpp:54:42:54:47 | buffer |
| realistic.cpp:60:16:60:18 | dst |
| realistic.cpp:61:21:61:23 | foo |
| realistic.cpp:61:21:61:30 | access to array |
| realistic.cpp:61:32:61:34 | baz |
| realistic.cpp:61:37:61:45 | userInput |
| realistic.cpp:61:47:61:55 | bufferLen |
| realistic.cpp:65:21:65:23 | foo |
| realistic.cpp:65:21:65:30 | access to array |
| realistic.cpp:65:32:65:34 | baz |
| realistic.cpp:65:37:65:45 | userInput |
| realistic.cpp:65:47:65:52 | buffer |
| realistic.cpp:66:21:66:23 | dst |
| simple.cpp:20:24:20:25 | this |
| simple.cpp:21:24:21:25 | this |
| simple.cpp:28:10:28:10 | f |
| simple.cpp:29:10:29:10 | f |
| simple.cpp:39:5:39:5 | f |
| simple.cpp:40:5:40:5 | g |
| simple.cpp:41:5:41:5 | h |
| simple.cpp:42:5:42:5 | h |
| simple.cpp:45:9:45:9 | f |
| simple.cpp:48:9:48:9 | g |
| simple.cpp:51:9:51:9 | h |
| simple.cpp:54:9:54:9 | i |
| simple.cpp:65:5:65:5 | a |
| simple.cpp:83:9:83:10 | f2 |
| simple.cpp:83:9:83:10 | this |
| simple.cpp:84:14:84:20 | this |
| simple.cpp:92:5:92:5 | a |
| struct_init.c:15:8:15:9 | ab |
| struct_init.c:15:12:15:12 | a |
| struct_init.c:16:8:16:9 | ab |
| struct_init.c:16:12:16:12 | b |
| struct_init.c:22:8:22:9 | ab |
| struct_init.c:22:11:22:11 | a |
| struct_init.c:23:8:23:9 | ab |
| struct_init.c:23:11:23:11 | b |
| struct_init.c:24:10:24:12 | & ... |
| struct_init.c:31:8:31:12 | outer |
| struct_init.c:31:14:31:21 | nestedAB |
| struct_init.c:31:23:31:23 | a |
| struct_init.c:32:8:32:12 | outer |
| struct_init.c:32:14:32:21 | nestedAB |
| struct_init.c:32:23:32:23 | b |
| struct_init.c:33:8:33:12 | outer |
| struct_init.c:33:14:33:22 | pointerAB |
| struct_init.c:33:25:33:25 | a |
| struct_init.c:34:8:34:12 | outer |
| struct_init.c:34:14:34:22 | pointerAB |
| struct_init.c:34:25:34:25 | b |
| struct_init.c:36:10:36:24 | & ... |
| struct_init.c:36:11:36:15 | outer |
| struct_init.c:46:10:46:14 | outer |
| struct_init.c:46:16:46:24 | pointerAB |

View File

@@ -107,6 +107,10 @@
| C.cpp:19:5:19:5 | c |
| C.cpp:24:5:24:8 | this |
| C.cpp:24:11:24:12 | s3 |
| C.cpp:29:10:29:11 | s1 |
| C.cpp:29:10:29:11 | this |
| C.cpp:31:10:31:11 | s3 |
| C.cpp:31:10:31:11 | this |
| D.cpp:9:21:9:24 | elem |
| D.cpp:9:21:9:24 | this |
| D.cpp:11:29:11:32 | elem |

View File

@@ -10,29 +10,35 @@ edges
| A.cpp:31:20:31:20 | c | A.cpp:23:10:23:10 | c |
| A.cpp:31:20:31:20 | c | A.cpp:31:14:31:21 | call to B [c] |
| A.cpp:41:15:41:21 | new | A.cpp:43:10:43:12 | & ... |
| A.cpp:43:10:43:12 | & ... | A.cpp:173:26:173:26 | o |
| A.cpp:47:12:47:18 | new | A.cpp:48:20:48:20 | c |
| A.cpp:48:12:48:18 | call to make [c] | A.cpp:49:10:49:10 | b [c] |
| A.cpp:48:20:48:20 | c | A.cpp:29:23:29:23 | c |
| A.cpp:48:20:48:20 | c | A.cpp:48:12:48:18 | call to make [c] |
| A.cpp:49:10:49:10 | b [c] | A.cpp:49:13:49:13 | c |
| A.cpp:49:13:49:13 | c | A.cpp:173:26:173:26 | o |
| A.cpp:55:5:55:5 | ref arg b [c] | A.cpp:56:10:56:10 | b [c] |
| A.cpp:55:12:55:19 | new | A.cpp:27:17:27:17 | c |
| A.cpp:55:12:55:19 | new | A.cpp:55:5:55:5 | ref arg b [c] |
| A.cpp:56:10:56:10 | b [c] | A.cpp:28:8:28:10 | this [c] |
| A.cpp:56:10:56:10 | b [c] | A.cpp:56:13:56:15 | call to get |
| A.cpp:56:13:56:15 | call to get | A.cpp:173:26:173:26 | o |
| A.cpp:57:11:57:24 | call to B [c] | A.cpp:57:11:57:24 | new [c] |
| A.cpp:57:11:57:24 | new [c] | A.cpp:28:8:28:10 | this [c] |
| A.cpp:57:11:57:24 | new [c] | A.cpp:57:28:57:30 | call to get |
| A.cpp:57:17:57:23 | new | A.cpp:23:10:23:10 | c |
| A.cpp:57:17:57:23 | new | A.cpp:57:11:57:24 | call to B [c] |
| A.cpp:57:28:57:30 | call to get | A.cpp:173:26:173:26 | o |
| A.cpp:64:10:64:15 | call to setOnB [c] | A.cpp:66:10:66:11 | b2 [c] |
| A.cpp:64:21:64:28 | new | A.cpp:64:10:64:15 | call to setOnB [c] |
| A.cpp:64:21:64:28 | new | A.cpp:85:26:85:26 | c |
| A.cpp:66:10:66:11 | b2 [c] | A.cpp:66:14:66:14 | c |
| A.cpp:66:14:66:14 | c | A.cpp:173:26:173:26 | o |
| A.cpp:73:10:73:19 | call to setOnBWrap [c] | A.cpp:75:10:75:11 | b2 [c] |
| A.cpp:73:25:73:32 | new | A.cpp:73:10:73:19 | call to setOnBWrap [c] |
| A.cpp:73:25:73:32 | new | A.cpp:78:27:78:27 | c |
| A.cpp:75:10:75:11 | b2 [c] | A.cpp:75:14:75:14 | c |
| A.cpp:75:14:75:14 | c | A.cpp:173:26:173:26 | o |
| A.cpp:78:27:78:27 | c | A.cpp:81:21:81:21 | c |
| A.cpp:81:10:81:15 | call to setOnB [c] | A.cpp:82:12:82:24 | ... ? ... : ... [c] |
| A.cpp:81:21:81:21 | c | A.cpp:81:10:81:15 | call to setOnB [c] |
@@ -48,13 +54,20 @@ edges
| A.cpp:103:14:103:14 | c [a] | A.cpp:107:12:107:13 | c1 [a] |
| A.cpp:103:14:103:14 | c [a] | A.cpp:120:12:120:13 | c1 [a] |
| A.cpp:107:12:107:13 | c1 [a] | A.cpp:107:16:107:16 | a |
| A.cpp:107:16:107:16 | a | A.cpp:173:26:173:26 | o |
| A.cpp:120:12:120:13 | c1 [a] | A.cpp:120:16:120:16 | a |
| A.cpp:120:16:120:16 | a | A.cpp:173:26:173:26 | o |
| A.cpp:124:14:124:14 | b [c] | A.cpp:131:8:131:8 | ref arg b [c] |
| A.cpp:126:5:126:5 | ref arg b [c] | A.cpp:124:14:124:14 | b [c] |
| A.cpp:126:5:126:5 | ref arg b [c] | A.cpp:131:8:131:8 | ref arg b [c] |
| A.cpp:126:12:126:18 | new | A.cpp:27:17:27:17 | c |
| A.cpp:126:12:126:18 | new | A.cpp:126:5:126:5 | ref arg b [c] |
| A.cpp:131:8:131:8 | ref arg b [c] | A.cpp:132:10:132:10 | b [c] |
| A.cpp:132:10:132:10 | b [c] | A.cpp:132:13:132:13 | c |
| A.cpp:132:13:132:13 | c | A.cpp:173:26:173:26 | o |
| A.cpp:140:13:140:13 | b | A.cpp:143:7:143:31 | ... = ... |
| A.cpp:140:13:140:13 | b [c] | A.cpp:151:18:151:18 | ref arg b [c] |
| A.cpp:142:7:142:7 | b [post update] [c] | A.cpp:140:13:140:13 | b [c] |
| A.cpp:142:7:142:7 | b [post update] [c] | A.cpp:143:7:143:31 | ... = ... [c] |
| A.cpp:142:7:142:7 | b [post update] [c] | A.cpp:151:18:151:18 | ref arg b [c] |
| A.cpp:142:7:142:20 | ... = ... | A.cpp:142:7:142:7 | b [post update] [c] |
@@ -66,15 +79,24 @@ edges
| A.cpp:143:7:143:31 | ... = ... [c] | A.cpp:143:7:143:10 | this [post update] [b, c] |
| A.cpp:143:25:143:31 | new | A.cpp:143:7:143:31 | ... = ... |
| A.cpp:150:12:150:18 | new | A.cpp:151:18:151:18 | b |
| A.cpp:151:12:151:24 | call to D [b, c] | A.cpp:152:10:152:10 | d [b, c] |
| A.cpp:151:12:151:24 | call to D [b, c] | A.cpp:153:10:153:10 | d [b, c] |
| A.cpp:151:12:151:24 | call to D [b] | A.cpp:152:10:152:10 | d [b] |
| A.cpp:151:18:151:18 | b | A.cpp:140:13:140:13 | b |
| A.cpp:151:18:151:18 | b | A.cpp:151:12:151:24 | call to D [b] |
| A.cpp:151:18:151:18 | ref arg b [c] | A.cpp:154:10:154:10 | b [c] |
| A.cpp:152:10:152:10 | d [b, c] | A.cpp:152:13:152:13 | b [c] |
| A.cpp:152:10:152:10 | d [b] | A.cpp:152:13:152:13 | b |
| A.cpp:152:10:152:10 | d [post update] [b, c] | A.cpp:153:10:153:10 | d [b, c] |
| A.cpp:152:13:152:13 | b | A.cpp:173:26:173:26 | o |
| A.cpp:152:13:152:13 | b [c] | A.cpp:152:13:152:13 | ref arg b [c] |
| A.cpp:152:13:152:13 | b [c] | A.cpp:173:26:173:26 | o [c] |
| A.cpp:152:13:152:13 | ref arg b [c] | A.cpp:152:10:152:10 | d [post update] [b, c] |
| A.cpp:153:10:153:10 | d [b, c] | A.cpp:153:13:153:13 | b [c] |
| A.cpp:153:13:153:13 | b [c] | A.cpp:153:16:153:16 | c |
| A.cpp:153:16:153:16 | c | A.cpp:173:26:173:26 | o |
| A.cpp:154:10:154:10 | b [c] | A.cpp:154:13:154:13 | c |
| A.cpp:154:13:154:13 | c | A.cpp:173:26:173:26 | o |
| A.cpp:159:12:159:18 | new | A.cpp:160:29:160:29 | b |
| A.cpp:160:18:160:60 | call to MyList [head] | A.cpp:161:38:161:39 | l1 [head] |
| A.cpp:160:29:160:29 | b | A.cpp:160:18:160:60 | call to MyList [head] |
@@ -87,13 +109,23 @@ edges
| A.cpp:162:38:162:39 | l2 [next, head] | A.cpp:162:18:162:40 | call to MyList [next, next, head] |
| A.cpp:162:38:162:39 | l2 [next, head] | A.cpp:181:32:181:35 | next [next, head] |
| A.cpp:165:10:165:11 | l3 [next, next, head] | A.cpp:165:14:165:17 | next [next, head] |
| A.cpp:165:10:165:11 | l3 [post update] [next, next, head] | A.cpp:167:44:167:44 | l [next, next, head] |
| A.cpp:165:14:165:17 | next [next, head] | A.cpp:165:20:165:23 | next [head] |
| A.cpp:165:14:165:17 | next [post update] [next, head] | A.cpp:165:10:165:11 | l3 [post update] [next, next, head] |
| A.cpp:165:20:165:23 | next [head] | A.cpp:165:26:165:29 | head |
| A.cpp:165:20:165:23 | next [head] | A.cpp:165:26:165:29 | head |
| A.cpp:165:20:165:23 | next [post update] [head] | A.cpp:165:14:165:17 | next [post update] [next, head] |
| A.cpp:165:26:165:29 | head | A.cpp:165:26:165:29 | ref arg head |
| A.cpp:165:26:165:29 | head | A.cpp:173:26:173:26 | o |
| A.cpp:165:26:165:29 | ref arg head | A.cpp:165:20:165:23 | next [post update] [head] |
| A.cpp:167:44:167:44 | l [next, head] | A.cpp:167:47:167:50 | next [head] |
| A.cpp:167:44:167:44 | l [next, next, head] | A.cpp:167:47:167:50 | next [next, head] |
| A.cpp:167:47:167:50 | next [head] | A.cpp:169:12:169:12 | l [head] |
| A.cpp:167:47:167:50 | next [next, head] | A.cpp:167:44:167:44 | l [next, head] |
| A.cpp:169:12:169:12 | l [head] | A.cpp:169:15:169:18 | head |
| A.cpp:169:15:169:18 | head | A.cpp:173:26:173:26 | o |
| A.cpp:173:26:173:26 | o | A.cpp:173:26:173:26 | o |
| A.cpp:173:26:173:26 | o [c] | A.cpp:173:26:173:26 | o [c] |
| A.cpp:181:15:181:21 | newHead | A.cpp:183:7:183:20 | ... = ... |
| A.cpp:181:32:181:35 | next [head] | A.cpp:184:7:184:23 | ... = ... [head] |
| A.cpp:181:32:181:35 | next [next, head] | A.cpp:184:7:184:23 | ... = ... [next, head] |
@@ -150,6 +182,7 @@ edges
| D.cpp:22:10:22:11 | b2 [box, elem] | D.cpp:22:14:22:20 | call to getBox1 [elem] |
| D.cpp:22:14:22:20 | call to getBox1 [elem] | D.cpp:10:11:10:17 | this [elem] |
| D.cpp:22:14:22:20 | call to getBox1 [elem] | D.cpp:22:25:22:31 | call to getElem |
| D.cpp:22:25:22:31 | call to getElem | realistic.cpp:41:17:41:17 | o |
| D.cpp:28:15:28:24 | new | D.cpp:30:5:30:20 | ... = ... |
| D.cpp:30:5:30:5 | b [post update] [box, elem] | D.cpp:31:14:31:14 | b [box, elem] |
| D.cpp:30:5:30:20 | ... = ... | D.cpp:30:8:30:10 | box [post update] [elem] |
@@ -182,17 +215,23 @@ edges
| D.cpp:64:10:64:17 | boxfield [box, elem] | D.cpp:64:20:64:22 | box [elem] |
| D.cpp:64:10:64:17 | this [boxfield, box, elem] | D.cpp:64:10:64:17 | boxfield [box, elem] |
| D.cpp:64:20:64:22 | box [elem] | D.cpp:64:25:64:28 | elem |
| D.cpp:64:25:64:28 | elem | realistic.cpp:41:17:41:17 | o |
| E.cpp:19:27:19:27 | p [data, buffer] | E.cpp:21:10:21:10 | p [data, buffer] |
| E.cpp:21:10:21:10 | p [data, buffer] | E.cpp:21:13:21:16 | data [buffer] |
| E.cpp:21:13:21:16 | data [buffer] | E.cpp:21:18:21:23 | buffer |
| E.cpp:21:18:21:23 | buffer | realistic.cpp:41:17:41:17 | o |
| E.cpp:28:21:28:23 | ref arg raw | E.cpp:31:10:31:12 | raw |
| E.cpp:29:21:29:21 | b [post update] [buffer] | E.cpp:32:10:32:10 | b [buffer] |
| E.cpp:29:24:29:29 | ref arg buffer | E.cpp:29:21:29:21 | b [post update] [buffer] |
| E.cpp:30:21:30:21 | p [post update] [data, buffer] | E.cpp:33:18:33:19 | & ... [data, buffer] |
| E.cpp:30:23:30:26 | data [post update] [buffer] | E.cpp:30:21:30:21 | p [post update] [data, buffer] |
| E.cpp:30:28:30:33 | ref arg buffer | E.cpp:30:23:30:26 | data [post update] [buffer] |
| E.cpp:31:10:31:12 | raw | realistic.cpp:41:17:41:17 | o |
| E.cpp:32:10:32:10 | b [buffer] | E.cpp:32:13:32:18 | buffer |
| E.cpp:32:13:32:18 | buffer | realistic.cpp:41:17:41:17 | o |
| E.cpp:33:18:33:19 | & ... [data, buffer] | E.cpp:19:27:19:27 | p [data, buffer] |
| aliasing.cpp:8:23:8:23 | s [m1] | aliasing.cpp:25:17:25:19 | ref arg & ... [m1] |
| aliasing.cpp:9:3:9:3 | s [post update] [m1] | aliasing.cpp:8:23:8:23 | s [m1] |
| aliasing.cpp:9:3:9:3 | s [post update] [m1] | aliasing.cpp:25:17:25:19 | ref arg & ... [m1] |
| aliasing.cpp:9:3:9:22 | ... = ... | aliasing.cpp:9:3:9:3 | s [post update] [m1] |
| aliasing.cpp:9:11:9:20 | call to user_input | aliasing.cpp:9:3:9:22 | ... = ... |
@@ -204,30 +243,42 @@ edges
| aliasing.cpp:25:17:25:19 | ref arg & ... [m1] | aliasing.cpp:29:8:29:9 | s1 [m1] |
| aliasing.cpp:26:19:26:20 | ref arg s2 [m1] | aliasing.cpp:30:8:30:9 | s2 [m1] |
| aliasing.cpp:29:8:29:9 | s1 [m1] | aliasing.cpp:29:11:29:12 | m1 |
| aliasing.cpp:29:11:29:12 | m1 | realistic.cpp:41:17:41:17 | o |
| aliasing.cpp:30:8:30:9 | s2 [m1] | aliasing.cpp:30:11:30:12 | m1 |
| aliasing.cpp:30:11:30:12 | m1 | realistic.cpp:41:17:41:17 | o |
| aliasing.cpp:60:3:60:4 | s2 [post update] [m1] | aliasing.cpp:62:8:62:12 | copy2 [m1] |
| aliasing.cpp:60:3:60:22 | ... = ... | aliasing.cpp:60:3:60:4 | s2 [post update] [m1] |
| aliasing.cpp:60:11:60:20 | call to user_input | aliasing.cpp:60:3:60:22 | ... = ... |
| aliasing.cpp:62:8:62:12 | copy2 [m1] | aliasing.cpp:62:14:62:15 | m1 |
| aliasing.cpp:62:14:62:15 | m1 | realistic.cpp:41:17:41:17 | o |
| aliasing.cpp:92:3:92:3 | w [post update] [s, m1] | aliasing.cpp:93:8:93:8 | w [s, m1] |
| aliasing.cpp:92:3:92:23 | ... = ... | aliasing.cpp:92:5:92:5 | s [post update] [m1] |
| aliasing.cpp:92:5:92:5 | s [post update] [m1] | aliasing.cpp:92:3:92:3 | w [post update] [s, m1] |
| aliasing.cpp:92:12:92:21 | call to user_input | aliasing.cpp:92:3:92:23 | ... = ... |
| aliasing.cpp:93:8:93:8 | w [s, m1] | aliasing.cpp:93:10:93:10 | s [m1] |
| aliasing.cpp:93:10:93:10 | s [m1] | aliasing.cpp:93:12:93:13 | m1 |
| aliasing.cpp:93:12:93:13 | m1 | realistic.cpp:41:17:41:17 | o |
| aliasing.cpp:105:23:105:24 | pa | aliasing.cpp:158:17:158:20 | ref arg data |
| aliasing.cpp:105:23:105:24 | pa | aliasing.cpp:164:17:164:20 | ref arg data |
| aliasing.cpp:105:23:105:24 | pa | aliasing.cpp:175:15:175:22 | ref arg & ... |
| aliasing.cpp:105:23:105:24 | pa | aliasing.cpp:187:15:187:22 | ref arg & ... |
| aliasing.cpp:105:23:105:24 | pa | aliasing.cpp:200:15:200:24 | ref arg & ... |
| aliasing.cpp:106:4:106:5 | pa [inner post update] | aliasing.cpp:158:17:158:20 | ref arg data |
| aliasing.cpp:106:4:106:5 | pa [inner post update] | aliasing.cpp:164:17:164:20 | ref arg data |
| aliasing.cpp:106:4:106:5 | pa [inner post update] | aliasing.cpp:175:15:175:22 | ref arg & ... |
| aliasing.cpp:106:4:106:5 | pa [inner post update] | aliasing.cpp:187:15:187:22 | ref arg & ... |
| aliasing.cpp:106:4:106:5 | pa [inner post update] | aliasing.cpp:200:15:200:24 | ref arg & ... |
| aliasing.cpp:106:9:106:18 | call to user_input | aliasing.cpp:105:23:105:24 | pa |
| aliasing.cpp:106:9:106:18 | call to user_input | aliasing.cpp:106:4:106:5 | pa [inner post update] |
| aliasing.cpp:158:15:158:15 | s [post update] [data] | aliasing.cpp:159:9:159:9 | s [data] |
| aliasing.cpp:158:17:158:20 | ref arg data | aliasing.cpp:158:15:158:15 | s [post update] [data] |
| aliasing.cpp:159:8:159:14 | * ... | realistic.cpp:41:17:41:17 | o |
| aliasing.cpp:159:9:159:9 | s [data] | aliasing.cpp:159:11:159:14 | data |
| aliasing.cpp:159:11:159:14 | data | aliasing.cpp:159:8:159:14 | * ... |
| aliasing.cpp:164:15:164:15 | s [post update] [data] | aliasing.cpp:165:8:165:8 | s [data] |
| aliasing.cpp:164:17:164:20 | ref arg data | aliasing.cpp:164:15:164:15 | s [post update] [data] |
| aliasing.cpp:165:8:165:8 | s [data] | aliasing.cpp:165:10:165:13 | data |
| aliasing.cpp:165:8:165:16 | access to array | realistic.cpp:41:17:41:17 | o |
| aliasing.cpp:165:10:165:13 | data | aliasing.cpp:165:8:165:16 | access to array |
| aliasing.cpp:175:15:175:22 | ref arg & ... | aliasing.cpp:175:21:175:22 | m1 [inner post update] |
| aliasing.cpp:175:16:175:17 | s2 [post update] [s, m1] | aliasing.cpp:176:8:176:9 | s2 [s, m1] |
@@ -235,24 +286,33 @@ edges
| aliasing.cpp:175:21:175:22 | m1 [inner post update] | aliasing.cpp:175:19:175:19 | s [post update] [m1] |
| aliasing.cpp:176:8:176:9 | s2 [s, m1] | aliasing.cpp:176:11:176:11 | s [m1] |
| aliasing.cpp:176:11:176:11 | s [m1] | aliasing.cpp:176:13:176:14 | m1 |
| aliasing.cpp:176:13:176:14 | m1 | realistic.cpp:41:17:41:17 | o |
| aliasing.cpp:187:15:187:22 | ref arg & ... | aliasing.cpp:187:21:187:22 | m1 [inner post update] |
| aliasing.cpp:187:16:187:17 | s2 [post update] [s, m1] | aliasing.cpp:189:8:189:11 | s2_2 [s, m1] |
| aliasing.cpp:187:19:187:19 | s [post update] [m1] | aliasing.cpp:187:16:187:17 | s2 [post update] [s, m1] |
| aliasing.cpp:187:21:187:22 | m1 [inner post update] | aliasing.cpp:187:19:187:19 | s [post update] [m1] |
| aliasing.cpp:189:8:189:11 | s2_2 [s, m1] | aliasing.cpp:189:13:189:13 | s [m1] |
| aliasing.cpp:189:13:189:13 | s [m1] | aliasing.cpp:189:15:189:16 | m1 |
| aliasing.cpp:189:15:189:16 | m1 | realistic.cpp:41:17:41:17 | o |
| aliasing.cpp:200:15:200:24 | ref arg & ... | aliasing.cpp:200:23:200:24 | m1 [inner post update] |
| aliasing.cpp:200:16:200:18 | ps2 [post update] [s, m1] | aliasing.cpp:201:8:201:10 | ps2 [s, m1] |
| aliasing.cpp:200:21:200:21 | s [post update] [m1] | aliasing.cpp:200:16:200:18 | ps2 [post update] [s, m1] |
| aliasing.cpp:200:23:200:24 | m1 [inner post update] | aliasing.cpp:200:21:200:21 | s [post update] [m1] |
| aliasing.cpp:201:8:201:10 | ps2 [s, m1] | aliasing.cpp:201:13:201:13 | s [m1] |
| aliasing.cpp:201:13:201:13 | s [m1] | aliasing.cpp:201:15:201:16 | m1 |
| aliasing.cpp:201:15:201:16 | m1 | realistic.cpp:41:17:41:17 | o |
| arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:7:8:7:13 | access to array |
| arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:8:8:8:13 | access to array |
| arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:9:8:9:11 | * ... |
| arrays.cpp:6:12:6:21 | call to user_input | arrays.cpp:10:8:10:15 | * ... |
| arrays.cpp:7:8:7:13 | access to array | realistic.cpp:41:17:41:17 | o |
| arrays.cpp:8:8:8:13 | access to array | realistic.cpp:41:17:41:17 | o |
| arrays.cpp:9:8:9:11 | * ... | realistic.cpp:41:17:41:17 | o |
| arrays.cpp:10:8:10:15 | * ... | realistic.cpp:41:17:41:17 | o |
| arrays.cpp:15:14:15:23 | call to user_input | arrays.cpp:16:8:16:13 | access to array |
| arrays.cpp:15:14:15:23 | call to user_input | arrays.cpp:17:8:17:13 | access to array |
| arrays.cpp:16:8:16:13 | access to array | realistic.cpp:41:17:41:17 | o |
| arrays.cpp:17:8:17:13 | access to array | realistic.cpp:41:17:41:17 | o |
| arrays.cpp:36:3:36:3 | o [post update] [nested, arr, data] | arrays.cpp:37:8:37:8 | o [nested, arr, data] |
| arrays.cpp:36:3:36:3 | o [post update] [nested, arr, data] | arrays.cpp:38:8:38:8 | o [nested, arr, data] |
| arrays.cpp:36:3:36:17 | access to array [post update] [data] | arrays.cpp:36:12:36:14 | arr [inner post update] [data] |
@@ -261,13 +321,22 @@ edges
| arrays.cpp:36:12:36:14 | arr [inner post update] [data] | arrays.cpp:36:5:36:10 | nested [post update] [arr, data] |
| arrays.cpp:36:26:36:35 | call to user_input | arrays.cpp:36:3:36:37 | ... = ... |
| arrays.cpp:37:8:37:8 | o [nested, arr, data] | arrays.cpp:37:10:37:15 | nested [arr, data] |
| arrays.cpp:37:8:37:8 | o [post update] [nested, arr, data] | arrays.cpp:38:8:38:8 | o [nested, arr, data] |
| arrays.cpp:37:8:37:22 | access to array [data] | arrays.cpp:37:24:37:27 | data |
| arrays.cpp:37:8:37:22 | access to array [data] | arrays.cpp:37:24:37:27 | data |
| arrays.cpp:37:8:37:22 | access to array [post update] [data] | arrays.cpp:37:17:37:19 | arr [inner post update] [data] |
| arrays.cpp:37:10:37:15 | nested [arr, data] | arrays.cpp:37:17:37:19 | arr [data] |
| arrays.cpp:37:10:37:15 | nested [post update] [arr, data] | arrays.cpp:37:8:37:8 | o [post update] [nested, arr, data] |
| arrays.cpp:37:17:37:19 | arr [data] | arrays.cpp:37:8:37:22 | access to array [data] |
| arrays.cpp:37:17:37:19 | arr [inner post update] [data] | arrays.cpp:37:10:37:15 | nested [post update] [arr, data] |
| arrays.cpp:37:24:37:27 | data | arrays.cpp:37:24:37:27 | ref arg data |
| arrays.cpp:37:24:37:27 | data | realistic.cpp:41:17:41:17 | o |
| arrays.cpp:37:24:37:27 | ref arg data | arrays.cpp:37:8:37:22 | access to array [post update] [data] |
| arrays.cpp:38:8:38:8 | o [nested, arr, data] | arrays.cpp:38:10:38:15 | nested [arr, data] |
| arrays.cpp:38:8:38:22 | access to array [data] | arrays.cpp:38:24:38:27 | data |
| arrays.cpp:38:10:38:15 | nested [arr, data] | arrays.cpp:38:17:38:19 | arr [data] |
| arrays.cpp:38:17:38:19 | arr [data] | arrays.cpp:38:8:38:22 | access to array [data] |
| arrays.cpp:38:24:38:27 | data | realistic.cpp:41:17:41:17 | o |
| arrays.cpp:42:3:42:3 | o [post update] [indirect, arr, data] | arrays.cpp:43:8:43:8 | o [indirect, arr, data] |
| arrays.cpp:42:3:42:3 | o [post update] [indirect, arr, data] | arrays.cpp:44:8:44:8 | o [indirect, arr, data] |
| arrays.cpp:42:3:42:20 | access to array [post update] [data] | arrays.cpp:42:15:42:17 | arr [inner post update] [data] |
@@ -276,14 +345,24 @@ edges
| arrays.cpp:42:15:42:17 | arr [inner post update] [data] | arrays.cpp:42:5:42:12 | indirect [post update] [arr, data] |
| arrays.cpp:42:29:42:38 | call to user_input | arrays.cpp:42:3:42:40 | ... = ... |
| arrays.cpp:43:8:43:8 | o [indirect, arr, data] | arrays.cpp:43:10:43:17 | indirect [arr, data] |
| arrays.cpp:43:8:43:8 | o [post update] [indirect, arr, data] | arrays.cpp:44:8:44:8 | o [indirect, arr, data] |
| arrays.cpp:43:8:43:25 | access to array [data] | arrays.cpp:43:27:43:30 | data |
| arrays.cpp:43:8:43:25 | access to array [data] | arrays.cpp:43:27:43:30 | data |
| arrays.cpp:43:8:43:25 | access to array [post update] [data] | arrays.cpp:43:20:43:22 | arr [inner post update] [data] |
| arrays.cpp:43:10:43:17 | indirect [arr, data] | arrays.cpp:43:20:43:22 | arr [data] |
| arrays.cpp:43:10:43:17 | indirect [post update] [arr, data] | arrays.cpp:43:8:43:8 | o [post update] [indirect, arr, data] |
| arrays.cpp:43:20:43:22 | arr [data] | arrays.cpp:43:8:43:25 | access to array [data] |
| arrays.cpp:43:20:43:22 | arr [inner post update] [data] | arrays.cpp:43:10:43:17 | indirect [post update] [arr, data] |
| arrays.cpp:43:27:43:30 | data | arrays.cpp:43:27:43:30 | ref arg data |
| arrays.cpp:43:27:43:30 | data | realistic.cpp:41:17:41:17 | o |
| arrays.cpp:43:27:43:30 | ref arg data | arrays.cpp:43:8:43:25 | access to array [post update] [data] |
| arrays.cpp:44:8:44:8 | o [indirect, arr, data] | arrays.cpp:44:10:44:17 | indirect [arr, data] |
| arrays.cpp:44:8:44:25 | access to array [data] | arrays.cpp:44:27:44:30 | data |
| arrays.cpp:44:10:44:17 | indirect [arr, data] | arrays.cpp:44:20:44:22 | arr [data] |
| arrays.cpp:44:20:44:22 | arr [data] | arrays.cpp:44:8:44:25 | access to array [data] |
| arrays.cpp:44:27:44:30 | data | realistic.cpp:41:17:41:17 | o |
| by_reference.cpp:11:48:11:52 | value | by_reference.cpp:12:5:12:16 | ... = ... |
| by_reference.cpp:12:5:12:5 | s [post update] [a] | by_reference.cpp:11:39:11:39 | s [a] |
| by_reference.cpp:12:5:12:16 | ... = ... | by_reference.cpp:12:5:12:5 | s [post update] [a] |
| by_reference.cpp:15:26:15:30 | value | by_reference.cpp:16:5:16:19 | ... = ... |
| by_reference.cpp:16:5:16:19 | ... = ... | by_reference.cpp:16:5:16:8 | this [post update] [a] |
@@ -308,21 +387,30 @@ edges
| by_reference.cpp:50:17:50:26 | call to user_input | by_reference.cpp:50:3:50:3 | ref arg s [a] |
| by_reference.cpp:51:8:51:8 | s [a] | by_reference.cpp:35:9:35:19 | this [a] |
| by_reference.cpp:51:8:51:8 | s [a] | by_reference.cpp:51:10:51:20 | call to getDirectly |
| by_reference.cpp:51:10:51:20 | call to getDirectly | realistic.cpp:41:17:41:17 | o |
| by_reference.cpp:56:3:56:3 | ref arg s [a] | by_reference.cpp:57:8:57:8 | s [a] |
| by_reference.cpp:56:19:56:28 | call to user_input | by_reference.cpp:19:28:19:32 | value |
| by_reference.cpp:56:19:56:28 | call to user_input | by_reference.cpp:56:3:56:3 | ref arg s [a] |
| by_reference.cpp:57:8:57:8 | s [a] | by_reference.cpp:39:9:39:21 | this [a] |
| by_reference.cpp:57:8:57:8 | s [a] | by_reference.cpp:57:10:57:22 | call to getIndirectly |
| by_reference.cpp:57:10:57:22 | call to getIndirectly | realistic.cpp:41:17:41:17 | o |
| by_reference.cpp:62:3:62:3 | ref arg s [a] | by_reference.cpp:63:8:63:8 | s [a] |
| by_reference.cpp:62:25:62:34 | call to user_input | by_reference.cpp:23:34:23:38 | value |
| by_reference.cpp:62:25:62:34 | call to user_input | by_reference.cpp:62:3:62:3 | ref arg s [a] |
| by_reference.cpp:63:8:63:8 | s [a] | by_reference.cpp:43:9:43:27 | this [a] |
| by_reference.cpp:63:8:63:8 | s [a] | by_reference.cpp:63:10:63:28 | call to getThroughNonMember |
| by_reference.cpp:63:10:63:28 | call to getThroughNonMember | realistic.cpp:41:17:41:17 | o |
| by_reference.cpp:68:17:68:18 | ref arg & ... [a] | by_reference.cpp:69:22:69:23 | & ... [a] |
| by_reference.cpp:68:21:68:30 | call to user_input | by_reference.cpp:11:48:11:52 | value |
| by_reference.cpp:68:21:68:30 | call to user_input | by_reference.cpp:68:17:68:18 | ref arg & ... [a] |
| by_reference.cpp:69:8:69:20 | call to nonMemberGetA | realistic.cpp:41:17:41:17 | o |
| by_reference.cpp:69:22:69:23 | & ... [a] | by_reference.cpp:31:46:31:46 | s [a] |
| by_reference.cpp:69:22:69:23 | & ... [a] | by_reference.cpp:69:8:69:20 | call to nonMemberGetA |
| by_reference.cpp:83:31:83:35 | inner [a] | by_reference.cpp:102:21:102:39 | ref arg & ... [a] |
| by_reference.cpp:83:31:83:35 | inner [a] | by_reference.cpp:103:27:103:35 | ref arg inner_ptr [a] |
| by_reference.cpp:83:31:83:35 | inner [a] | by_reference.cpp:106:21:106:41 | ref arg & ... [a] |
| by_reference.cpp:83:31:83:35 | inner [a] | by_reference.cpp:107:29:107:37 | ref arg inner_ptr [a] |
| by_reference.cpp:84:3:84:7 | inner [post update] [a] | by_reference.cpp:83:31:83:35 | inner [a] |
| by_reference.cpp:84:3:84:7 | inner [post update] [a] | by_reference.cpp:102:21:102:39 | ref arg & ... [a] |
| by_reference.cpp:84:3:84:7 | inner [post update] [a] | by_reference.cpp:103:27:103:35 | ref arg inner_ptr [a] |
| by_reference.cpp:84:3:84:7 | inner [post update] [a] | by_reference.cpp:106:21:106:41 | ref arg & ... [a] |
@@ -340,8 +428,11 @@ edges
| by_reference.cpp:88:3:88:7 | inner [post update] [a] | by_reference.cpp:127:21:127:38 | ref arg * ... [a] |
| by_reference.cpp:88:3:88:24 | ... = ... | by_reference.cpp:88:3:88:7 | inner [post update] [a] |
| by_reference.cpp:88:13:88:22 | call to user_input | by_reference.cpp:88:3:88:24 | ... = ... |
| by_reference.cpp:91:25:91:26 | pa | by_reference.cpp:104:15:104:22 | ref arg & ... |
| by_reference.cpp:91:25:91:26 | pa | by_reference.cpp:108:15:108:24 | ref arg & ... |
| by_reference.cpp:92:4:92:5 | pa [inner post update] | by_reference.cpp:104:15:104:22 | ref arg & ... |
| by_reference.cpp:92:4:92:5 | pa [inner post update] | by_reference.cpp:108:15:108:24 | ref arg & ... |
| by_reference.cpp:92:9:92:18 | call to user_input | by_reference.cpp:91:25:91:26 | pa |
| by_reference.cpp:92:9:92:18 | call to user_input | by_reference.cpp:92:4:92:5 | pa [inner post update] |
| by_reference.cpp:95:25:95:26 | pa | by_reference.cpp:124:21:124:21 | ref arg a |
| by_reference.cpp:95:25:95:26 | pa | by_reference.cpp:128:23:128:23 | ref arg a |
@@ -364,14 +455,20 @@ edges
| by_reference.cpp:108:24:108:24 | a [inner post update] | by_reference.cpp:108:16:108:21 | pouter [post update] [a] |
| by_reference.cpp:110:8:110:12 | outer [inner_nested, a] | by_reference.cpp:110:14:110:25 | inner_nested [a] |
| by_reference.cpp:110:14:110:25 | inner_nested [a] | by_reference.cpp:110:27:110:27 | a |
| by_reference.cpp:110:27:110:27 | a | realistic.cpp:41:17:41:17 | o |
| by_reference.cpp:111:8:111:12 | outer [inner_ptr, a] | by_reference.cpp:111:14:111:22 | inner_ptr [a] |
| by_reference.cpp:111:14:111:22 | inner_ptr [a] | by_reference.cpp:111:25:111:25 | a |
| by_reference.cpp:111:25:111:25 | a | realistic.cpp:41:17:41:17 | o |
| by_reference.cpp:112:8:112:12 | outer [a] | by_reference.cpp:112:14:112:14 | a |
| by_reference.cpp:112:14:112:14 | a | realistic.cpp:41:17:41:17 | o |
| by_reference.cpp:114:8:114:13 | pouter [inner_nested, a] | by_reference.cpp:114:16:114:27 | inner_nested [a] |
| by_reference.cpp:114:16:114:27 | inner_nested [a] | by_reference.cpp:114:29:114:29 | a |
| by_reference.cpp:114:29:114:29 | a | realistic.cpp:41:17:41:17 | o |
| by_reference.cpp:115:8:115:13 | pouter [inner_ptr, a] | by_reference.cpp:115:16:115:24 | inner_ptr [a] |
| by_reference.cpp:115:16:115:24 | inner_ptr [a] | by_reference.cpp:115:27:115:27 | a |
| by_reference.cpp:115:27:115:27 | a | realistic.cpp:41:17:41:17 | o |
| by_reference.cpp:116:8:116:13 | pouter [a] | by_reference.cpp:116:16:116:16 | a |
| by_reference.cpp:116:16:116:16 | a | realistic.cpp:41:17:41:17 | o |
| by_reference.cpp:122:21:122:25 | outer [post update] [inner_nested, a] | by_reference.cpp:130:8:130:12 | outer [inner_nested, a] |
| by_reference.cpp:122:27:122:38 | ref arg inner_nested [a] | by_reference.cpp:122:21:122:25 | outer [post update] [inner_nested, a] |
| by_reference.cpp:123:21:123:36 | ref arg * ... [a] | by_reference.cpp:123:28:123:36 | inner_ptr [inner post update] [a] |
@@ -388,14 +485,20 @@ edges
| by_reference.cpp:128:23:128:23 | ref arg a | by_reference.cpp:128:15:128:20 | pouter [post update] [a] |
| by_reference.cpp:130:8:130:12 | outer [inner_nested, a] | by_reference.cpp:130:14:130:25 | inner_nested [a] |
| by_reference.cpp:130:14:130:25 | inner_nested [a] | by_reference.cpp:130:27:130:27 | a |
| by_reference.cpp:130:27:130:27 | a | realistic.cpp:41:17:41:17 | o |
| by_reference.cpp:131:8:131:12 | outer [inner_ptr, a] | by_reference.cpp:131:14:131:22 | inner_ptr [a] |
| by_reference.cpp:131:14:131:22 | inner_ptr [a] | by_reference.cpp:131:25:131:25 | a |
| by_reference.cpp:131:25:131:25 | a | realistic.cpp:41:17:41:17 | o |
| by_reference.cpp:132:8:132:12 | outer [a] | by_reference.cpp:132:14:132:14 | a |
| by_reference.cpp:132:14:132:14 | a | realistic.cpp:41:17:41:17 | o |
| by_reference.cpp:134:8:134:13 | pouter [inner_nested, a] | by_reference.cpp:134:16:134:27 | inner_nested [a] |
| by_reference.cpp:134:16:134:27 | inner_nested [a] | by_reference.cpp:134:29:134:29 | a |
| by_reference.cpp:134:29:134:29 | a | realistic.cpp:41:17:41:17 | o |
| by_reference.cpp:135:8:135:13 | pouter [inner_ptr, a] | by_reference.cpp:135:16:135:24 | inner_ptr [a] |
| by_reference.cpp:135:16:135:24 | inner_ptr [a] | by_reference.cpp:135:27:135:27 | a |
| by_reference.cpp:135:27:135:27 | a | realistic.cpp:41:17:41:17 | o |
| by_reference.cpp:136:8:136:13 | pouter [a] | by_reference.cpp:136:16:136:16 | a |
| by_reference.cpp:136:16:136:16 | a | realistic.cpp:41:17:41:17 | o |
| complex.cpp:9:7:9:7 | this [a_] | complex.cpp:9:20:9:21 | this [a_] |
| complex.cpp:9:20:9:21 | this [a_] | complex.cpp:9:20:9:21 | a_ |
| complex.cpp:10:7:10:7 | this [b_] | complex.cpp:10:20:10:21 | this [b_] |
@@ -439,26 +542,31 @@ edges
| complex.cpp:65:7:65:8 | b3 [inner, f, a_] | complex.cpp:40:17:40:17 | b [inner, f, a_] |
| complex.cpp:65:7:65:8 | b3 [inner, f, b_] | complex.cpp:40:17:40:17 | b [inner, f, b_] |
| conflated.cpp:19:19:19:21 | ref arg raw | conflated.cpp:20:8:20:10 | raw |
| conflated.cpp:20:8:20:10 | raw | realistic.cpp:41:17:41:17 | o |
| conflated.cpp:29:3:29:4 | pa [post update] [x] | conflated.cpp:30:8:30:9 | pa [x] |
| conflated.cpp:29:3:29:22 | ... = ... | conflated.cpp:29:3:29:4 | pa [post update] [x] |
| conflated.cpp:29:11:29:20 | call to user_input | conflated.cpp:29:3:29:22 | ... = ... |
| conflated.cpp:30:8:30:9 | pa [x] | conflated.cpp:30:12:30:12 | x |
| conflated.cpp:30:12:30:12 | x | realistic.cpp:41:17:41:17 | o |
| conflated.cpp:36:3:36:4 | pa [post update] [x] | conflated.cpp:37:8:37:9 | pa [x] |
| conflated.cpp:36:3:36:22 | ... = ... | conflated.cpp:36:3:36:4 | pa [post update] [x] |
| conflated.cpp:36:11:36:20 | call to user_input | conflated.cpp:36:3:36:22 | ... = ... |
| conflated.cpp:37:8:37:9 | pa [x] | conflated.cpp:37:12:37:12 | x |
| conflated.cpp:37:12:37:12 | x | realistic.cpp:41:17:41:17 | o |
| conflated.cpp:54:3:54:4 | ll [post update] [next, y] | conflated.cpp:55:8:55:9 | ll [next, y] |
| conflated.cpp:54:3:54:28 | ... = ... | conflated.cpp:54:7:54:10 | next [post update] [y] |
| conflated.cpp:54:7:54:10 | next [post update] [y] | conflated.cpp:54:3:54:4 | ll [post update] [next, y] |
| conflated.cpp:54:17:54:26 | call to user_input | conflated.cpp:54:3:54:28 | ... = ... |
| conflated.cpp:55:8:55:9 | ll [next, y] | conflated.cpp:55:12:55:15 | next [y] |
| conflated.cpp:55:12:55:15 | next [y] | conflated.cpp:55:18:55:18 | y |
| conflated.cpp:55:18:55:18 | y | realistic.cpp:41:17:41:17 | o |
| conflated.cpp:60:3:60:4 | ll [post update] [next, y] | conflated.cpp:61:8:61:9 | ll [next, y] |
| conflated.cpp:60:3:60:28 | ... = ... | conflated.cpp:60:7:60:10 | next [post update] [y] |
| conflated.cpp:60:7:60:10 | next [post update] [y] | conflated.cpp:60:3:60:4 | ll [post update] [next, y] |
| conflated.cpp:60:17:60:26 | call to user_input | conflated.cpp:60:3:60:28 | ... = ... |
| conflated.cpp:61:8:61:9 | ll [next, y] | conflated.cpp:61:12:61:15 | next [y] |
| conflated.cpp:61:12:61:15 | next [y] | conflated.cpp:61:18:61:18 | y |
| conflated.cpp:61:18:61:18 | y | realistic.cpp:41:17:41:17 | o |
| constructors.cpp:18:9:18:9 | this [a_] | constructors.cpp:18:22:18:23 | this [a_] |
| constructors.cpp:18:22:18:23 | this [a_] | constructors.cpp:18:22:18:23 | a_ |
| constructors.cpp:19:9:19:9 | this [b_] | constructors.cpp:19:22:19:23 | this [b_] |
@@ -492,6 +600,7 @@ edges
| qualifiers.cpp:9:21:9:25 | value | qualifiers.cpp:9:30:9:44 | ... = ... |
| qualifiers.cpp:9:30:9:44 | ... = ... | qualifiers.cpp:9:30:9:33 | this [post update] [a] |
| qualifiers.cpp:12:40:12:44 | value | qualifiers.cpp:12:49:12:64 | ... = ... |
| qualifiers.cpp:12:49:12:53 | inner [post update] [a] | qualifiers.cpp:12:27:12:31 | inner [a] |
| qualifiers.cpp:12:49:12:64 | ... = ... | qualifiers.cpp:12:49:12:53 | inner [post update] [a] |
| qualifiers.cpp:13:42:13:46 | value | qualifiers.cpp:13:51:13:65 | ... = ... |
| qualifiers.cpp:13:51:13:55 | inner [post update] [a] | qualifiers.cpp:13:29:13:33 | inner [a] |
@@ -502,18 +611,21 @@ edges
| qualifiers.cpp:22:27:22:36 | call to user_input | qualifiers.cpp:22:5:22:38 | ... = ... |
| qualifiers.cpp:23:10:23:14 | outer [inner, a] | qualifiers.cpp:23:16:23:20 | inner [a] |
| qualifiers.cpp:23:16:23:20 | inner [a] | qualifiers.cpp:23:23:23:23 | a |
| qualifiers.cpp:23:23:23:23 | a | realistic.cpp:41:17:41:17 | o |
| qualifiers.cpp:27:5:27:9 | ref arg outer [inner, a] | qualifiers.cpp:28:10:28:14 | outer [inner, a] |
| qualifiers.cpp:27:11:27:18 | ref arg call to getInner [a] | qualifiers.cpp:27:5:27:9 | ref arg outer [inner, a] |
| qualifiers.cpp:27:28:27:37 | call to user_input | qualifiers.cpp:9:21:9:25 | value |
| qualifiers.cpp:27:28:27:37 | call to user_input | qualifiers.cpp:27:11:27:18 | ref arg call to getInner [a] |
| qualifiers.cpp:28:10:28:14 | outer [inner, a] | qualifiers.cpp:28:16:28:20 | inner [a] |
| qualifiers.cpp:28:16:28:20 | inner [a] | qualifiers.cpp:28:23:28:23 | a |
| qualifiers.cpp:28:23:28:23 | a | realistic.cpp:41:17:41:17 | o |
| qualifiers.cpp:32:17:32:21 | ref arg outer [inner, a] | qualifiers.cpp:33:10:33:14 | outer [inner, a] |
| qualifiers.cpp:32:23:32:30 | ref arg call to getInner [a] | qualifiers.cpp:32:17:32:21 | ref arg outer [inner, a] |
| qualifiers.cpp:32:35:32:44 | call to user_input | qualifiers.cpp:12:40:12:44 | value |
| qualifiers.cpp:32:35:32:44 | call to user_input | qualifiers.cpp:32:23:32:30 | ref arg call to getInner [a] |
| qualifiers.cpp:33:10:33:14 | outer [inner, a] | qualifiers.cpp:33:16:33:20 | inner [a] |
| qualifiers.cpp:33:16:33:20 | inner [a] | qualifiers.cpp:33:23:33:23 | a |
| qualifiers.cpp:33:23:33:23 | a | realistic.cpp:41:17:41:17 | o |
| qualifiers.cpp:37:19:37:35 | ref arg * ... [a] | qualifiers.cpp:37:26:37:33 | call to getInner [inner post update] [a] |
| qualifiers.cpp:37:20:37:24 | ref arg outer [inner, a] | qualifiers.cpp:38:10:38:14 | outer [inner, a] |
| qualifiers.cpp:37:26:37:33 | call to getInner [inner post update] [a] | qualifiers.cpp:37:20:37:24 | ref arg outer [inner, a] |
@@ -521,6 +633,7 @@ edges
| qualifiers.cpp:37:38:37:47 | call to user_input | qualifiers.cpp:37:19:37:35 | ref arg * ... [a] |
| qualifiers.cpp:38:10:38:14 | outer [inner, a] | qualifiers.cpp:38:16:38:20 | inner [a] |
| qualifiers.cpp:38:16:38:20 | inner [a] | qualifiers.cpp:38:23:38:23 | a |
| qualifiers.cpp:38:23:38:23 | a | realistic.cpp:41:17:41:17 | o |
| qualifiers.cpp:42:5:42:40 | ... = ... | qualifiers.cpp:42:6:42:22 | * ... [post update] [a] |
| qualifiers.cpp:42:6:42:22 | * ... [post update] [a] | qualifiers.cpp:42:13:42:20 | call to getInner [inner post update] [a] |
| qualifiers.cpp:42:7:42:11 | ref arg outer [inner, a] | qualifiers.cpp:43:10:43:14 | outer [inner, a] |
@@ -528,12 +641,15 @@ edges
| qualifiers.cpp:42:29:42:38 | call to user_input | qualifiers.cpp:42:5:42:40 | ... = ... |
| qualifiers.cpp:43:10:43:14 | outer [inner, a] | qualifiers.cpp:43:16:43:20 | inner [a] |
| qualifiers.cpp:43:16:43:20 | inner [a] | qualifiers.cpp:43:23:43:23 | a |
| qualifiers.cpp:43:23:43:23 | a | realistic.cpp:41:17:41:17 | o |
| qualifiers.cpp:47:5:47:42 | ... = ... | qualifiers.cpp:47:15:47:22 | call to getInner [post update] [a] |
| qualifiers.cpp:47:6:47:11 | ref arg & ... [inner, a] | qualifiers.cpp:48:10:48:14 | outer [inner, a] |
| qualifiers.cpp:47:15:47:22 | call to getInner [post update] [a] | qualifiers.cpp:47:6:47:11 | ref arg & ... [inner, a] |
| qualifiers.cpp:47:31:47:40 | call to user_input | qualifiers.cpp:47:5:47:42 | ... = ... |
| qualifiers.cpp:48:10:48:14 | outer [inner, a] | qualifiers.cpp:48:16:48:20 | inner [a] |
| qualifiers.cpp:48:16:48:20 | inner [a] | qualifiers.cpp:48:23:48:23 | a |
| qualifiers.cpp:48:23:48:23 | a | realistic.cpp:41:17:41:17 | o |
| realistic.cpp:41:17:41:17 | o | realistic.cpp:41:17:41:17 | o |
| realistic.cpp:53:9:53:11 | foo [post update] [bar, baz, userInput, bufferLen] | realistic.cpp:61:21:61:23 | foo [bar, baz, userInput, bufferLen] |
| realistic.cpp:53:9:53:18 | access to array [post update] [baz, userInput, bufferLen] | realistic.cpp:53:13:53:15 | bar [inner post update] [baz, userInput, bufferLen] |
| realistic.cpp:53:9:53:66 | ... = ... | realistic.cpp:53:25:53:33 | userInput [post update] [bufferLen] |
@@ -542,10 +658,19 @@ edges
| realistic.cpp:53:25:53:33 | userInput [post update] [bufferLen] | realistic.cpp:53:20:53:22 | baz [post update] [userInput, bufferLen] |
| realistic.cpp:53:55:53:64 | call to user_input | realistic.cpp:53:9:53:66 | ... = ... |
| realistic.cpp:61:21:61:23 | foo [bar, baz, userInput, bufferLen] | realistic.cpp:61:25:61:27 | bar [baz, userInput, bufferLen] |
| realistic.cpp:61:21:61:23 | foo [post update] [bar, baz, userInput, bufferLen] | realistic.cpp:61:21:61:23 | foo [bar, baz, userInput, bufferLen] |
| realistic.cpp:61:21:61:30 | access to array [baz, userInput, bufferLen] | realistic.cpp:61:32:61:34 | baz [userInput, bufferLen] |
| realistic.cpp:61:21:61:30 | access to array [post update] [baz, userInput, bufferLen] | realistic.cpp:61:25:61:27 | bar [inner post update] [baz, userInput, bufferLen] |
| realistic.cpp:61:25:61:27 | bar [baz, userInput, bufferLen] | realistic.cpp:61:21:61:30 | access to array [baz, userInput, bufferLen] |
| realistic.cpp:61:25:61:27 | bar [inner post update] [baz, userInput, bufferLen] | realistic.cpp:61:21:61:23 | foo [post update] [bar, baz, userInput, bufferLen] |
| realistic.cpp:61:32:61:34 | baz [post update] [userInput, bufferLen] | realistic.cpp:61:21:61:30 | access to array [post update] [baz, userInput, bufferLen] |
| realistic.cpp:61:32:61:34 | baz [userInput, bufferLen] | realistic.cpp:61:37:61:45 | userInput [bufferLen] |
| realistic.cpp:61:37:61:45 | userInput [bufferLen] | realistic.cpp:61:47:61:55 | bufferLen |
| realistic.cpp:61:37:61:45 | userInput [bufferLen] | realistic.cpp:61:47:61:55 | bufferLen |
| realistic.cpp:61:37:61:45 | userInput [post update] [bufferLen] | realistic.cpp:61:32:61:34 | baz [post update] [userInput, bufferLen] |
| realistic.cpp:61:47:61:55 | bufferLen | realistic.cpp:41:17:41:17 | o |
| realistic.cpp:61:47:61:55 | bufferLen | realistic.cpp:61:47:61:55 | ref arg bufferLen |
| realistic.cpp:61:47:61:55 | ref arg bufferLen | realistic.cpp:61:37:61:45 | userInput [post update] [bufferLen] |
| simple.cpp:18:9:18:9 | this [a_] | simple.cpp:18:22:18:23 | this [a_] |
| simple.cpp:18:22:18:23 | this [a_] | simple.cpp:18:22:18:23 | a_ |
| simple.cpp:19:9:19:9 | this [b_] | simple.cpp:19:22:19:23 | this [b_] |
@@ -593,14 +718,28 @@ edges
| simple.cpp:92:5:92:22 | ... = ... | simple.cpp:92:5:92:5 | a [post update] [i] |
| simple.cpp:92:11:92:20 | call to user_input | simple.cpp:92:5:92:22 | ... = ... |
| simple.cpp:94:10:94:11 | a2 [i] | simple.cpp:94:13:94:13 | i |
| struct_init.c:14:24:14:25 | ab [a] | struct_init.c:14:24:14:25 | ab [a] |
| struct_init.c:14:24:14:25 | ab [a] | struct_init.c:15:8:15:9 | ab [a] |
| struct_init.c:15:8:15:9 | ab [a] | struct_init.c:15:12:15:12 | a |
| struct_init.c:15:8:15:9 | ab [a] | struct_init.c:15:12:15:12 | a |
| struct_init.c:15:8:15:9 | ab [post update] [a] | struct_init.c:14:24:14:25 | ab [a] |
| struct_init.c:15:12:15:12 | a | realistic.cpp:41:17:41:17 | o |
| struct_init.c:15:12:15:12 | a | struct_init.c:15:12:15:12 | ref arg a |
| struct_init.c:15:12:15:12 | ref arg a | struct_init.c:15:8:15:9 | ab [post update] [a] |
| struct_init.c:20:17:20:36 | {...} [a] | struct_init.c:22:8:22:9 | ab [a] |
| struct_init.c:20:17:20:36 | {...} [a] | struct_init.c:24:10:24:12 | & ... [a] |
| struct_init.c:20:17:20:36 | {...} [a] | struct_init.c:28:5:28:7 | & ... [a] |
| struct_init.c:20:20:20:29 | call to user_input | struct_init.c:20:17:20:36 | {...} [a] |
| struct_init.c:22:8:22:9 | ab [a] | struct_init.c:22:11:22:11 | a |
| struct_init.c:22:8:22:9 | ab [a] | struct_init.c:22:11:22:11 | a |
| struct_init.c:22:8:22:9 | ab [post update] [a] | struct_init.c:24:10:24:12 | & ... [a] |
| struct_init.c:22:8:22:9 | ab [post update] [a] | struct_init.c:28:5:28:7 | & ... [a] |
| struct_init.c:22:11:22:11 | a | realistic.cpp:41:17:41:17 | o |
| struct_init.c:22:11:22:11 | a | struct_init.c:22:11:22:11 | ref arg a |
| struct_init.c:22:11:22:11 | ref arg a | struct_init.c:22:8:22:9 | ab [post update] [a] |
| struct_init.c:24:10:24:12 | & ... [a] | struct_init.c:14:24:14:25 | ab [a] |
| struct_init.c:24:10:24:12 | & ... [a] | struct_init.c:24:10:24:12 | ref arg & ... [a] |
| struct_init.c:24:10:24:12 | ref arg & ... [a] | struct_init.c:28:5:28:7 | & ... [a] |
| struct_init.c:26:23:29:3 | {...} [nestedAB, a] | struct_init.c:31:8:31:12 | outer [nestedAB, a] |
| struct_init.c:26:23:29:3 | {...} [nestedAB, a] | struct_init.c:36:11:36:15 | outer [nestedAB, a] |
| struct_init.c:26:23:29:3 | {...} [pointerAB, a] | struct_init.c:33:8:33:12 | outer [pointerAB, a] |
@@ -608,9 +747,16 @@ edges
| struct_init.c:27:7:27:16 | call to user_input | struct_init.c:27:5:27:23 | {...} [a] |
| struct_init.c:28:5:28:7 | & ... [a] | struct_init.c:26:23:29:3 | {...} [pointerAB, a] |
| struct_init.c:31:8:31:12 | outer [nestedAB, a] | struct_init.c:31:14:31:21 | nestedAB [a] |
| struct_init.c:31:8:31:12 | outer [post update] [nestedAB, a] | struct_init.c:36:11:36:15 | outer [nestedAB, a] |
| struct_init.c:31:14:31:21 | nestedAB [a] | struct_init.c:31:23:31:23 | a |
| struct_init.c:31:14:31:21 | nestedAB [a] | struct_init.c:31:23:31:23 | a |
| struct_init.c:31:14:31:21 | nestedAB [post update] [a] | struct_init.c:31:8:31:12 | outer [post update] [nestedAB, a] |
| struct_init.c:31:23:31:23 | a | realistic.cpp:41:17:41:17 | o |
| struct_init.c:31:23:31:23 | a | struct_init.c:31:23:31:23 | ref arg a |
| struct_init.c:31:23:31:23 | ref arg a | struct_init.c:31:14:31:21 | nestedAB [post update] [a] |
| struct_init.c:33:8:33:12 | outer [pointerAB, a] | struct_init.c:33:14:33:22 | pointerAB [a] |
| struct_init.c:33:14:33:22 | pointerAB [a] | struct_init.c:33:25:33:25 | a |
| struct_init.c:33:25:33:25 | a | realistic.cpp:41:17:41:17 | o |
| struct_init.c:36:10:36:24 | & ... [a] | struct_init.c:14:24:14:25 | ab [a] |
| struct_init.c:36:11:36:15 | outer [nestedAB, a] | struct_init.c:36:17:36:24 | nestedAB [a] |
| struct_init.c:36:17:36:24 | nestedAB [a] | struct_init.c:36:10:36:24 | & ... [a] |
@@ -674,12 +820,14 @@ nodes
| A.cpp:107:16:107:16 | a | semmle.label | a |
| A.cpp:120:12:120:13 | c1 [a] | semmle.label | c1 [a] |
| A.cpp:120:16:120:16 | a | semmle.label | a |
| A.cpp:124:14:124:14 | b [c] | semmle.label | b [c] |
| A.cpp:126:5:126:5 | ref arg b [c] | semmle.label | ref arg b [c] |
| A.cpp:126:12:126:18 | new | semmle.label | new |
| A.cpp:131:8:131:8 | ref arg b [c] | semmle.label | ref arg b [c] |
| A.cpp:132:10:132:10 | b [c] | semmle.label | b [c] |
| A.cpp:132:13:132:13 | c | semmle.label | c |
| A.cpp:140:13:140:13 | b | semmle.label | b |
| A.cpp:140:13:140:13 | b [c] | semmle.label | b [c] |
| A.cpp:142:7:142:7 | b [post update] [c] | semmle.label | b [post update] [c] |
| A.cpp:142:7:142:20 | ... = ... | semmle.label | ... = ... |
| A.cpp:142:14:142:20 | new | semmle.label | new |
@@ -695,8 +843,12 @@ nodes
| A.cpp:151:12:151:24 | call to D [b] | semmle.label | call to D [b] |
| A.cpp:151:18:151:18 | b | semmle.label | b |
| A.cpp:151:18:151:18 | ref arg b [c] | semmle.label | ref arg b [c] |
| A.cpp:152:10:152:10 | d [b, c] | semmle.label | d [b, c] |
| A.cpp:152:10:152:10 | d [b] | semmle.label | d [b] |
| A.cpp:152:10:152:10 | d [post update] [b, c] | semmle.label | d [post update] [b, c] |
| A.cpp:152:13:152:13 | b | semmle.label | b |
| A.cpp:152:13:152:13 | b [c] | semmle.label | b [c] |
| A.cpp:152:13:152:13 | ref arg b [c] | semmle.label | ref arg b [c] |
| A.cpp:153:10:153:10 | d [b, c] | semmle.label | d [b, c] |
| A.cpp:153:13:153:13 | b [c] | semmle.label | b [c] |
| A.cpp:153:16:153:16 | c | semmle.label | c |
@@ -710,15 +862,24 @@ nodes
| A.cpp:162:18:162:40 | call to MyList [next, next, head] | semmle.label | call to MyList [next, next, head] |
| A.cpp:162:38:162:39 | l2 [next, head] | semmle.label | l2 [next, head] |
| A.cpp:165:10:165:11 | l3 [next, next, head] | semmle.label | l3 [next, next, head] |
| A.cpp:165:10:165:11 | l3 [post update] [next, next, head] | semmle.label | l3 [post update] [next, next, head] |
| A.cpp:165:14:165:17 | next [next, head] | semmle.label | next [next, head] |
| A.cpp:165:14:165:17 | next [post update] [next, head] | semmle.label | next [post update] [next, head] |
| A.cpp:165:20:165:23 | next [head] | semmle.label | next [head] |
| A.cpp:165:20:165:23 | next [post update] [head] | semmle.label | next [post update] [head] |
| A.cpp:165:26:165:29 | head | semmle.label | head |
| A.cpp:165:26:165:29 | head | semmle.label | head |
| A.cpp:165:26:165:29 | ref arg head | semmle.label | ref arg head |
| A.cpp:167:44:167:44 | l [next, head] | semmle.label | l [next, head] |
| A.cpp:167:44:167:44 | l [next, next, head] | semmle.label | l [next, next, head] |
| A.cpp:167:47:167:50 | next [head] | semmle.label | next [head] |
| A.cpp:167:47:167:50 | next [next, head] | semmle.label | next [next, head] |
| A.cpp:169:12:169:12 | l [head] | semmle.label | l [head] |
| A.cpp:169:15:169:18 | head | semmle.label | head |
| A.cpp:173:26:173:26 | o | semmle.label | o |
| A.cpp:173:26:173:26 | o | semmle.label | o |
| A.cpp:173:26:173:26 | o [c] | semmle.label | o [c] |
| A.cpp:173:26:173:26 | o [c] | semmle.label | o [c] |
| A.cpp:181:15:181:21 | newHead | semmle.label | newHead |
| A.cpp:181:32:181:35 | next [head] | semmle.label | next [head] |
| A.cpp:181:32:181:35 | next [next, head] | semmle.label | next [next, head] |
@@ -829,6 +990,7 @@ nodes
| E.cpp:32:10:32:10 | b [buffer] | semmle.label | b [buffer] |
| E.cpp:32:13:32:18 | buffer | semmle.label | buffer |
| E.cpp:33:18:33:19 | & ... [data, buffer] | semmle.label | & ... [data, buffer] |
| aliasing.cpp:8:23:8:23 | s [m1] | semmle.label | s [m1] |
| aliasing.cpp:9:3:9:3 | s [post update] [m1] | semmle.label | s [post update] [m1] |
| aliasing.cpp:9:3:9:22 | ... = ... | semmle.label | ... = ... |
| aliasing.cpp:9:11:9:20 | call to user_input | semmle.label | call to user_input |
@@ -854,6 +1016,7 @@ nodes
| aliasing.cpp:93:8:93:8 | w [s, m1] | semmle.label | w [s, m1] |
| aliasing.cpp:93:10:93:10 | s [m1] | semmle.label | s [m1] |
| aliasing.cpp:93:12:93:13 | m1 | semmle.label | m1 |
| aliasing.cpp:105:23:105:24 | pa | semmle.label | pa |
| aliasing.cpp:106:4:106:5 | pa [inner post update] | semmle.label | pa [inner post update] |
| aliasing.cpp:106:9:106:18 | call to user_input | semmle.label | call to user_input |
| aliasing.cpp:158:15:158:15 | s [post update] [data] | semmle.label | s [post update] [data] |
@@ -902,10 +1065,16 @@ nodes
| arrays.cpp:36:12:36:14 | arr [inner post update] [data] | semmle.label | arr [inner post update] [data] |
| arrays.cpp:36:26:36:35 | call to user_input | semmle.label | call to user_input |
| arrays.cpp:37:8:37:8 | o [nested, arr, data] | semmle.label | o [nested, arr, data] |
| arrays.cpp:37:8:37:8 | o [post update] [nested, arr, data] | semmle.label | o [post update] [nested, arr, data] |
| arrays.cpp:37:8:37:22 | access to array [data] | semmle.label | access to array [data] |
| arrays.cpp:37:8:37:22 | access to array [post update] [data] | semmle.label | access to array [post update] [data] |
| arrays.cpp:37:10:37:15 | nested [arr, data] | semmle.label | nested [arr, data] |
| arrays.cpp:37:10:37:15 | nested [post update] [arr, data] | semmle.label | nested [post update] [arr, data] |
| arrays.cpp:37:17:37:19 | arr [data] | semmle.label | arr [data] |
| arrays.cpp:37:17:37:19 | arr [inner post update] [data] | semmle.label | arr [inner post update] [data] |
| arrays.cpp:37:24:37:27 | data | semmle.label | data |
| arrays.cpp:37:24:37:27 | data | semmle.label | data |
| arrays.cpp:37:24:37:27 | ref arg data | semmle.label | ref arg data |
| arrays.cpp:38:8:38:8 | o [nested, arr, data] | semmle.label | o [nested, arr, data] |
| arrays.cpp:38:8:38:22 | access to array [data] | semmle.label | access to array [data] |
| arrays.cpp:38:10:38:15 | nested [arr, data] | semmle.label | nested [arr, data] |
@@ -918,15 +1087,22 @@ nodes
| arrays.cpp:42:15:42:17 | arr [inner post update] [data] | semmle.label | arr [inner post update] [data] |
| arrays.cpp:42:29:42:38 | call to user_input | semmle.label | call to user_input |
| arrays.cpp:43:8:43:8 | o [indirect, arr, data] | semmle.label | o [indirect, arr, data] |
| arrays.cpp:43:8:43:8 | o [post update] [indirect, arr, data] | semmle.label | o [post update] [indirect, arr, data] |
| arrays.cpp:43:8:43:25 | access to array [data] | semmle.label | access to array [data] |
| arrays.cpp:43:8:43:25 | access to array [post update] [data] | semmle.label | access to array [post update] [data] |
| arrays.cpp:43:10:43:17 | indirect [arr, data] | semmle.label | indirect [arr, data] |
| arrays.cpp:43:10:43:17 | indirect [post update] [arr, data] | semmle.label | indirect [post update] [arr, data] |
| arrays.cpp:43:20:43:22 | arr [data] | semmle.label | arr [data] |
| arrays.cpp:43:20:43:22 | arr [inner post update] [data] | semmle.label | arr [inner post update] [data] |
| arrays.cpp:43:27:43:30 | data | semmle.label | data |
| arrays.cpp:43:27:43:30 | data | semmle.label | data |
| arrays.cpp:43:27:43:30 | ref arg data | semmle.label | ref arg data |
| arrays.cpp:44:8:44:8 | o [indirect, arr, data] | semmle.label | o [indirect, arr, data] |
| arrays.cpp:44:8:44:25 | access to array [data] | semmle.label | access to array [data] |
| arrays.cpp:44:10:44:17 | indirect [arr, data] | semmle.label | indirect [arr, data] |
| arrays.cpp:44:20:44:22 | arr [data] | semmle.label | arr [data] |
| arrays.cpp:44:27:44:30 | data | semmle.label | data |
| by_reference.cpp:11:39:11:39 | s [a] | semmle.label | s [a] |
| by_reference.cpp:11:48:11:52 | value | semmle.label | value |
| by_reference.cpp:12:5:12:5 | s [post update] [a] | semmle.label | s [post update] [a] |
| by_reference.cpp:12:5:12:16 | ... = ... | semmle.label | ... = ... |
@@ -967,6 +1143,7 @@ nodes
| by_reference.cpp:68:21:68:30 | call to user_input | semmle.label | call to user_input |
| by_reference.cpp:69:8:69:20 | call to nonMemberGetA | semmle.label | call to nonMemberGetA |
| by_reference.cpp:69:22:69:23 | & ... [a] | semmle.label | & ... [a] |
| by_reference.cpp:83:31:83:35 | inner [a] | semmle.label | inner [a] |
| by_reference.cpp:84:3:84:7 | inner [post update] [a] | semmle.label | inner [post update] [a] |
| by_reference.cpp:84:3:84:25 | ... = ... | semmle.label | ... = ... |
| by_reference.cpp:84:14:84:23 | call to user_input | semmle.label | call to user_input |
@@ -974,6 +1151,7 @@ nodes
| by_reference.cpp:88:3:88:7 | inner [post update] [a] | semmle.label | inner [post update] [a] |
| by_reference.cpp:88:3:88:24 | ... = ... | semmle.label | ... = ... |
| by_reference.cpp:88:13:88:22 | call to user_input | semmle.label | call to user_input |
| by_reference.cpp:91:25:91:26 | pa | semmle.label | pa |
| by_reference.cpp:92:4:92:5 | pa [inner post update] | semmle.label | pa [inner post update] |
| by_reference.cpp:92:9:92:18 | call to user_input | semmle.label | call to user_input |
| by_reference.cpp:95:25:95:26 | pa | semmle.label | pa |
@@ -1141,6 +1319,7 @@ nodes
| qualifiers.cpp:9:21:9:25 | value | semmle.label | value |
| qualifiers.cpp:9:30:9:33 | this [post update] [a] | semmle.label | this [post update] [a] |
| qualifiers.cpp:9:30:9:44 | ... = ... | semmle.label | ... = ... |
| qualifiers.cpp:12:27:12:31 | inner [a] | semmle.label | inner [a] |
| qualifiers.cpp:12:40:12:44 | value | semmle.label | value |
| qualifiers.cpp:12:49:12:53 | inner [post update] [a] | semmle.label | inner [post update] [a] |
| qualifiers.cpp:12:49:12:64 | ... = ... | semmle.label | ... = ... |
@@ -1189,6 +1368,8 @@ nodes
| qualifiers.cpp:48:10:48:14 | outer [inner, a] | semmle.label | outer [inner, a] |
| qualifiers.cpp:48:16:48:20 | inner [a] | semmle.label | inner [a] |
| qualifiers.cpp:48:23:48:23 | a | semmle.label | a |
| realistic.cpp:41:17:41:17 | o | semmle.label | o |
| realistic.cpp:41:17:41:17 | o | semmle.label | o |
| realistic.cpp:53:9:53:11 | foo [post update] [bar, baz, userInput, bufferLen] | semmle.label | foo [post update] [bar, baz, userInput, bufferLen] |
| realistic.cpp:53:9:53:18 | access to array [post update] [baz, userInput, bufferLen] | semmle.label | access to array [post update] [baz, userInput, bufferLen] |
| realistic.cpp:53:9:53:66 | ... = ... | semmle.label | ... = ... |
@@ -1197,11 +1378,18 @@ nodes
| realistic.cpp:53:25:53:33 | userInput [post update] [bufferLen] | semmle.label | userInput [post update] [bufferLen] |
| realistic.cpp:53:55:53:64 | call to user_input | semmle.label | call to user_input |
| realistic.cpp:61:21:61:23 | foo [bar, baz, userInput, bufferLen] | semmle.label | foo [bar, baz, userInput, bufferLen] |
| realistic.cpp:61:21:61:23 | foo [post update] [bar, baz, userInput, bufferLen] | semmle.label | foo [post update] [bar, baz, userInput, bufferLen] |
| realistic.cpp:61:21:61:30 | access to array [baz, userInput, bufferLen] | semmle.label | access to array [baz, userInput, bufferLen] |
| realistic.cpp:61:21:61:30 | access to array [post update] [baz, userInput, bufferLen] | semmle.label | access to array [post update] [baz, userInput, bufferLen] |
| realistic.cpp:61:25:61:27 | bar [baz, userInput, bufferLen] | semmle.label | bar [baz, userInput, bufferLen] |
| realistic.cpp:61:25:61:27 | bar [inner post update] [baz, userInput, bufferLen] | semmle.label | bar [inner post update] [baz, userInput, bufferLen] |
| realistic.cpp:61:32:61:34 | baz [post update] [userInput, bufferLen] | semmle.label | baz [post update] [userInput, bufferLen] |
| realistic.cpp:61:32:61:34 | baz [userInput, bufferLen] | semmle.label | baz [userInput, bufferLen] |
| realistic.cpp:61:37:61:45 | userInput [bufferLen] | semmle.label | userInput [bufferLen] |
| realistic.cpp:61:37:61:45 | userInput [post update] [bufferLen] | semmle.label | userInput [post update] [bufferLen] |
| realistic.cpp:61:47:61:55 | bufferLen | semmle.label | bufferLen |
| realistic.cpp:61:47:61:55 | bufferLen | semmle.label | bufferLen |
| realistic.cpp:61:47:61:55 | ref arg bufferLen | semmle.label | ref arg bufferLen |
| simple.cpp:18:9:18:9 | this [a_] | semmle.label | this [a_] |
| simple.cpp:18:22:18:23 | a_ | semmle.label | a_ |
| simple.cpp:18:22:18:23 | this [a_] | semmle.label | this [a_] |
@@ -1253,21 +1441,33 @@ nodes
| simple.cpp:94:10:94:11 | a2 [i] | semmle.label | a2 [i] |
| simple.cpp:94:13:94:13 | i | semmle.label | i |
| struct_init.c:14:24:14:25 | ab [a] | semmle.label | ab [a] |
| struct_init.c:14:24:14:25 | ab [a] | semmle.label | ab [a] |
| struct_init.c:15:8:15:9 | ab [a] | semmle.label | ab [a] |
| struct_init.c:15:8:15:9 | ab [post update] [a] | semmle.label | ab [post update] [a] |
| struct_init.c:15:12:15:12 | a | semmle.label | a |
| struct_init.c:15:12:15:12 | a | semmle.label | a |
| struct_init.c:15:12:15:12 | ref arg a | semmle.label | ref arg a |
| struct_init.c:20:17:20:36 | {...} [a] | semmle.label | {...} [a] |
| struct_init.c:20:20:20:29 | call to user_input | semmle.label | call to user_input |
| struct_init.c:22:8:22:9 | ab [a] | semmle.label | ab [a] |
| struct_init.c:22:8:22:9 | ab [post update] [a] | semmle.label | ab [post update] [a] |
| struct_init.c:22:11:22:11 | a | semmle.label | a |
| struct_init.c:22:11:22:11 | a | semmle.label | a |
| struct_init.c:22:11:22:11 | ref arg a | semmle.label | ref arg a |
| struct_init.c:24:10:24:12 | & ... [a] | semmle.label | & ... [a] |
| struct_init.c:24:10:24:12 | ref arg & ... [a] | semmle.label | ref arg & ... [a] |
| struct_init.c:26:23:29:3 | {...} [nestedAB, a] | semmle.label | {...} [nestedAB, a] |
| struct_init.c:26:23:29:3 | {...} [pointerAB, a] | semmle.label | {...} [pointerAB, a] |
| struct_init.c:27:5:27:23 | {...} [a] | semmle.label | {...} [a] |
| struct_init.c:27:7:27:16 | call to user_input | semmle.label | call to user_input |
| struct_init.c:28:5:28:7 | & ... [a] | semmle.label | & ... [a] |
| struct_init.c:31:8:31:12 | outer [nestedAB, a] | semmle.label | outer [nestedAB, a] |
| struct_init.c:31:8:31:12 | outer [post update] [nestedAB, a] | semmle.label | outer [post update] [nestedAB, a] |
| struct_init.c:31:14:31:21 | nestedAB [a] | semmle.label | nestedAB [a] |
| struct_init.c:31:14:31:21 | nestedAB [post update] [a] | semmle.label | nestedAB [post update] [a] |
| struct_init.c:31:23:31:23 | a | semmle.label | a |
| struct_init.c:31:23:31:23 | a | semmle.label | a |
| struct_init.c:31:23:31:23 | ref arg a | semmle.label | ref arg a |
| struct_init.c:33:8:33:12 | outer [pointerAB, a] | semmle.label | outer [pointerAB, a] |
| struct_init.c:33:14:33:22 | pointerAB [a] | semmle.label | pointerAB [a] |
| struct_init.c:33:25:33:25 | a | semmle.label | a |
@@ -1293,9 +1493,11 @@ subpaths
| A.cpp:90:15:90:15 | c | A.cpp:27:17:27:17 | c | A.cpp:27:22:27:25 | this [post update] [c] | A.cpp:90:7:90:8 | ref arg b2 [c] |
| A.cpp:126:12:126:18 | new | A.cpp:27:17:27:17 | c | A.cpp:27:22:27:25 | this [post update] [c] | A.cpp:126:5:126:5 | ref arg b [c] |
| A.cpp:151:18:151:18 | b | A.cpp:140:13:140:13 | b | A.cpp:143:7:143:10 | this [post update] [b] | A.cpp:151:12:151:24 | call to D [b] |
| A.cpp:152:13:152:13 | b [c] | A.cpp:173:26:173:26 | o [c] | A.cpp:173:26:173:26 | o [c] | A.cpp:152:13:152:13 | ref arg b [c] |
| A.cpp:160:29:160:29 | b | A.cpp:181:15:181:21 | newHead | A.cpp:183:7:183:10 | this [post update] [head] | A.cpp:160:18:160:60 | call to MyList [head] |
| A.cpp:161:38:161:39 | l1 [head] | A.cpp:181:32:181:35 | next [head] | A.cpp:184:7:184:10 | this [post update] [next, head] | A.cpp:161:18:161:40 | call to MyList [next, head] |
| A.cpp:162:38:162:39 | l2 [next, head] | A.cpp:181:32:181:35 | next [next, head] | A.cpp:184:7:184:10 | this [post update] [next, next, head] | A.cpp:162:18:162:40 | call to MyList [next, next, head] |
| A.cpp:165:26:165:29 | head | A.cpp:173:26:173:26 | o | A.cpp:173:26:173:26 | o | A.cpp:165:26:165:29 | ref arg head |
| B.cpp:7:25:7:25 | e | B.cpp:33:16:33:17 | e1 | B.cpp:35:7:35:10 | this [post update] [elem1] | B.cpp:7:16:7:35 | call to Box1 [elem1] |
| B.cpp:8:25:8:26 | b1 [elem1] | B.cpp:44:16:44:17 | b1 [elem1] | B.cpp:46:7:46:10 | this [post update] [box1, elem1] | B.cpp:8:16:8:27 | call to Box2 [box1, elem1] |
| B.cpp:16:37:16:37 | e | B.cpp:33:26:33:27 | e2 | B.cpp:36:7:36:10 | this [post update] [elem2] | B.cpp:16:16:16:38 | call to Box1 [elem2] |
@@ -1304,7 +1506,10 @@ subpaths
| D.cpp:22:14:22:20 | call to getBox1 [elem] | D.cpp:10:11:10:17 | this [elem] | D.cpp:10:30:10:33 | elem | D.cpp:22:25:22:31 | call to getElem |
| D.cpp:37:21:37:21 | e | D.cpp:11:24:11:24 | e | D.cpp:11:29:11:32 | this [post update] [elem] | D.cpp:37:8:37:10 | ref arg box [elem] |
| D.cpp:51:27:51:27 | e | D.cpp:11:24:11:24 | e | D.cpp:11:29:11:32 | this [post update] [elem] | D.cpp:51:8:51:14 | ref arg call to getBox1 [elem] |
| arrays.cpp:37:24:37:27 | data | realistic.cpp:41:17:41:17 | o | realistic.cpp:41:17:41:17 | o | arrays.cpp:37:24:37:27 | ref arg data |
| arrays.cpp:43:27:43:30 | data | realistic.cpp:41:17:41:17 | o | realistic.cpp:41:17:41:17 | o | arrays.cpp:43:27:43:30 | ref arg data |
| by_reference.cpp:20:23:20:27 | value | by_reference.cpp:15:26:15:30 | value | by_reference.cpp:16:5:16:8 | this [post update] [a] | by_reference.cpp:20:5:20:8 | ref arg this [a] |
| by_reference.cpp:24:25:24:29 | value | by_reference.cpp:11:48:11:52 | value | by_reference.cpp:11:39:11:39 | s [a] | by_reference.cpp:24:19:24:22 | ref arg this [a] |
| by_reference.cpp:24:25:24:29 | value | by_reference.cpp:11:48:11:52 | value | by_reference.cpp:12:5:12:5 | s [post update] [a] | by_reference.cpp:24:19:24:22 | ref arg this [a] |
| by_reference.cpp:40:12:40:15 | this [a] | by_reference.cpp:35:9:35:19 | this [a] | by_reference.cpp:36:18:36:18 | a | by_reference.cpp:40:18:40:28 | call to getDirectly |
| by_reference.cpp:44:26:44:29 | this [a] | by_reference.cpp:31:46:31:46 | s [a] | by_reference.cpp:32:15:32:15 | a | by_reference.cpp:44:12:44:24 | call to nonMemberGetA |
@@ -1314,6 +1519,7 @@ subpaths
| by_reference.cpp:57:8:57:8 | s [a] | by_reference.cpp:39:9:39:21 | this [a] | by_reference.cpp:40:18:40:28 | call to getDirectly | by_reference.cpp:57:10:57:22 | call to getIndirectly |
| by_reference.cpp:62:25:62:34 | call to user_input | by_reference.cpp:23:34:23:38 | value | by_reference.cpp:24:19:24:22 | ref arg this [a] | by_reference.cpp:62:3:62:3 | ref arg s [a] |
| by_reference.cpp:63:8:63:8 | s [a] | by_reference.cpp:43:9:43:27 | this [a] | by_reference.cpp:44:12:44:24 | call to nonMemberGetA | by_reference.cpp:63:10:63:28 | call to getThroughNonMember |
| by_reference.cpp:68:21:68:30 | call to user_input | by_reference.cpp:11:48:11:52 | value | by_reference.cpp:11:39:11:39 | s [a] | by_reference.cpp:68:17:68:18 | ref arg & ... [a] |
| by_reference.cpp:68:21:68:30 | call to user_input | by_reference.cpp:11:48:11:52 | value | by_reference.cpp:12:5:12:5 | s [post update] [a] | by_reference.cpp:68:17:68:18 | ref arg & ... [a] |
| by_reference.cpp:69:22:69:23 | & ... [a] | by_reference.cpp:31:46:31:46 | s [a] | by_reference.cpp:32:15:32:15 | a | by_reference.cpp:69:8:69:20 | call to nonMemberGetA |
| complex.cpp:42:16:42:16 | f [a_] | complex.cpp:9:7:9:7 | this [a_] | complex.cpp:9:20:9:21 | a_ | complex.cpp:42:18:42:18 | call to a |
@@ -1329,9 +1535,11 @@ subpaths
| constructors.cpp:36:11:36:20 | call to user_input | constructors.cpp:23:13:23:13 | a | constructors.cpp:23:25:23:29 | constructor init of field a_ [post-this] [a_] | constructors.cpp:36:11:36:37 | call to Foo [a_] |
| constructors.cpp:36:25:36:34 | call to user_input | constructors.cpp:23:20:23:20 | b | constructors.cpp:23:32:23:36 | constructor init of field b_ [post-this] [b_] | constructors.cpp:36:11:36:37 | call to Foo [b_] |
| qualifiers.cpp:27:28:27:37 | call to user_input | qualifiers.cpp:9:21:9:25 | value | qualifiers.cpp:9:30:9:33 | this [post update] [a] | qualifiers.cpp:27:11:27:18 | ref arg call to getInner [a] |
| qualifiers.cpp:32:35:32:44 | call to user_input | qualifiers.cpp:12:40:12:44 | value | qualifiers.cpp:12:27:12:31 | inner [a] | qualifiers.cpp:32:23:32:30 | ref arg call to getInner [a] |
| qualifiers.cpp:32:35:32:44 | call to user_input | qualifiers.cpp:12:40:12:44 | value | qualifiers.cpp:12:49:12:53 | inner [post update] [a] | qualifiers.cpp:32:23:32:30 | ref arg call to getInner [a] |
| qualifiers.cpp:37:38:37:47 | call to user_input | qualifiers.cpp:13:42:13:46 | value | qualifiers.cpp:13:29:13:33 | inner [a] | qualifiers.cpp:37:19:37:35 | ref arg * ... [a] |
| qualifiers.cpp:37:38:37:47 | call to user_input | qualifiers.cpp:13:42:13:46 | value | qualifiers.cpp:13:51:13:55 | inner [post update] [a] | qualifiers.cpp:37:19:37:35 | ref arg * ... [a] |
| realistic.cpp:61:47:61:55 | bufferLen | realistic.cpp:41:17:41:17 | o | realistic.cpp:41:17:41:17 | o | realistic.cpp:61:47:61:55 | ref arg bufferLen |
| simple.cpp:28:10:28:10 | f [a_] | simple.cpp:18:9:18:9 | this [a_] | simple.cpp:18:22:18:23 | a_ | simple.cpp:28:12:28:12 | call to a |
| simple.cpp:29:10:29:10 | f [b_] | simple.cpp:19:9:19:9 | this [b_] | simple.cpp:19:22:19:23 | b_ | simple.cpp:29:12:29:12 | call to b |
| simple.cpp:39:12:39:21 | call to user_input | simple.cpp:20:19:20:19 | a | simple.cpp:20:24:20:25 | this [post update] [a_] | simple.cpp:39:5:39:5 | ref arg f [a_] |
@@ -1339,6 +1547,10 @@ subpaths
| simple.cpp:41:12:41:21 | call to user_input | simple.cpp:20:19:20:19 | a | simple.cpp:20:24:20:25 | this [post update] [a_] | simple.cpp:41:5:41:5 | ref arg h [a_] |
| simple.cpp:42:12:42:21 | call to user_input | simple.cpp:21:19:21:19 | b | simple.cpp:21:24:21:25 | this [post update] [b_] | simple.cpp:42:5:42:5 | ref arg h [b_] |
| simple.cpp:84:14:84:20 | this [f2, f1] | simple.cpp:78:9:78:15 | this [f2, f1] | simple.cpp:79:19:79:20 | f1 | simple.cpp:84:14:84:20 | call to getf2f1 |
| struct_init.c:15:12:15:12 | a | realistic.cpp:41:17:41:17 | o | realistic.cpp:41:17:41:17 | o | struct_init.c:15:12:15:12 | ref arg a |
| struct_init.c:22:11:22:11 | a | realistic.cpp:41:17:41:17 | o | realistic.cpp:41:17:41:17 | o | struct_init.c:22:11:22:11 | ref arg a |
| struct_init.c:24:10:24:12 | & ... [a] | struct_init.c:14:24:14:25 | ab [a] | struct_init.c:14:24:14:25 | ab [a] | struct_init.c:24:10:24:12 | ref arg & ... [a] |
| struct_init.c:31:23:31:23 | a | realistic.cpp:41:17:41:17 | o | realistic.cpp:41:17:41:17 | o | struct_init.c:31:23:31:23 | ref arg a |
#select
| A.cpp:43:10:43:12 | & ... | A.cpp:41:15:41:21 | new | A.cpp:43:10:43:12 | & ... | & ... flows from $@ | A.cpp:41:15:41:21 | new | new |
| A.cpp:49:13:49:13 | c | A.cpp:47:12:47:18 | new | A.cpp:49:13:49:13 | c | c flows from $@ | A.cpp:47:12:47:18 | new | new |

View File

@@ -20,31 +20,31 @@ namespace qualifiers {
void assignToGetter(Outer outer) {
outer.getInner()->a = user_input();
sink(outer.inner->a); // $ ast MISSING: ir
sink(outer.inner->a); // $ ast,ir
}
void getterArgument1(Outer outer) {
outer.getInner()->setA(user_input());
sink(outer.inner->a); // $ ast MISSING: ir
sink(outer.inner->a); // $ ast,ir
}
void getterArgument2(Outer outer) {
pointerSetA(outer.getInner(), user_input());
sink(outer.inner->a); // $ ast MISSING: ir
sink(outer.inner->a); // $ ast,ir
}
void getterArgument2Ref(Outer outer) {
referenceSetA(*outer.getInner(), user_input());
sink(outer.inner->a); // $ ast MISSING: ir
sink(outer.inner->a); // $ ast,ir
}
void assignToGetterStar(Outer outer) {
(*outer.getInner()).a = user_input();
sink(outer.inner->a); // $ ast MISSING: ir
sink(outer.inner->a); // $ ast,ir
}
void assignToGetterAmp(Outer outer) {
(&outer)->getInner()->a = user_input();
sink(outer.inner->a); // $ ast MISSING: ir
sink(outer.inner->a); // $ ast,ir
}
}

View File

@@ -58,7 +58,7 @@ int main(int argc, char** argv) {
return -1;
}
memcpy(dst, foo.bar[i].baz->userInput.buffer, foo.bar[i].baz->userInput.bufferLen);
sink((void*)foo.bar[i].baz->userInput.bufferLen); // $ ast MISSING: ir
sink((void*)foo.bar[i].baz->userInput.bufferLen); // $ ast ir=53:47 ir=53:55
// There is no flow to the following two `sink` calls because the
// source is the _pointer_ returned by `user_input` rather than the
// _data_ to which it points.

View File

@@ -12,7 +12,7 @@ struct Outer {
};
void absink(struct AB *ab) {
sink(ab->a); //$ ast,ir=20:20 ast,ir=27:7 ast=40:20 MISSING: ir
sink(ab->a); //$ ast,ir=20:20 ast,ir=27:7 ast,ir=40:20
sink(ab->b); // no flow
}
@@ -30,7 +30,7 @@ int struct_init(void) {
sink(outer.nestedAB.a); //$ ast,ir
sink(outer.nestedAB.b); // no flow
sink(outer.pointerAB->a); //$ ast MISSING: ir
sink(outer.pointerAB->a); //$ ast,ir
sink(outer.pointerAB->b); // no flow
absink(&outer.nestedAB);

View File

@@ -10,6 +10,10 @@
| test.cpp:49:23:49:28 | call to getenv | test.cpp:50:29:50:40 | envStrGlobal | AST only |
| test.cpp:49:23:49:28 | call to getenv | test.cpp:52:2:52:12 | * ... | AST only |
| test.cpp:49:23:49:28 | call to getenv | test.cpp:52:3:52:12 | envStr_ptr | AST only |
| test.cpp:49:23:49:28 | call to getenv | test.cpp:54:6:54:35 | ! ... | AST only |
| test.cpp:49:23:49:28 | call to getenv | test.cpp:54:7:54:12 | call to strcmp | AST only |
| test.cpp:49:23:49:28 | call to getenv | test.cpp:54:7:54:35 | (bool)... | AST only |
| test.cpp:49:23:49:28 | call to getenv | test.cpp:54:14:54:25 | envStrGlobal | AST only |
| test.cpp:60:29:60:34 | call to getenv | test.cpp:10:27:10:27 | s | AST only |
| test.cpp:60:29:60:34 | call to getenv | test.cpp:60:18:60:25 | userName | AST only |
| test.cpp:68:28:68:33 | call to getenv | test.cpp:11:20:11:21 | s1 | AST only |

View File

@@ -14,10 +14,6 @@
| test.cpp:49:23:49:28 | call to getenv | test.cpp:49:23:49:28 | call to getenv |
| test.cpp:49:23:49:28 | call to getenv | test.cpp:49:23:49:40 | (const char *)... |
| test.cpp:49:23:49:28 | call to getenv | test.cpp:52:16:52:21 | envStr |
| test.cpp:49:23:49:28 | call to getenv | test.cpp:54:6:54:35 | ! ... |
| test.cpp:49:23:49:28 | call to getenv | test.cpp:54:7:54:12 | call to strcmp |
| test.cpp:49:23:49:28 | call to getenv | test.cpp:54:7:54:35 | (bool)... |
| test.cpp:49:23:49:28 | call to getenv | test.cpp:54:14:54:25 | envStrGlobal |
| test.cpp:60:29:60:34 | call to getenv | test.cpp:60:29:60:34 | call to getenv |
| test.cpp:60:29:60:34 | call to getenv | test.cpp:60:29:60:47 | (const char *)... |
| test.cpp:60:29:60:34 | call to getenv | test.cpp:64:25:64:32 | userName |

View File

@@ -7,7 +7,7 @@ void test_unique_ptr_int() {
std::unique_ptr<int> p1(new int(source()));
std::unique_ptr<int> p2 = std::make_unique<int>(source());
sink(*p1); // $ ir MISSING: ast
sink(*p1); // $ MISSING: ast,ir
sink(*p2); // $ ast ir=8:50
}
@@ -21,9 +21,9 @@ void test_unique_ptr_struct() {
std::unique_ptr<A> p1(new A{source(), 0});
std::unique_ptr<A> p2 = std::make_unique<A>(source(), 0);
sink(p1->x); // $ ir MISSING: ast
sink(p1->x); // $ MISSING: ast,ir
sink(p1->y);
sink(p2->x); // $ MISSING: ast,ir
sink(p2->x); // $ MISSING: ast,ir=22:46
sink(p2->y);
}
@@ -31,7 +31,7 @@ void test_shared_ptr_int() {
std::shared_ptr<int> p1(new int(source()));
std::shared_ptr<int> p2 = std::make_shared<int>(source());
sink(*p1); // $ ast ir
sink(*p1); // $ ast MISSING: ir
sink(*p2); // $ ast ir=32:50
}
@@ -39,7 +39,7 @@ void test_shared_ptr_struct() {
std::shared_ptr<A> p1(new A{source(), 0});
std::shared_ptr<A> p2 = std::make_shared<A>(source(), 0);
sink(p1->x); // $ ir MISSING: ast
sink(p1->x); // $ MISSING: ast,ir
sink(p1->y);
sink(p2->x); // $ MISSING: ast,ir
sink(p2->y);

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