Compare commits

..

972 Commits

Author SHA1 Message Date
Mathias Vorreiter Pedersen
3059ce3070 Merge pull request #11938 from github/release-prep/2.12.1
Release preparation for version 2.12.1
2023-01-20 14:30:42 +00:00
Jeroen Ketema
cddaa0c8fa Apply suggestions from code review 2023-01-20 14:10:27 +01:00
github-actions[bot]
005b3e4a47 Release preparation for version 2.12.1 2023-01-20 12:03:19 +00:00
Ian Lynagh
05c80b3f3c Merge pull request #11894 from igfoo/igfoo/make-private
Kotlin: Make a couple of functions private
2023-01-19 20:59:32 +00:00
Ian Lynagh
c2d5281e73 Merge pull request #11930 from igfoo/igfoo/fetch-codeql
CI: fetch-codeql: Set $CODEQL_FETCHED_CODEQL_PATH in the enivironment
2023-01-19 15:33:08 +00:00
Paolo Tranquilli
c2c14cdddb Merge pull request #11929 from github/redsun82/swift-expand-ref-in-auto-docs
Swift: expand `ref` in autogenerated docs
2023-01-19 15:24:05 +01:00
Michael B. Gale
14cc27e49b Merge pull request #11910 from owen-mc/go/log-injection-sanitizer-newreplacer-replace
Add missing string replacement sanitizers to log-injection and string-break
2023-01-19 14:23:03 +00:00
Chris Smowton
9a5e1f5e28 Make import private 2023-01-19 14:10:17 +00:00
Owen Mansel-Chan
13d1c88a11 Make new data flow copy for StringOps.StringsNewReplacer 2023-01-19 13:05:31 +00:00
Ian Lynagh
3a5bec5778 CI: fetch-codeql: Set $CODEQL_FETCHED_CODEQL_PATH in the enivironment 2023-01-19 11:37:05 +00:00
Paolo Tranquilli
490bd051cd Swift: expand ref in autogenerated docs 2023-01-19 09:27:44 +00:00
Michael Nebel
e6aebd9df0 Merge pull request #11814 from michaelnebel/csharp/genericattributes
C# 11: Generic attributes
2023-01-19 07:35:17 +01:00
Mathias Vorreiter Pedersen
14468b64fb Merge pull request #11924 from atorralba/atorralba/optbinding-getters
Swift: Support more CFG node types in optional binding flow
2023-01-18 16:37:11 +00:00
Owen Mansel-Chan
3fda9f6e65 Add change note 2023-01-18 15:42:42 +00:00
Owen Mansel-Chan
30f0dd8c03 Add string replacement sanitizer to log injection 2023-01-18 15:24:39 +00:00
Owen Mansel-Chan
015ef4c3ef Add use of strings.Replacer to replace sanitizer 2023-01-18 15:20:14 +00:00
Owen Mansel-Chan
2b1a7898d9 Move ReplaceAll sanitizer to shared code 2023-01-18 15:12:52 +00:00
AlexDenisov
5173f10e68 Merge pull request #11925 from github/alexdenisov/swift-drop-dead-code
Swift: drop dead code
2023-01-18 16:10:25 +01:00
Alex Denisov
35620c4c86 Swift: drop dead code 2023-01-18 15:35:40 +01:00
Mathias Vorreiter Pedersen
e26e83b8df Merge pull request #11728 from github/rdmarsh2/parameterize-range-analysis
C++: Parameterize the semantic range analysis
2023-01-18 14:22:35 +00:00
Tony Torralba
90517e254a Accept test expectation changes 2023-01-18 13:25:04 +01:00
Mathias Vorreiter Pedersen
48439bc252 Merge pull request #11905 from geoffw0/rncrypt
Swift: Add RNCryptor sinks to swift/constant-password
2023-01-18 11:43:23 +00:00
Tony Torralba
d75a5212b2 Support more CFG node types in optional binding flow 2023-01-18 12:42:44 +01:00
Tony Torralba
4a89a30abd Add failing test 2023-01-18 12:41:59 +01:00
Mathias Vorreiter Pedersen
c8bcfb77b2 Merge pull request #11836 from geoffw0/optbinding
Swift: Data flow through optional binding
2023-01-18 11:25:27 +00:00
Geoffrey White
71c1ca53a9 Merge branch 'main' into rncrypt 2023-01-18 11:09:09 +00:00
Michael Nebel
4c94adb5ec C#: Add change note. 2023-01-18 10:50:04 +01:00
Michael Nebel
3846349ba0 C#: Add testcase for CIL generic attribute extraction. 2023-01-18 10:49:44 +01:00
Michael Nebel
821d294be8 C#: Add library support for CIL generic attributes. 2023-01-18 10:49:44 +01:00
Michael Nebel
5ff89a2ccf C#: Update expected test output for printing of constructed generic CIL types. 2023-01-18 10:49:44 +01:00
Michael Nebel
8b231c51f9 C#: Improve printing of constructed generic CIL types. 2023-01-18 10:49:44 +01:00
Michael Nebel
b680795d15 C#: The generic attribute type is a constructed class. 2023-01-18 10:49:44 +01:00
Michael Nebel
62e7c22783 C#: Add generic attribute test and expected results. 2023-01-18 10:48:30 +01:00
Michael Nebel
211af1943c C#: Library support for generic attributes. 2023-01-18 10:48:30 +01:00
Michael Nebel
3a4623b437 Merge pull request #11907 from michaelnebel/csharp/cil/attributes
C#: CIL attributes
2023-01-18 10:46:34 +01:00
Rasmus Wriedt Larsen
e0ccb9306a Merge pull request #11908 from RasmusWL/dataflow-consistency-more-excludes
DataFlow: Add `uniqueParameterNodePositionExclude`
2023-01-18 10:44:51 +01:00
AlexDenisov
8910ba4f32 Merge pull request #11919 from github/redsun82/swift-obsolete-conf
Swift: remove obsolete configuration fields
2023-01-18 10:34:24 +01:00
Tony Torralba
c8e894b854 Merge pull request #11917 from github/workflow/coverage/update
Update CSV framework coverage reports
2023-01-18 10:02:22 +01:00
Erik Krogh Kristensen
1a64393c4c Merge pull request #11893 from erik-krogh/csharpIndexFiles
C#: add --working-dir=. to pre-finalize
2023-01-18 09:05:29 +01:00
Paolo Tranquilli
2c4c2dfeb3 Swift: remove obsolete configuration fields 2023-01-18 08:55:59 +01:00
Michael Nebel
8e3e6505ad C#: Add change note. 2023-01-18 07:56:24 +01:00
github-actions[bot]
571942fb21 Add changed framework coverage reports 2023-01-18 00:17:19 +00:00
Jeroen Ketema
6cd52237c3 Merge pull request #11913 from jketema/test-fixes
C++: Some minor test fixes
2023-01-17 21:52:57 +01:00
yoff
5a82012d03 Merge pull request #11854 from yoff/python/fix-tarslip-improv-bug
Python: fix bug  in `py/tarslip-extended`
2023-01-17 20:44:06 +01:00
Jeroen Ketema
ee19c3d80f C++: Rename identically named classes in syntax-zoo
Conceptually the test that comprises the whole of `syntax-zoo` forms one
single binary. To this binary ODR applies. There were two class definitions
`Foo` in `syntax-zoo`, violating ODR. Rename those classes to have different
names.
2023-01-17 19:02:40 +01:00
Jeroen Ketema
06767c6760 C++: Split bad_asts.cpp IR test into two files
The statements from `errorExpr` - which does not parse correctly - affected the
tuples that were being generated for the other code in `bad_asts.cpp` due to
the way the front-end handles parse errors. This did not affect the test
results, but was also not the intention of the test. Split off `errorExpr` into
a separate file.
2023-01-17 18:57:29 +01:00
Geoffrey White
5e5c4e9a8c Swift: Accept QL-for-QL recommendation. 2023-01-17 16:25:34 +00:00
Geoffrey White
ea06ad1933 Merge pull request #11529 from geoffw0/format
Swift: Uncontrolled format string query
2023-01-17 16:16:10 +00:00
Edward Minnix III
4c018759c8 Merge pull request #11283 from egregius313/egregius313/webview-setAllowContentAccess
Java: Android WebView Content Access Query
2023-01-17 11:02:47 -05:00
Michael Nebel
62533501fe C#: Update CIL attributes test case and the expected output. 2023-01-17 17:00:01 +01:00
Geoffrey White
54b3262d9c Merge pull request #11891 from geoffw0/authbypass
C++: Fix issue with cpp/user-controlled-bypass
2023-01-17 15:43:08 +00:00
Jami
babdee36aa Merge pull request #11779 from jcogs33/jcogs33/model-more-top-jdk-apis
Java: model top JDK APIs
2023-01-17 10:20:32 -05:00
Geoffrey White
d628cc5ab8 Update cpp/ql/src/Security/CWE/CWE-290/AuthenticationBypass.ql
Co-authored-by: Mathias Vorreiter Pedersen <mathiasvp@github.com>
2023-01-17 14:37:19 +00:00
Geoffrey White
037b49b454 Update swift/ql/test/query-tests/Security/CWE-259/rncryptor.swift
Co-authored-by: Mathias Vorreiter Pedersen <mathiasvp@github.com>
2023-01-17 14:16:52 +00:00
Paolo Tranquilli
6b43ff45a4 Merge pull request #11904 from github/redsun82/swift-extension-protocols
Swift: extract `ExtensionDecl` protocols
2023-01-17 15:16:20 +01:00
Paolo Tranquilli
d9bd41b8b1 Merge pull request #11571 from github/redsun82/swift-open-redirection
Swift: generalize open redirection on both platforms and rework output rewriting
2023-01-17 15:15:56 +01:00
Jami Cogswell
10f0975812 Java: remove models for System.[get|set]Property 2023-01-17 08:51:48 -05:00
Paolo Tranquilli
9e5db7c6ec Merge branch 'main' into redsun82/swift-extension-protocols 2023-01-17 14:39:09 +01:00
Michael Nebel
5f57a097ab C#: CIL method attribute extraction. 2023-01-17 14:17:35 +01:00
Michael Nebel
951f6362aa Merge pull request #11825 from michaelnebel/csharp/genericmathsupport
C# 11: Support for static virtual and static abstract interface members.
2023-01-17 14:14:02 +01:00
Rasmus Wriedt Larsen
a0b1c2ea79 DataFlow: Add uniqueParameterNodePositionExclude 2023-01-17 14:05:22 +01:00
Rasmus Wriedt Larsen
2b0a5fd5d1 DataFlow: Add uniqueParameterNodeAtPositionExclude 2023-01-17 14:05:17 +01:00
Erik Krogh Kristensen
2e4f4c64fe Merge pull request #11903 from erik-krogh/revertClap
QL: Revert "update clap to 3.0 in QL-for-QL"
2023-01-17 13:29:04 +01:00
Paolo Tranquilli
0a792f2f61 Swift: add upgrade and downgrade scripts for ExtensionDecl new protocols property 2023-01-17 13:07:02 +01:00
Paolo Tranquilli
0d32f00020 Swift: update ExtensionDecl test results 2023-01-17 12:58:02 +01:00
Paolo Tranquilli
d6e0ef9ff9 Swift: extract ExtensionDecl protocols 2023-01-17 12:56:09 +01:00
Paolo Tranquilli
f6e26211f9 Swift: add protocols to ExtensionDecl schema 2023-01-17 12:54:50 +01:00
Geoffrey White
74a37475db Swift: Model RNCryptor. 2023-01-17 11:54:12 +00:00
Mathias Vorreiter Pedersen
44ebc77ada Update cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisSpecific.qll 2023-01-17 11:52:43 +00:00
Paolo Tranquilli
8906e101cb Swift: add ExtensionDecl QL test 2023-01-17 12:49:53 +01:00
erik-krogh
5a4fe71529 Revert "update clap to 3.0 in QL-for-QL"
This reverts commit d072ed969e.
2023-01-17 12:38:30 +01:00
Erik Krogh Kristensen
50b9f5bba0 Merge pull request #11892 from erik-krogh/clap
QL: update clap to 3.0 in QL-for-QL
2023-01-17 12:33:18 +01:00
Mathias Vorreiter Pedersen
77a9cea737 Merge pull request #11901 from github/redsun82/swift-ql-internal
Swift: introduce `@ql.internal` pragma for classes
2023-01-17 10:46:56 +00:00
Paolo Tranquilli
67bd8cba32 Merge pull request #11900 from github/alexdenisov/swift-ignore-lsregister
Swift: do not trace lsregister
2023-01-17 11:26:22 +01:00
Chris Smowton
29425982a5 Merge pull request #11899 from ataillefer/patch-1
Fix partial path traversal Java example
2023-01-17 09:39:36 +00:00
Paolo Tranquilli
6106edd5e2 Swift: add INTERNAL doc marker to ql.internal classes 2023-01-17 10:30:59 +01:00
Paolo Tranquilli
b22da25e05 Swift: remove ql.internal classes from global import 2023-01-17 10:18:03 +01:00
Paolo Tranquilli
48825442c3 Swift: add ql.internal pragma in schema definitions 2023-01-17 10:10:35 +01:00
Paolo Tranquilli
cdc99b5240 Swift: simplify pragma definition 2023-01-17 10:10:02 +01:00
Geoffrey White
449ebb8a12 Swift: Add tests for RNCryptor library. 2023-01-17 09:03:07 +00:00
Paolo Tranquilli
e3502e2e5f Merge branch 'main' into redsun82/swift-open-redirection 2023-01-17 09:43:00 +01:00
Alex Denisov
63b4e5ef5c Swift: do not trace lsregister 2023-01-17 09:26:31 +01:00
Erik Krogh Kristensen
51bd1ef1e1 Merge pull request #11884 from erik-krogh/qlWin
QL/Ryby: fix qltest on Windows
2023-01-16 21:57:01 +01:00
Antoine Taillefer
660e6d7085 Fix partial path traversal Java example
The Java recommendation example for the "Partial path traversal vulnerability from remote" query doesn't seem right to me. Indeed, the following statement doesn't compile, since `dir.getCanonicalPath()` returns a String:
```
dir.getCanonicalPath().toPath()
```
Maybe the author wanted to state `dir.getCanonicalFile().toPath()`, which would compile, but is useless compared to `dir.getCanonicalPath()`.

Moreover, `parent.getCanonicalFile().toPath()` or `parent.getCanonicalPath()` will **not** be slash-terminated, contrary to what the description says.
From what I can see (and test), the correct fix is to concatenate `File.separator` to the parent canonical path.
2023-01-16 21:14:29 +01:00
erik-krogh
dcc1c3d487 add --working-dir=. to pre-finalize for c# 2023-01-16 18:09:00 +01:00
Ian Lynagh
17de5c120a Kotlin: Make a couple of functions private 2023-01-16 15:29:14 +00:00
Tony Torralba
bd5619147d Merge pull request #11590 from atorralba/atorralba/swift/sensitive-info-logs
Swift: Add Cleartext Logging query
2023-01-16 16:22:20 +01:00
erik-krogh
713599963b add --working-dir to Ruby qltest.cmd to fix Windows 2023-01-16 15:37:35 +01:00
erik-krogh
9e153cfb0d change the Ruby-build test such that Windows fails 2023-01-16 15:37:35 +01:00
erik-krogh
587adea809 QL: add --working-dir to qltest.cmd to fix qltest 2023-01-16 15:37:14 +01:00
erik-krogh
2c1ecb507d fix windows 2023-01-16 15:36:57 +01:00
erik-krogh
1de65131fe add compilation cache to QL-for-QL tests 2023-01-16 15:36:57 +01:00
erik-krogh
0685732e3f delete ql/ specific format step now that we have an all-languages format check 2023-01-16 15:36:57 +01:00
erik-krogh
1d62751e15 test QL-for-QL on mac/win 2023-01-16 15:36:55 +01:00
Tony Torralba
0017461e2d Update swift/ql/src/queries/Security/CWE-312/CleartextLogging.ql
Co-authored-by: Ben Ahmady <32935794+subatoi@users.noreply.github.com>
2023-01-16 15:35:58 +01:00
Michael Nebel
8981d4c06b C#: Add change note. 2023-01-16 13:43:26 +01:00
Michael Nebel
2f602a629f C#: Add upgrade and downgrade scripts. 2023-01-16 13:27:37 +01:00
Erik Krogh Kristensen
8ccc384043 Merge pull request #11858 from erik-krogh/moreSpawn
JS: track shell:true more in js/shell-command-constructed-from-input
2023-01-16 13:24:50 +01:00
Erik Krogh Kristensen
59a8b21851 Merge pull request #10862 from erik-krogh/unsafeCodeConstruction
Rb: Add an `unsafe-code-construction` query
2023-01-16 13:22:58 +01:00
Michael Nebel
3552a41552 C#: Add test case for static abstract and static virtual interface members. 2023-01-16 13:07:50 +01:00
Michael Nebel
dc50b6bad3 C#: Support for operators in implements relations. 2023-01-16 13:07:50 +01:00
Michael Nebel
8c2931cbb8 C#: Operators are now allowed to be declared virtual. 2023-01-16 13:07:50 +01:00
erik-krogh
d072ed969e update clap to 3.0 in QL-for-QL 2023-01-16 12:34:56 +01:00
Paolo Tranquilli
874fe2b8f9 Swift: introduce an in-memory file hash cache
File hashing is now done internally in `SwiftFileInterception` (and
exported as a `getHashOfRealFile` function for future use in linkage
awareness), and using a per-process in-memory cache. The persistent
caching of paths is removed, so the solution is now robust against input
file changes during the build.

For the same reason, the hash to artifact mapping have the symlinks
reversed now. The artifacts themselves are stored using the hash as
filenames, and the original paths of the artifacts are reacreated in the
scratch dir with symlinks mostly for debugging purposes (to understand
what artifact each hash corresponds to, and to follow what was built by
the extractor).
2023-01-16 12:05:36 +01:00
Tony Torralba
fdb3b65bce Apply suggestions from code review
Co-authored-by: Ben Ahmady <32935794+subatoi@users.noreply.github.com>
2023-01-16 11:57:37 +01:00
Tony Torralba
7f880a24df Merge pull request #11886 from jelaiw/jelaiw-patch-1
Fix small typo in good/bad code sample.
2023-01-16 09:43:23 +01:00
Paolo Tranquilli
738412260f Merge branch 'main' into redsun82/swift-open-redirection 2023-01-16 09:09:10 +01:00
jelaiw
cf7189bb28 Fix small typo in good/bad code sample. 2023-01-13 19:16:11 -06:00
Geoffrey White
1a416884d4 C++: Do something similar with the other three cases. 2023-01-14 00:09:01 +00:00
Geoffrey White
316117f5c9 C++: Reduce number of regexps. 2023-01-13 18:50:41 +00:00
Geoffrey White
2f09f0e2c1 C++: Turn the huge list into a predicate. 2023-01-13 18:47:18 +00:00
Geoffrey White
13ae15b867 C++: Add tests for more edge cases. 2023-01-13 18:38:29 +00:00
Jami Cogswell
fb6725ddaa Java: add WithoutElement comment for clear methods 2023-01-13 13:20:45 -05:00
Mathias Vorreiter Pedersen
2dbacbc302 Merge pull request #11841 from MathiasVP/swift-add-integral-types
Swift: Add integral type classes
2023-01-13 17:30:57 +00:00
Robert Marsh
601b43ac0a Merge branch 'main' into rdmarsh2/parameterize-range-analysis
Conflicting change to boundedPhiInp copied to RangeAnalysisStage.qll
2023-01-13 12:06:21 -05:00
Geoffrey White
c9a0067705 Swift: Remove flow in cases with multiple variables. 2023-01-13 16:37:23 +00:00
Mathias Vorreiter Pedersen
c5038ed281 Merge pull request #11883 from MathiasVP/fold-definitions
C++: Fix bad join in `definitionOf`
2023-01-13 16:28:26 +00:00
Mathias Vorreiter Pedersen
6e6f2115c0 Merge pull request #11857 from MathiasVP/speedup-missing-check-scanf
C++: Speedup `cpp/missing-check-scanf`
2023-01-13 16:11:16 +00:00
Geoffrey White
2c35af51cd Swift: Move logic into Ssa::WriteDefinition.assigns. 2023-01-13 15:19:33 +00:00
Geoffrey White
8a77906296 Swift: Use Ssa::Definition rather than ConcreteVarDecl. 2023-01-13 15:01:20 +00:00
Michael Nebel
2d46272295 Merge pull request #11881 from michaelnebel/java/modeldiffignore
Java: Ignore missing html artifacts in the Model Diff workflow.
2023-01-13 14:11:19 +01:00
Michael Nebel
b36be009d4 Merge pull request #11834 from michaelnebel/csharp/operators
C# 11: Extractor and library support for Unsigned right shift.
2023-01-13 13:21:02 +01:00
erik-krogh
71af8ab022 simplifications inspired by review 2023-01-13 13:18:52 +01:00
Mathias Vorreiter Pedersen
2283eacc0b C++: Fix bad join in 'definitionOf'. 2023-01-13 11:42:15 +00:00
Mathias Vorreiter Pedersen
59072f9e81 C++: Improve QLDoc. 2023-01-13 11:01:23 +00:00
Mathias Vorreiter Pedersen
dd8bead21a C++: Fix spurious backticks. 2023-01-13 10:57:44 +00:00
Mathias Vorreiter Pedersen
cf9998b932 Merge pull request #5 from geoffw0/integraltypes
Swift: Work on integral type classes
2023-01-13 10:01:23 +00:00
Michael Nebel
600412db48 Java: Ignore missing html artifacts. 2023-01-13 08:58:53 +01:00
Michael Nebel
3b15f2359b Merge pull request #11861 from michaelnebel/java/testmodeldiff
Java: Update the Model Difference workflow to use the `gh api`.
2023-01-13 08:20:18 +01:00
Jami Cogswell
a43f3cf95f Java: remove Supplier.get model 2023-01-12 17:09:13 -05:00
Jami Cogswell
f040ff2d8d Java: undo change to Function.apply test case 2023-01-12 17:01:58 -05:00
Robert Marsh
337a747bde C++: cleanup some unneeded code 2023-01-12 16:38:58 -05:00
Robert Marsh
b2b45237c6 C++: use rounding to prevent float wobble in range analysis 2023-01-12 16:38:57 -05:00
Robert Marsh
31b61b1aa6 C++: fix a join order in range analysis 2023-01-12 16:38:57 -05:00
Robert Marsh
938176c9da C++: update test QL for modulus and sign analysis
These now instantiate their respective parameterized modules. No
results change.
2023-01-12 16:38:56 -05:00
Robert Marsh
7586762b10 C++: fix ambiguous import warnings 2023-01-12 16:38:56 -05:00
Robert Marsh
488368ecde C++: private import for module params 2023-01-12 16:38:55 -05:00
Robert Marsh
23281410e3 C++: Make bounds import private to preserve API 2023-01-12 16:38:54 -05:00
Robert Marsh
6db728190e C++: autoformat 2023-01-12 16:38:36 -05:00
Robert Marsh
02f1957919 C++: make SemBound a RangeAnalysis parameter 2023-01-12 16:38:11 -05:00
Robert Marsh
71b93d125e C++: Make RangeAnalysis.qll expose the old API 2023-01-12 16:38:11 -05:00
Robert Marsh
fb1ef07e9f C++: more parameterized modules in range analysis
This makes the modulus analysis and sign analysis into parameterized
modules which are instantiated in the main range analysis module, and
makes RangeAnalysisSpecific and RangeUtils into parameters to the main
range analysis.
Some classes also need to be moved and made into `instanceof` extensions
because they'd otherwise be extending across parameterized module
boundaries.
2023-01-12 16:38:10 -05:00
Robert Marsh
c062d5e206 C++: move language specific predicates to LangParam 2023-01-12 16:38:10 -05:00
Robert Marsh
c10733f926 C++: fix float binding issue in range analysis 2023-01-12 16:38:09 -05:00
Robert Marsh
b8c43d7a71 C++: convert RangeAnalysis to float 2023-01-12 16:38:09 -05:00
Robert Marsh
eebada46b1 C++: rename to RagneAnalysisStage.qll 2023-01-12 16:38:08 -05:00
Robert Marsh
edbe95837f Convert RangeAnalysis to trivial parameterized mod 2023-01-12 16:38:08 -05:00
Jami Cogswell
c3a1d088ac Java: update change note 2023-01-12 16:32:52 -05:00
Jami Cogswell
a39b2aaaac Java: remove endsWith test case 2023-01-12 16:24:57 -05:00
Jami Cogswell
ffb267937a Java: add endsWith additionalTaintStep to ConditionalBypassFlowConfig 2023-01-12 16:24:05 -05:00
Arthur Baars
af8cb65b2e Merge pull request #11877 from aibaars/ql-ql-cross
QL/Ruby: include OS version in cache keys for Rust binaries
2023-01-12 20:02:25 +01:00
Michael Nebel
fd80974210 Java: Download databases using the gh api instead of lgtm. 2023-01-12 19:30:12 +01:00
Michael Nebel
c1c0ff4308 C#: Update database stats. 2023-01-12 19:06:29 +01:00
Michael Nebel
1384aa669b C#: Add change note. 2023-01-12 19:06:29 +01:00
Michael Nebel
5e89119b3d C#: Add upgrade- and downgrade scripts for unsigned right shift operators. 2023-01-12 19:06:29 +01:00
Michael Nebel
529be7ef18 C++: Sync files. 2023-01-12 19:06:29 +01:00
Michael Nebel
5c466f3319 Java: Sync files and update other relavant files related to the new naming of shift. 2023-01-12 19:06:29 +01:00
Michael Nebel
49a87e152a C#: Add unsigned right shift operator test case. 2023-01-12 19:06:28 +01:00
Michael Nebel
30738103f0 C#: Add unsigned right shift operator class. 2023-01-12 19:06:28 +01:00
Michael Nebel
148dc6de5a C#: Rename shift operator classes. 2023-01-12 19:06:28 +01:00
Michael Nebel
f48eda829f C#: Rename some of the TBinarySignOperation constructors. 2023-01-12 19:06:28 +01:00
Michael Nebel
d92b226041 C#: Add test example for unsigned right shift assignment in intermediate representation. 2023-01-12 19:06:28 +01:00
Michael Nebel
5bb8f8ed5c C#: Support for unsigned shift right in the experimental intermediate representation. 2023-01-12 19:06:28 +01:00
Michael Nebel
f74c7c28ae C#: Auto format test file and update expected test output. 2023-01-12 19:06:28 +01:00
Michael Nebel
0f032c5be9 C#: Sign analysis testcase for unsigned right shift. 2023-01-12 19:06:28 +01:00
Michael Nebel
2568318460 C#: Sign analysis support for unsigned right shift. 2023-01-12 19:06:28 +01:00
Michael Nebel
d06a877709 C#: Introduce test cases and expected result for unsigned right shift. 2023-01-12 19:06:28 +01:00
Michael Nebel
9eb7933778 C#: Implement library support for unsigned right shift. 2023-01-12 19:06:28 +01:00
Michael Nebel
99b7bc3b73 C#: Implement extractor support for unsigned right shift. 2023-01-12 19:06:28 +01:00
Michael Nebel
14c92e6eb3 C#: Add expressions kind including dummy stats for unsigned right shift and unsigned right shift assigment. 2023-01-12 19:06:28 +01:00
Michael Nebel
902b0a60d0 C#: Fixup ShiftExpr rename. 2023-01-12 19:06:28 +01:00
Michael Nebel
36980bbf42 C#: Rename shift expression classes. 2023-01-12 19:06:27 +01:00
Michael Nebel
a9f1c95513 C#: Rename shift assignment expression classes. 2023-01-12 19:06:27 +01:00
Chris Smowton
8aa2c23ba8 Merge pull request #11700 from JLLeitschuh/doc/JLL/improve-java-unsafe-deserialization-documentation
[Java] Document fixes for deserialization vulnerabilities by framework
2023-01-12 18:04:13 +00:00
Chris Smowton
09d8a50494 Spelling 2023-01-12 17:46:00 +00:00
Michael Nebel
aefb43324b Merge pull request #11738 from michaelnebel/go/maddataextensions
Go: Models as Data using extensions.
2023-01-12 18:42:35 +01:00
Erik Krogh Kristensen
8f9ad1f5ba Merge pull request #11872 from erik-krogh/jsAst
JS: Fixup some problems in PrintAST
2023-01-12 16:56:56 +01:00
Geoffrey White
7f31c9c7e5 Swift: Add a test. 2023-01-12 15:19:57 +00:00
Jami Cogswell
e0444449c8 Java: remove Function.apply model 2023-01-12 09:58:53 -05:00
Arthur Baars
e29e077a03 Ruby/QL4QL: include OS version in cache keys 2023-01-12 15:47:10 +01:00
erik-krogh
7ae27bcc34 fix errors in JS printAst 2023-01-12 15:37:52 +01:00
Henry Mercer
15ead6d0e6 Merge pull request #11864 from github/codeql-ci/atm/release-0.4.5
JS: Bump version numbers of ML-powered packs after 0.4.5 release
2023-01-12 13:51:24 +00:00
Henry Mercer
70f1015fba Merge branch 'main' into codeql-ci/atm/release-0.4.5 2023-01-12 12:32:25 +00:00
Ian Lynagh
9ebe59d353 Merge pull request #11637 from igfoo/igfoo/kotlin-1.8
Kotlin: Add 1.8 support
2023-01-12 12:15:00 +00:00
Geoffrey White
3d1b2fdbda Swift: Rename NumericOrCharType.qll -> Numer> NumericType.qll. 2023-01-12 11:46:51 +00:00
Geoffrey White
418d593a97 Swift: Replace NumericOrCharType with a more basic NumericType, and rename classes for consistency with other static languages. 2023-01-12 11:43:20 +00:00
Geoffrey White
d0eb167d47 Swift: Merge FloatingPointType.qll into NumericOrCharType.qll, because it is a numeric type and other stuff like CharacterType is there. 2023-01-12 11:42:36 +00:00
Geoffrey White
4e5483744f Swift: Add a test case we're discussing. 2023-01-12 10:52:03 +00:00
Michael Nebel
48d0eccbf6 Go: Cleanup and renaming. 2023-01-12 11:13:34 +01:00
Michael Nebel
3749a1bd4d Go: Migrate unit tests to use data extensions for Models as Data. 2023-01-12 11:13:33 +01:00
Michael Nebel
218f553fef Go: Convert remaining CSV production models to use data extensions. 2023-01-12 11:13:33 +01:00
Michael Nebel
ebb3485a73 Go: Use the extensible predicates for model definitions. 2023-01-12 11:13:33 +01:00
Michael Nebel
5fd687d3df Go: Add MaD related extensible predicates. 2023-01-12 11:13:33 +01:00
Michael Nebel
0f993a0d26 Go: Prepare library for adding extensions. 2023-01-12 11:13:28 +01:00
Mathias Vorreiter Pedersen
1ae52b6c7e C++: Speedup 'MissingCheckScanf'. 2023-01-12 10:13:02 +00:00
Paolo Tranquilli
4f5f0aad45 Merge branch 'main' into redsun82/swift-open-redirection 2023-01-12 10:54:04 +01:00
Michael Nebel
18a815ca8b Merge pull request #11721 from michaelnebel/csharpjava/refactorprovenance
C#/Java: Re-factor provenance related predicates.
2023-01-12 10:50:31 +01:00
yoff
006eaf3e2a Merge pull request #11088 from yoff/python/inline-query-tests
Python: Inline query tests
2023-01-12 10:32:26 +01:00
Jami Cogswell
fd593fd4f0 Java: undo changes to tests that were affected by numeric-flow summary models 2023-01-11 22:34:19 -05:00
Jami Cogswell
ce74c9d959 Java: Date models as neutral 2023-01-11 22:15:41 -05:00
Jami Cogswell
6bb865ad05 Java: make numeric flow models neutral 2023-01-11 18:04:43 -05:00
Henning Makholm
1d4b2fd0bb Merge pull request #11870 from github/hmakholm/pr/mergeback-2.12.0
Merge codeql-cli-2.12.0 back to main
2023-01-11 23:51:56 +01:00
Pierre
4e1f772f23 Merge pull request #11702 from github/turbo/experimental/combined
Introduce the security-experimental CodeQL suite and experimental tag
2023-01-11 20:37:42 +01:00
Jami Cogswell
0c7ffb0554 Java: update System.getProperty model 2023-01-11 12:04:22 -05:00
Pierre
c3116b3f0f Merge branch 'main' into turbo/experimental/combined 2023-01-11 18:02:55 +01:00
Jami Cogswell
2a99af0e6d Java: remove summary model for String.endsWith 2023-01-11 10:58:46 -05:00
Jami Cogswell
99ee6c95a1 Java: remove models for Consumer.accept and Collectors.toMap 2023-01-11 10:44:38 -05:00
Jami Cogswell
ac064ac2a7 Java: remove model for Collectors.joining 2023-01-11 10:30:49 -05:00
Michael Nebel
7e4f7a0c17 C#: Address review comments and sync files. 2023-01-11 16:29:24 +01:00
Michael Nebel
67cbe38255 Sync files. 2023-01-11 16:20:55 +01:00
Michael Nebel
8112058a0a Java: Adapt TopJdpApi library to the re-factor. 2023-01-11 16:20:55 +01:00
Michael Nebel
372ecf402f Go: Delete unused summaryModel predicate. 2023-01-11 16:20:55 +01:00
Michael Nebel
80a4197604 Swift: Re-factor provenance related predicates for summarized callable. 2023-01-11 16:20:55 +01:00
Michael Nebel
c01361a1fd Ruby: Re-factor provenance related predicates for summarized callable. 2023-01-11 16:20:55 +01:00
Michael Nebel
59a9e255c7 Python: Re-factor provenance related predicates for summarized callable. 2023-01-11 16:20:55 +01:00
Michael Nebel
6622eda04c Go: Re-factor provenance related predicates for summarized callable. 2023-01-11 16:20:55 +01:00
Michael Nebel
6a047d6916 Java: Re-factor provenance related predicates for summarized callable. 2023-01-11 16:20:55 +01:00
Michael Nebel
ea173f9516 Sync files. 2023-01-11 16:20:55 +01:00
Michael Nebel
7422029e49 C#: Re-factor provenance related predicates for summarized callable. 2023-01-11 16:20:48 +01:00
Michael Nebel
4b47b08ed2 Merge pull request #11760 from michaelnebel/movemodelgenerator
C#/Java: Move the modelgenerator.
2023-01-11 16:02:36 +01:00
Tony Torralba
c6d9e1ec81 Merge pull request #11742 from atorralba/atorralba/swift/more-path-injection-sinks
Swift: Add more path injection sinks
2023-01-11 15:15:42 +01:00
Tony Torralba
c115a9fee4 Add more path injection sinks 2023-01-11 14:28:24 +01:00
Tony Torralba
5d54482c71 Merge pull request #11770 from atorralba/atorralba/ql/omittable-exists
QL: Add OmittableExists query
2023-01-11 14:27:40 +01:00
Michael Nebel
11ca3f49f6 C#/Java: Adjust imports after moving files. 2023-01-11 13:13:33 +01:00
Michael Nebel
787b4743ee C#/Java: Rename the directories containing the model generator and tests. 2023-01-11 13:13:33 +01:00
Michael Nebel
178fd0e9e1 C#/Java: Remove all dashes in mode-generator. 2023-01-11 13:13:33 +01:00
erik-krogh
6914e9a17a Merge branch 'main' into atorralba/ql/omittable-exists 2023-01-11 13:09:38 +01:00
Erik Krogh Kristensen
466f24663e Merge pull request #11867 from erik-krogh/qlFix
QL: move queries folder instead of .cache folder now that we got .qlx
2023-01-11 13:03:47 +01:00
Erik Krogh Kristensen
3fa6a7cbff cache -> queries
Co-authored-by: Tony Torralba <atorralba@users.noreply.github.com>
2023-01-11 12:29:15 +01:00
Tony Torralba
a4f813183e Merge pull request #11785 from atorralba/atorralba/swift/grdb-sinks
Swift: Add sinks for the GRDB library
2023-01-11 11:49:37 +01:00
erik-krogh
74a58f64aa move queries folder instead of .cache folder now that we got .qlx 2023-01-11 11:13:42 +01:00
erik-krogh
ed2dd87bda update the codeql-action version used in QL-for-QL 2023-01-11 11:13:06 +01:00
Tony Torralba
ecf568629b Add ExprAggregate as a negative edge in getConjunctionParentRec 2023-01-11 09:41:16 +01:00
Jami Cogswell
181a711f04 Java: switch Collectors.joining model from neutral to summary 2023-01-10 21:06:03 -05:00
github-actions[bot]
76e121e359 JS: Bump version of ML-powered library and query packs to 0.4.6 2023-01-10 21:11:23 +00:00
github-actions[bot]
dc88bdccc7 JS: Bump patch version of ML-powered library and query packs 2023-01-10 21:04:31 +00:00
Edward Minnix III
ce06df3152 Merge pull request #11628 from egregius313/egregius313/android-webview-addjavascriptinterface-dataflow
Java: Add parameters of methods annotated @JavascriptInterface as remote flow sources
2023-01-10 12:41:52 -05:00
Florin Coada
4c1c12dd70 suggestions in list format 2023-01-10 11:18:56 -05:00
Jonathan Leitschuh
1d7881e03f Apply suggestions from code review
Co-authored-by: Chris Smowton <smowton@github.com>
2023-01-10 11:18:56 -05:00
Tony Torralba
b7364f5428 Update UnsafeDeserialization.qhelp
Move the table under <recommendation>, minor fixes.
2023-01-10 11:18:56 -05:00
Jonathan Leitschuh
3fa11c21c3 [Java] Document fixes for deserialization vulnerabilities by framework
Related https://github.com/github/codeql/issues/11603
2023-01-10 11:18:56 -05:00
Paolo Tranquilli
0ad585cfe6 Merge pull request #11860 from github/redsun82/swift-clang-14
Swift: make compilation with newer STL possible
2023-01-10 17:17:56 +01:00
Erik Krogh Kristensen
54c780bdf9 Merge pull request #11853 from erik-krogh/assignMore
JS: add local flow when recognizing Object.assign calls for library-inputs
2023-01-10 17:04:29 +01:00
Tony Torralba
ae8c75ac97 Generalize ConjunctionParent 2023-01-10 16:08:42 +01:00
Tony Torralba
72a11e737d Merge pull request #11775 from atorralba/atorralba/all/omittable-exists
All: Remove omittable exists variables
2023-01-10 16:07:06 +01:00
Ian Lynagh
3367da82c4 Kotlin: Accept test changes
We get better locations with Kotlin 1.8.0.
2023-01-10 14:41:30 +00:00
Ian Lynagh
b7eb521fa0 Kotlin: Fix custom_plugin test for Kotlin 1.8.0 2023-01-10 14:41:30 +00:00
Ian Lynagh
c71ea80029 Kotlin: Accept test changes
We now get better locations, with Kotlin 1.8.0.
2023-01-10 14:41:30 +00:00
Ian Lynagh
20b35e5d02 Kotlin: 1.8.0 changes 2023-01-10 14:41:30 +00:00
Ian Lynagh
c4119761cc Kotlin: Another 1.8 build fix 2023-01-10 14:41:30 +00:00
Ian Lynagh
89b3363761 Kotlin: Bump CI version to 1.8.0-Beta 2023-01-10 14:41:30 +00:00
Ian Lynagh
b51c3aae85 Kotlin: Logs test: Allow for -Beta versions etc when parsing the logs 2023-01-10 14:41:29 +00:00
Ian Lynagh
6fbda1a9f0 Kotlin: Accept test changes with 1.8 2023-01-10 14:41:29 +00:00
Ian Lynagh
f7d8d16ed3 Kotlin: Fix build for 1.8.0-Beta
The build no longer works for Kotlin < 1.8: We get

    error: class 'org.jetbrains.kotlin.ir.IrElement' was compiled
           with an incompatible version of Kotlin. The binary version
           of its metadata is 1.8.0, expected version is 1.6.0.
2023-01-10 14:41:29 +00:00
erik-krogh
62b69bbd3e autoformat 2023-01-10 15:38:13 +01:00
Erik Krogh Kristensen
6623e5fbf3 Merge pull request #11852 from erik-krogh/jsInfiniteChar
JS: recognize an infinite repetition of a char-class like regex as a char-class like regex
2023-01-10 15:32:22 +01:00
Erik Krogh Kristensen
ce8836fb65 Update javascript/ql/lib/semmle/javascript/PackageExports.qll
Co-authored-by: Esben Sparre Andreasen <esbena@github.com>
2023-01-10 15:30:44 +01:00
erik-krogh
43696f5e27 add explicit this 2023-01-10 15:27:37 +01:00
erik-krogh
23a847b1cf track shell:true more in js/shell-command-constructed-from-input 2023-01-10 15:27:37 +01:00
Erik Krogh Kristensen
9f8d10de11 Merge pull request #11851 from erik-krogh/jsFixMissingThis
JS: fix bad join-order in js/missing-this-qualifier
2023-01-10 15:23:25 +01:00
Paolo Tranquilli
2fb5621527 Swift: replace $(CC) with clang
On macOS `$(CC)` points to a wrapper that requires `DEVELOPER_DIR` to be
set in the environment. Using `clang` is slightly less generic, but
that's our default any way. Even if we do set a different clang version
somewhere, the selected version of GCC would not change, and the test
is targeting that.
2023-01-10 14:58:21 +01:00
Paolo Tranquilli
943763a026 Swift: add -Wno-pragma-once-outside-header to check 2023-01-10 14:30:35 +01:00
Paolo Tranquilli
28d79eeb77 Swift: make compilation with different STL versions possible
Previous to this patch the code contained a workaround for the standard
defect

https://cplusplus.github.io/LWG/issue3657

where `std::filesystem::path` did not have a `std::hash` implementation.

This patch allows compiling against versions of the STL that contain the
fix to the above issue. This is done by running the compiler against
code defining `std::hash<std::filesystem::path>`: if compilation
succeeds, it means the fix is not there and we need to use the
workaround, contained in `PathHash.h.workaround`. Otherwise, the fix is
there and we use `PathHash.h.fixed` instead, which only includes the
standard headers included by `PathHash.h.workaround`, so that one is a
drop-in replacement of the other.
2023-01-10 14:14:33 +01:00
Jeroen Ketema
1a4048d238 Merge pull request #11830 from jketema/frontend-update
C++: Changes for frontend update
2023-01-10 14:01:46 +01:00
erik-krogh
5c388c554c fix that the TypeTracker was unrestricted for the base-case of nonFirstLocationType 2023-01-10 13:39:50 +01:00
erik-krogh
e02b67af63 add failing test 2023-01-10 13:39:50 +01:00
Tony Torralba
50cd40ed20 Swift: Remove omittable exists variables 2023-01-10 13:39:50 +01:00
Tony Torralba
7ef8099a8b Shared: Remove omittable exists variables 2023-01-10 13:39:50 +01:00
Tony Torralba
c9d1cd97fb Ruby: Remove omittable exists variables 2023-01-10 13:39:49 +01:00
Tony Torralba
f6c3f77602 QL: Remove omittable exists variables 2023-01-10 13:37:58 +01:00
Tony Torralba
d87c8c75d6 Python: Remove omittable exists variables 2023-01-10 13:37:35 +01:00
Tony Torralba
3b6dae41cd JavaScript: Remove omittable exists variables 2023-01-10 13:37:21 +01:00
Tony Torralba
32471d326e Java: Remove omittable exists variables 2023-01-10 13:37:19 +01:00
Tony Torralba
7a92970d89 Go: Remove omittable exists variables 2023-01-10 13:36:48 +01:00
Tony Torralba
2ca0df0369 C#: Remove omittable exists variables 2023-01-10 13:36:25 +01:00
Tony Torralba
3fcc99e5cb C++: Remove omittable exists variables 2023-01-10 13:36:01 +01:00
Erik Krogh Kristensen
f2658a0936 apply suggestions from doc review
Co-authored-by: mc <42146119+mchammer01@users.noreply.github.com>
2023-01-10 12:56:22 +01:00
Tony Torralba
da90ae0e8f Update java/ql/lib/semmle/code/java/dataflow/FlowSources.qll 2023-01-10 11:18:53 +01:00
Jeroen Ketema
8d46642de3 C++: Update dbscheme stats file 2023-01-10 10:41:43 +01:00
Jeroen Ketema
2fc6484162 C++: Add dbscheme upgrade and downgrade scripts 2023-01-10 10:41:43 +01:00
Jeroen Ketema
1bab950023 C++: Introduce (_Complex) _Float16 type which is needed after frontend update 2023-01-10 10:41:43 +01:00
Jeroen Ketema
282ca1094e C++: Accept test changes after improving size of _Float128 in frontend 2023-01-10 10:41:43 +01:00
Jeroen Ketema
e215c4c94c C++: Accept test changes after frontend update
The location of a reference dereference has changed slightly.
2023-01-10 10:41:43 +01:00
Michael Nebel
16cd148961 Merge pull request #11711 from michaelnebel/externalflowcleanup
C#/Java: Delete deprecated ModelCsv classes and related predicates.
2023-01-10 10:22:50 +01:00
Michael Nebel
1729319ebe Merge pull request #11804 from michaelnebel/csharp/alignqueryids
C#: Align query IDs.
2023-01-10 10:14:07 +01:00
Michael Nebel
18a0abdb4c Merge pull request #11740 from michaelnebel/csharp/updatestats
C#: Update stats based on projects.
2023-01-10 10:09:53 +01:00
Ed Minnix
293a203756 Move JavascriptInterfaceMethod to WebView.qll 2023-01-09 15:10:23 -05:00
Rasmus Lerchedahl Petersen
2edbfbf8bc python: update test expectations
...now the bug is fixed
2023-01-09 20:35:20 +01:00
Mathias Vorreiter Pedersen
7f5344e025 Update swift/ql/lib/codeql/swift/elements/type/NumericOrCharType.qll
Co-authored-by: Tony Torralba <atorralba@users.noreply.github.com>
2023-01-09 17:08:27 +00:00
Tony Torralba
8e0a018673 Consider Int8 and UInt8 as OsLogNonRedactedTypes 2023-01-09 18:05:18 +01:00
Tony Torralba
49a41c98ee Test that hashed passwords are 'safe' to log
This doesn't seem completely right, but the heuristic approach we have regarding sensitive expressions has to draw the line somewhere.
2023-01-09 18:01:07 +01:00
Tony Torralba
160d89fb4e Add qhelp examples 2023-01-09 18:01:07 +01:00
Tony Torralba
33029b0ed8 Fix sanitizer QLDoc 2023-01-09 18:01:07 +01:00
Tony Torralba
7e0869965c Uncomment tests 2023-01-09 18:01:07 +01:00
Tony Torralba
c1f19dd145 Add stub so that tests work on Linux 2023-01-09 18:01:07 +01:00
Tony Torralba
b203a9eb6e Add a sanitizer for OSLogPrivacy options
Add test cases to verify how the sanitizer behaves depending on the argument type and the privacy option being used.
2023-01-09 18:01:07 +01:00
Tony Torralba
aad56097ac Add Cleartext Loggin query for Swift.
With some caveats: see TODO comments and failing tests.
2023-01-09 18:01:07 +01:00
Rasmus Lerchedahl Petersen
c142495a8b python: simplify code 2023-01-09 17:51:45 +01:00
Rasmus Lerchedahl Petersen
5fe62e293a python: fix bug, add clarifying comment 2023-01-09 17:45:50 +01:00
erik-krogh
9f100ef2c6 add local flow when recognizing Object.assign calls for library-inputs 2023-01-09 17:44:11 +01:00
Tony Torralba
eb78661c1f Add missing SQL injection tests for the GRDB SQL class 2023-01-09 17:36:54 +01:00
erik-krogh
90f9e3f825 recognize an infinite repetition of a char-class like regex as a char-class like regex 2023-01-09 17:25:08 +01:00
Sarita Iyer
be06469a19 Merge pull request #11835 from github/saritai/pr/qlx
Docs: CodeQL pack compatibility
2023-01-09 10:15:08 -05:00
Ed Minnix
909b1d70d9 Rename files to say "Allow" instead of "Permit" 2023-01-09 10:11:03 -05:00
Ed Minnix
c723df3ca7 Fix alert message in expected file 2023-01-09 10:08:19 -05:00
erik-krogh
785c21f462 fix bad join-order in js/missing-this-qualifier 2023-01-09 16:06:26 +01:00
Ed Minnix
f626d4794a Change wording from "permit" to "allow" in id and name 2023-01-09 10:03:12 -05:00
Ed Minnix
972b4629c8 Fix typo in change note 2023-01-09 10:01:38 -05:00
Ed Minnix
64668883a4 Add good example to documentation 2023-01-09 09:59:38 -05:00
Ed Minnix
2ec73c50f9 Mention WebView in alert message 2023-01-09 09:55:09 -05:00
Arthur Baars
664fdc3b2a Merge pull request #11815 from aibaars/too-many-fields
Ruby: use record_parse_error_for_node to report extractor error
2023-01-09 15:40:19 +01:00
Erik Krogh Kristensen
5157d4df7b Merge pull request #11581 from erik-krogh/stdin
Rb: add stdin as source for unsafe-deserialization
2023-01-09 13:57:47 +01:00
Chris Smowton
e9bbb5d7fa Merge pull request #11730 from smowton/smowton/admin/improve-sql-unescaped-docs
Java: improve naming and description of SqlUnescaped.ql
2023-01-09 12:50:27 +00:00
yoff
c01ce955ba Merge pull request #11778 from yoff/shared/inline-tests
Shared: Inline test expectations
2023-01-09 13:21:18 +01:00
Chris Smowton
2e26fb1171 Merge pull request #11819 from smowton/smowton/admin/port-java-autobuilder-tests
Add Java autobuilder integration tests
2023-01-09 12:17:39 +00:00
Chris Smowton
efe23c1da7 Note that alerts should not be re-raised 2023-01-09 10:56:13 +00:00
Chris Smowton
994a46289f Add change note 2023-01-09 10:56:13 +00:00
Chris Smowton
ef27f9fe96 Replace one more mention of escaping 2023-01-09 10:56:13 +00:00
Chris Smowton
45c732a6f9 Java: improve naming and description of SqlUnescaped.ql
Since the main thing it's objecting to is concatenation not lack of escaping (in particular it doesn't look for escaping sanitizers), rename and re-describe it accordingly.
2023-01-09 10:56:13 +00:00
Mathias Vorreiter Pedersen
381301e552 Update swift/ql/lib/swift.qll
Co-authored-by: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
2023-01-09 10:32:52 +00:00
Geoffrey White
9333e80def Swift: Add getVaList stub to the test. 2023-01-09 10:29:37 +00:00
Taus
06ea249997 Merge pull request #11820 from yoff/python/fix-downgrades
Python: fix downgrade script
2023-01-09 11:24:41 +01:00
Mathias Vorreiter Pedersen
6bb09ef289 Swift: Add integral type classes. 2023-01-09 09:43:09 +00:00
Mathias Vorreiter Pedersen
9be9636816 Merge pull request #11670 from atorralba/atorralba/swift/predicate-injection
Swift: Add predicate injection query
2023-01-09 08:54:13 +00:00
Harry Maclean
5b117084db Merge pull request #11534 from hmac/array-inclusion-barrier-guard-constant
Ruby: Make array inclusion barrier more sensitive
2023-01-09 20:57:09 +13:00
Paolo Tranquilli
82d9edfabf Merge branch 'main' into redsun82/swift-open-redirection 2023-01-09 08:44:02 +01:00
Jami Cogswell
a3c7b2c3a2 Java: move java.lang.Math.min to the correct file 2023-01-06 14:35:09 -05:00
Geoffrey White
bb50a99b36 Swift: Additional test cases. 2023-01-06 18:48:46 +00:00
Geoffrey White
b5dd815249 Swift: Flow through optional binding. 2023-01-06 18:34:22 +00:00
Geoffrey White
c598d9b882 Swift: Generalize an SSA case for variables declared in Patterns. 2023-01-06 18:34:22 +00:00
Geoffrey White
8a9a69fa00 Swift: Add more dataflow tests for of optionals, patterns, enums. 2023-01-06 18:34:22 +00:00
Jeroen Ketema
a743fbcc95 Merge pull request #11799 from jketema/case-uncomment
C++: Uncomment cases in dbscheme
2023-01-06 19:26:53 +01:00
Sarita Iyer
d7bf2d9375 docs for codeql pack compatibility 2023-01-06 12:07:24 -05:00
Geoffrey White
04f87a26a9 Swift: Test layout change. 2023-01-06 16:52:54 +00:00
Sarita Iyer
a9867a266e fixed link 2023-01-06 11:50:07 -05:00
Sarita Iyer
d68cfc7d4f codeql pack compatibility docs 2023-01-06 11:17:02 -05:00
Chris Smowton
831255e9c0 Merge pull request #11832 from github/mbg/fix/go-version-warnings
Go: Handle output from `go version` more gracefully
2023-01-06 14:05:39 +00:00
Jeroen Ketema
c1bc097355 C++: Add upgrade/downgrade scripts for dbscheme update 2023-01-06 14:26:24 +01:00
Jeroen Ketema
cdb34bb1f9 C++: Update database stats file 2023-01-06 14:26:23 +01:00
Jeroen Ketema
b9b0c8091f C++: Uncomment cases in dbscheme
Note that the builtin types `__int{8,16,32,64}` are not uncommented,
as these are never and could have never been generated by the
extractor.
2023-01-06 14:26:23 +01:00
Geoffrey White
f3914ffe25 Merge pull request #11823 from geoffw0/heuristicalloc
C++: Use HeuristicAllocationExpr in more queries
2023-01-06 13:13:14 +00:00
Jami
f5e5f6dfd1 Merge pull request #11821 from jcogs33/jcogs33/fix-mad-typos
Java: fix typos in MaD row `name` columns for `MappingSqlQuery` and `MappingSqlQueryWithParameters`
2023-01-06 07:59:30 -05:00
Rasmus Lerchedahl Petersen
03bd6cb414 python: Allow optional result=OK
Also add a further test case
2023-01-06 13:33:12 +01:00
Nick Rolfe
4c5f149afd Merge pull request #11831 from github/post-release-prep/codeql-cli-2.12.0
Post-release preparation for codeql-cli-2.12.0
2023-01-06 12:15:17 +00:00
Michael B. Gale
1ef1d63c11 Add test for parseGoVersion 2023-01-06 11:20:51 +00:00
Michael B. Gale
9af9b32722 Find the last line of output from go version 2023-01-06 11:20:39 +00:00
Geoffrey White
bb451f3911 C++: Fix result duplication. 2023-01-06 11:05:47 +00:00
github-actions[bot]
cdb8f67601 Post-release preparation for codeql-cli-2.12.0 2023-01-06 10:36:34 +00:00
Rasmus Lerchedahl Petersen
8d9e94a00f swift: fix typo 2023-01-06 11:22:49 +01:00
erik-krogh
0a1769657d add change-note 2023-01-06 09:09:09 +01:00
erik-krogh
19d2b49562 drive-by: make Base64.decode64(..) into a flowsummary that is shared with all queries 2023-01-06 09:04:37 +01:00
erik-krogh
1a27441cfb drive-by: delete code-execution sinks from unsafe-deserialization, we risked duplicate alerts 2023-01-06 09:04:36 +01:00
erik-krogh
0e6028a7f3 add stdin as source for unsafe-deserialization 2023-01-06 09:04:36 +01:00
Rasmus Lerchedahl Petersen
d42bb119fe python: align annotations with Ruby
use `result=BAD` for expected alert
and `result=OK` on sinks where alerts are not wanted.
2023-01-05 21:41:28 +01:00
Rasmus Lerchedahl Petersen
ad95225272 python: improve code
according to alert and reviewer's suggestion
2023-01-05 20:42:29 +01:00
erik-krogh
f98ff65b11 use eval() instead of send() in test 2023-01-05 20:04:04 +01:00
Erik Krogh Kristensen
d9176541c6 Apply suggestions from code review
Co-authored-by: Alex Ford <alexrford@users.noreply.github.com>
2023-01-05 20:02:54 +01:00
Nick Rolfe
5317fb5b53 Merge pull request #11828 from github/release-prep/2.12.0
Release preparation for version 2.12.0
2023-01-05 18:58:30 +00:00
Nick Rolfe
a3cc93b80b correct spelling and capitalization of TCP/UDP 2023-01-05 17:43:25 +00:00
Jeroen Ketema
de37f3b7d5 Properly indent code block in change log 2023-01-05 18:38:33 +01:00
Jeroen Ketema
ed87c3a90a Update go/ql/lib/CHANGELOG.md 2023-01-05 18:03:19 +01:00
Jeroen Ketema
af2c321380 Update python/ql/src/change-notes/released/0.6.0.md 2023-01-05 18:01:28 +01:00
Jeroen Ketema
3e634c92c1 Update python/ql/src/CHANGELOG.md 2023-01-05 18:01:21 +01:00
Jeroen Ketema
170242f79c Apply suggestions from code review 2023-01-05 17:57:19 +01:00
Nick Rolfe
44213f0144 Merge pull request #11826 from github/nickrolfe/check-change-note
CI: fail if a changenote filename doesn't have the right format
2023-01-05 16:55:30 +00:00
Nick Rolfe
6e07076151 tweak wording in 2.12 release notes 2023-01-05 16:46:44 +00:00
github-actions[bot]
b6a8193785 Release preparation for version 2.12.0 2023-01-05 16:32:14 +00:00
Nick Rolfe
4e6baf83c8 Update .github/workflows/check-change-note.yml
Co-authored-by: Taus <tausbn@github.com>
2023-01-05 16:26:43 +00:00
Nick Rolfe
0beca9d96c CI: fail if a changenote filename doesn't have the right format 2023-01-05 16:01:07 +00:00
Jeroen Ketema
f370cd840c Merge pull request #11818 from jketema/downgrade-fix
C++: Fix the expression kind in two of the downgrade scripts
2023-01-05 16:33:16 +01:00
Nick Rolfe
f58ec799dd Merge pull request #11822 from github/nickrolfe/codeql-cli-2.12.0-changenote-fix
Go: fix date format in changenote
2023-01-05 15:16:51 +00:00
Geoffrey White
b3e82498fa C++: Change note. 2023-01-05 15:06:40 +00:00
Nick Rolfe
b7846da65d Go: fix date format in changenote 2023-01-05 15:05:39 +00:00
Jami Cogswell
f03f687d61 Java: add change note 2023-01-05 09:08:04 -05:00
Rasmus Lerchedahl Petersen
bb26c31f84 Python: fix downgrade script
When new kinds are inserted, new indices exists that do not
correspond to any old indices.
These were previously mapped, now they are not.
2023-01-05 14:56:52 +01:00
Jami Cogswell
0640bd9d8b Java: fix typos in the MaD row name columns for MappingSqlQuery and MappingSqlQueryWithParameters 2023-01-05 08:32:22 -05:00
Rasmus Lerchedahl Petersen
8afb541718 cpp/swift: fix qldoc 2023-01-05 14:30:13 +01:00
yoff
a74062cd51 Update go/ql/test/TestUtilities/InlineExpectationsTest.qll
Co-authored-by: Owen Mansel-Chan <62447351+owen-mc@users.noreply.github.com>
2023-01-05 14:12:16 +01:00
Geoffrey White
3b31da8a62 C++: Update the experimental query as well. 2023-01-05 12:48:17 +00:00
Geoffrey White
46baf9d5e5 C++: Add test cases for an experimental query as well. 2023-01-05 12:48:16 +00:00
Geoffrey White
c160e0b2a4 C++: Add a warning on HeuristicAllocationExpr.getSizeBytes() and similar methods. 2023-01-05 12:47:52 +00:00
Geoffrey White
823c767aac C++: Undo changes to SizeCheck.ql, SizeCheck2.ql. 2023-01-05 12:34:12 +00:00
Chris Smowton
52297c0b23 Add Java autobuilder integration tests 2023-01-05 12:19:25 +00:00
Jonas Jensen
c8f35ea1ea Merge pull request #11810 from kaspersv/kaspersv/inline-late-pragma
Add inline_late pragma to QL language spec
2023-01-05 13:15:12 +01:00
Geoffrey White
2023abdc60 C++: Update the queries. 2023-01-05 11:33:58 +00:00
Geoffrey White
a9aa67177b C++: Add test cases for HeuristicAllocationExpr in queries. 2023-01-05 11:30:21 +00:00
Geoffrey White
10ca2dac19 C++: Remove unnecessary 'semmle' directory. 2023-01-05 11:30:15 +00:00
Jeroen Ketema
14283f01ac C++: Fix the expression kind in two of the downgrade scripts
A 0 value for the expression kind is not valid, as 0 does not occur in the
relevant case split. This should have been the value of `@errorexpr`, which
is 1.
2023-01-05 11:04:31 +01:00
Rasmus Lerchedahl Petersen
c3b3c05cf3 Revert "Merge pull request #37 from erik-krogh/shared/inline-tests"
This reverts commit 65fe9abcfe, reversing
changes made to 08e9d3391f.
2023-01-05 09:19:43 +01:00
Rasmus Lerchedahl Petersen
2e46919e10 java: nicer code as suggested by review 2023-01-04 19:50:29 +01:00
Geoffrey White
e45750a8ca Merge branch 'main' into format 2023-01-04 18:00:59 +00:00
Robert Marsh
4aa62757a9 Merge pull request #11803 from jketema/gvn-deprecation
C++: Mark a number of private predicates in the GVN library as deprecated
2023-01-04 12:33:23 -05:00
Arthur Baars
799e0c1bcc Ruby: use record_parse_error_for_node to report extractor error 2023-01-04 17:35:47 +01:00
Aditya Sharad
ed73875fac Merge pull request #11747 from adityasharad/tutorial/library-pack
Tutorial: Move QL detective tutorial library into shared `codeql/tutorial` library pack
2023-01-04 08:24:53 -08:00
yoff
65fe9abcfe Merge pull request #37 from erik-krogh/shared/inline-tests
inline Location into the shared implementation of InlineExpectationsTest
2023-01-04 17:08:23 +01:00
Jeroen Ketema
134fbb2128 Merge pull request #11805 from geoffw0/references
Swift: Add a reference for swift/hardcoded-key.
2023-01-04 16:39:24 +01:00
James Fletcher
60a5512ca2 Merge pull request #11813 from github/rc/3.8
Merge docs updates from rc/3.8 into main
2023-01-04 14:19:53 +00:00
James Fletcher
9ef0056c55 Merge pull request #11812 from github/codeql-cli-2.11.6
Merge docs updates from codeql-cli-2.11.6 into rc/3.8
2023-01-04 13:39:55 +00:00
James Fletcher
24552fb948 Merge branch 'rc/3.8' into codeql-cli-2.11.6 2023-01-04 12:06:27 +00:00
James Fletcher
a205818ba6 Merge pull request #11811 from jf205/codeql-cli-2.11.5-docs-mergeback
Merge docs updates from codeql-cli-2.11.5 -> codeql-cli-2.11.6
2023-01-04 11:57:51 +00:00
Geoffrey White
7ad8771b53 Merge remote-tracking branch 'upstream/main' into references 2023-01-04 10:55:24 +00:00
Henry Mercer
b96160f0f3 Merge pull request #11783 from github/henrymercer/specify-baseline-languages
Specify language names in extractor packs
2023-01-04 10:42:18 +00:00
james
2dc7da07bd Merge remote-tracking branch 'upstream/codeql-cli-2.11.6' into codeql-cli-2.11.5-docs-mergeback 2023-01-04 10:40:41 +00:00
Chris Smowton
353573bf31 Merge pull request #11701 from owen-mc/go/count-fields-correctly
Go: Count fields correctly
2023-01-04 10:38:36 +00:00
Kasper Svendsen
9ad572fa29 Add inline_late pragma to QL language spec 2023-01-04 11:28:08 +01:00
James Fletcher
413b4c6eb0 Merge pull request #11554 from github/siaramist/codeql-template
Update intro tutorial to include Codespaces CodeQL template
2023-01-04 09:56:36 +00:00
Erik Krogh Kristensen
cedc9c0bff Merge pull request #11582 from erik-krogh/heuristics
JS: Add experimental variants of common security queries with more sources
2023-01-04 10:46:19 +01:00
Harry Maclean
4d228bcddf Ruby: Recognise more string-valued variables
This increases the sensitivity of our barrier guards.
2023-01-04 11:45:10 +13:00
Harry Maclean
9944252c43 Ruby: Add test for barrier guards
This demonstrates that we are missing a guard when a case branch
compares against a string-valued variable rather than a string literal.
2023-01-04 11:45:10 +13:00
Harry Maclean
698a679c78 Ruby: add test 2023-01-04 11:45:10 +13:00
Harry Maclean
0fbb6bf608 Ruby: Make array inclusion barrier more sensitive 2023-01-04 11:45:09 +13:00
Jami Cogswell
abe501c1af Java: add change note 2023-01-03 17:15:50 -05:00
Aditya Sharad
9988c19a42 Merge branch 'main' into tutorial/library-pack 2023-01-03 14:08:37 -08:00
Jami Cogswell
5d92792e40 Java: update test case affected by Function.apply model 2023-01-03 16:14:08 -05:00
Jami Cogswell
feaae16f7c Java: adjust comments 2023-01-03 16:08:14 -05:00
Ed Minnix
0be8648a9d Add changenote 2023-01-03 15:55:53 -05:00
Ed Minnix
28f555c2b2 Add simple test case for @JavascriptInterface parameter flow 2023-01-03 15:31:40 -05:00
Ed Minnix
ab7ca1d642 Java: Add parameters of @JavascriptInterface methods as a remote flow sources 2023-01-03 15:31:40 -05:00
Ed Minnix
f9b8200009 Add stub for android.webkit.JavascriptInterface annoation 2023-01-03 15:31:40 -05:00
Edward Minnix III
69fd5e93bc Merge pull request #28 from egregius313/egregisu313/webview-setAllowContentAccess-single-query
Merge `setAllowContentAccess` queries into singular query
2023-01-03 15:27:09 -05:00
Ed Minnix
81df89f93e Use proper @id in changenote 2023-01-03 15:19:26 -05:00
Ed Minnix
28ad9d00fb Merge both setAllowContentAccess queries into one query
Previously, the query to detect whether or not access to `content://`
links was done using two queries.

Now they can be merged into one query
2023-01-03 15:17:07 -05:00
Jami Cogswell
29221ae426 Java: add summary model for System.getProperty, adjust comments 2023-01-03 15:11:21 -05:00
Jami Cogswell
21a018e5c5 Java: add summary model and test for File.getName 2023-01-03 13:12:24 -05:00
Geoffrey White
e5a74cb29c Swift: Add a reference for swift/hardcoded-key. 2023-01-03 17:27:31 +00:00
Chris Smowton
c5138674a4 Merge pull request #11800 from github/smowton/admin/delete-install-deps
Remove Go's install-deps.sh script
2023-01-03 17:16:15 +00:00
Geoffrey White
fc646a6d48 Swift: Update .expected following a toString change in main. 2023-01-03 16:25:14 +00:00
Geoffrey White
e05bb7fcee Merge branch 'main' into format 2023-01-03 15:14:55 +00:00
Michael Nebel
17cd182d72 C#: Update stats based on projects. 2023-01-03 15:44:47 +01:00
Calum Grant
b3a3957dc9 Merge pull request #11741 from github/calumgrant/remove-lgtm
Remove references to LGTM in code
2023-01-03 14:23:38 +00:00
Michael Nebel
9d608a78a3 C#: Add change note on renamed query ids. 2023-01-03 15:18:22 +01:00
Michael Nebel
bfe5a0c438 C#: Rename query id's to be prefixed with cs instead of csharp. 2023-01-03 15:13:54 +01:00
Jeroen Ketema
5f4326f2bf C++: Mark a number of private predicates in the GVN library as deprecated
This silences a number of warnings related to GVN deprecation.
2023-01-03 12:47:36 +01:00
Chris Smowton
781e96e2a0 Remove Go's install-deps.sh script 2023-01-03 10:45:06 +00:00
Calum Grant
ad55706527 Merge branch 'main' into calumgrant/remove-lgtm 2023-01-03 10:27:30 +00:00
Jeroen Ketema
dcd0be04c4 Merge pull request #11794 from sigfaulterror/main
Update annotations-in-java.rst
2023-01-02 17:13:14 +01:00
erik-krogh
3811eae679 simplify the qhelp for unsafe-code-construction
The `send()` example is not flagged by any current query, so it was weird talking about it as "vulnerable".
2023-01-02 13:33:56 +01:00
Arthur Baars
1092326699 Merge pull request #11796 from erik-krogh/fixBinding
Ruby: Fix compile error in test
2023-01-02 13:26:20 +01:00
sigfaulterror
1dd545ed99 Update annotations-in-java.rst
A typo in the SuppressWarnings's annotation value, it should be `deprecation` and not `deprecated`.
2023-01-02 13:24:17 +01:00
Erik Krogh Kristensen
79a2b6d0b0 use any() instead of this = this
Co-authored-by: Arthur Baars <aibaars@github.com>
2023-01-02 10:49:54 +01:00
erik-krogh
99dc0a8356 fix binding 2023-01-02 10:30:28 +01:00
erik-krogh
3815a5a096 fix qhelp syntax 2023-01-02 10:19:05 +01:00
Ed Minnix
35de551f6b Formatting 2022-12-31 17:19:49 -05:00
Ed Minnix
515fa21aad Change notes 2022-12-31 17:18:37 -05:00
Ed Minnix
df1a4d2ed1 Documentation fix: Add state1 and state2 to documentation 2022-12-31 15:25:37 -05:00
Ed Minnix
68392aa8d8 Fix test expectations 2022-12-31 15:25:25 -05:00
Ed Minnix
02f70f3536 Add @security-severity tag 2022-12-31 15:00:28 -05:00
Edward Minnix III
1d345c6101 Refactoring and simplification
Co-authored-by: Tony Torralba <atorralba@users.noreply.github.com>
2022-12-31 15:00:28 -05:00
Ed Minnix
9ef319f659 Java: setAllowContentAccess query tests 2022-12-31 15:00:28 -05:00
Ed Minnix
5265cb4b03 Merge two dataflow configurations into one taint tracking 2022-12-31 15:00:28 -05:00
Ed Minnix
973f649e76 Break dataflow into two steps in order to capture flow from WebView to settings call 2022-12-31 15:00:28 -05:00
Ed Minnix
0e15dd9fa9 Query metadata 2022-12-31 15:00:28 -05:00
Edward Minnix III
778749184b Change id to use android/ instead of prepending android-
Co-authored-by: Tony Torralba <atorralba@users.noreply.github.com>
2022-12-31 15:00:28 -05:00
Ed Minnix
da25c586e6 Dataflow query for detecting paths that disable content access
Since the default value is `true`, we need to determine whether or not
the `setAllowContentAccess` method is ever called using dataflow.
2022-12-31 15:00:28 -05:00
Ed Minnix
8a763015e6 Reduce precision rating to medium
This query won't always be a security problem, so it should have a lower
precision rating than `high`.
2022-12-31 15:00:28 -05:00
Ed Minnix
7cc53126f3 Java: WebView setAllowContentAccess query test cases 2022-12-31 15:00:28 -05:00
Ed Minnix
a023726c03 Java: add Android stubs to options file for CWE-200 tests 2022-12-31 15:00:28 -05:00
Ed Minnix
e4e13d38b7 Java: query for Android WebView setAllowContentAccess 2022-12-31 15:00:28 -05:00
Ed Minnix
e259ef5d1d Java: Add class for android.webkit.WebSettings.setAllowContentAccess 2022-12-31 15:00:28 -05:00
Calum Grant
2d0f8798a4 Py: Reformat test 2022-12-28 11:05:48 +00:00
Harry Maclean
a6571a05ab Ruby: Include send example in qhelp 2022-12-28 11:34:55 +13:00
Harry Maclean
d3812f5906 Ruby: Add another code injection example to qhelp 2022-12-28 11:20:56 +13:00
Harry Maclean
b70ca77afc Merge pull request #10899 from hmac/flow-summary-docs
Ruby: Document flow summary syntax
2022-12-28 10:47:38 +13:00
Erik Krogh Kristensen
9c255b6c16 Merge pull request #11786 from erik-krogh/fix-nomagic-termination
QL: fix catastrophic join-order in `ql/cand-missing-nomagic`
2022-12-24 10:54:51 +01:00
erik-krogh
9e63390c78 fix that ql/cand-missing-nomagic had a catastrophic join-order 2022-12-23 21:20:30 +01:00
Tony Torralba
07d99bd643 Add path injection sinks 2022-12-23 17:16:06 +01:00
Tony Torralba
4215a89bc8 Add cleartext storage database sinks 2022-12-23 17:15:59 +01:00
Tony Torralba
ac39aeb6b6 Add SQLi sinks 2022-12-23 17:03:31 +01:00
Erik Krogh Kristensen
393a8c2bd8 Merge pull request #11630 from erik-krogh/useInstanceOf
QL4QL: enable medium precision queries, and make the "suggest instanceof" query louder
2022-12-23 14:22:23 +01:00
Henry Mercer
6be790929d Specify language names in extractor packs 2022-12-23 13:15:04 +00:00
Jami Cogswell
939279af38 Java: add comments 2022-12-22 16:25:12 -05:00
Jami Cogswell
673d37cc3d Java: update Math.min test case 2022-12-22 14:36:06 -05:00
Jami Cogswell
a81c54b58c Java: updates to order alphabetically 2022-12-22 13:22:12 -05:00
Jami Cogswell
e6331dc2e6 Java: update test case affected by Long.parseLong summary model 2022-12-22 12:57:37 -05:00
Jami Cogswell
997219a280 Java: update test case affected by Class.isAssignableFrom neutral model 2022-12-22 12:54:02 -05:00
Jami Cogswell
6007827dd3 Java: update test cases 2022-12-22 12:29:57 -05:00
Mathias Vorreiter Pedersen
98c30b8545 Merge pull request #11761 from MathiasVP/ir-for-microsoft-try-except-finally
C++: Generate IR for `__try __finally` and `__try __except`
2022-12-22 11:23:01 +00:00
Erik Krogh Kristensen
7201071084 Merge pull request #11777 from erik-krogh/use-new-cache
CI: use the new actions/cache@v3 instead of my own fork
2022-12-22 12:15:14 +01:00
Erik Krogh Kristensen
c4883925bb Merge pull request #11519 from erik-krogh/equiv
QL: Mock the `QlBuiltins` module in QL-for-QL
2022-12-22 12:14:57 +01:00
Mathias Vorreiter Pedersen
b330b628e3 Merge pull request #11595 from d10c/swift/extract-mainactor
Swift: MethodRefExpr -> MethodLookupExpr
2022-12-22 10:22:33 +00:00
Tony Torralba
36ca97e4f6 Add exclusions to reduce FP
Predicate parameters that have a database type are excluded.

Also, uses of the exists variable in an agreggation or another quantifier are excluded.
2022-12-22 11:15:07 +01:00
erik-krogh
b3dd50bc36 inline Location into the shared implementation of InlineExpectationsTest 2022-12-22 11:09:43 +01:00
Mathias Vorreiter Pedersen
a974cb1861 C++: Add another test with an _actual_ throw. 2022-12-22 10:01:41 +00:00
Mathias Vorreiter Pedersen
5fa968138c C++: Add another test case with a throw. 2022-12-22 09:38:57 +00:00
Rasmus Lerchedahl Petersen
08e9d3391f swift: use shared inline tests
- add util shared pack to swift
 - remove from identical-files
2022-12-22 10:20:07 +01:00
Rasmus Lerchedahl Petersen
b0d7998342 go: use shared inline tests
- remove from identical-files
2022-12-22 10:20:07 +01:00
Rasmus Lerchedahl Petersen
f28eb6bf31 ql4ql: use shared inline tests
- add util shared pack to ql
 - remove from identical-files
2022-12-22 10:20:07 +01:00
Rasmus Lerchedahl Petersen
0d6c643d77 ruby: use shared inline tests
- remove from identical-files
2022-12-22 10:20:07 +01:00
Rasmus Lerchedahl Petersen
4667068017 java: use shared inline tests
- remove from identical-files
2022-12-22 10:20:06 +01:00
Rasmus Lerchedahl Petersen
a9b232bff4 csharp: use shared inline tests
- remove from identical-files
2022-12-22 10:20:06 +01:00
Rasmus Lerchedahl Petersen
d97e185994 cpp: use shared inline tests
- remove from identical-files
2022-12-22 10:20:06 +01:00
Rasmus Lerchedahl Petersen
e8d3802ee5 Python: use shared inline tests
- remove from identical-files
2022-12-22 10:20:05 +01:00
Rasmus Lerchedahl Petersen
b767dcfd18 shared: Add shared inline expectation test library 2022-12-22 10:20:05 +01:00
Jami Cogswell
de5965525f Java: add initial test cases for summary models 2022-12-21 16:19:37 -05:00
erik-krogh
38bd4d9b12 update expected output to have more copies of "T" 2022-12-21 21:45:59 +01:00
erik-krogh
dbdc7275fc have unique parents, also for mock AST nodes 2022-12-21 21:38:52 +01:00
erik-krogh
5728e3ee8f Merge branch 'main' into equiv 2022-12-21 21:28:32 +01:00
erik-krogh
b4dddc07f1 use the new actions/cache@v3 instead of my own fork 2022-12-21 21:10:55 +01:00
Jami Cogswell
c251da799f Java: update TopJdkApis test 2022-12-21 13:19:09 -05:00
Jami Cogswell
16de30e07e Java: add java.util.stream models 2022-12-21 13:05:23 -05:00
Jami Cogswell
1db829e55c Java: add java.util models 2022-12-21 13:03:57 -05:00
Jami Cogswell
573de92441 Java: add java.util.function models 2022-12-21 12:59:58 -05:00
Jami Cogswell
a8c55ee4b7 Java: add java.util.concurrent models 2022-12-21 12:59:00 -05:00
Jami Cogswell
db0d24fdd1 Java: add java.util.concurrent.atomic models 2022-12-21 12:57:22 -05:00
Jami Cogswell
cfe075ef54 Java: add java.time models 2022-12-21 12:54:35 -05:00
Jami Cogswell
8e20aeb314 Java: add java.text models 2022-12-21 12:51:44 -05:00
Jami Cogswell
b9ce588076 Java: add java.sql models 2022-12-21 12:49:29 -05:00
Jami Cogswell
1544f49f91 Java: add java.math models 2022-12-21 12:47:32 -05:00
Jami Cogswell
ed534b06d5 Java: add java.lang models 2022-12-21 12:45:12 -05:00
Jami Cogswell
99ddd484be Java: add java.io models 2022-12-21 12:34:26 -05:00
Edward Minnix III
b77923f6e6 Merge pull request #11767 from atorralba/atorralba/java/fix-pinning-tests
Java: Small simplification in Missing Certificate Pinning tests
2022-12-21 11:21:47 -05:00
Edward Minnix III
597523e65a Merge pull request #11766 from atorralba/atorralba/java/fix-android-query-id
Java: Fix new Android queries' IDs
2022-12-21 11:21:12 -05:00
Tony Torralba
7d0018c897 Update ql/ql/src/queries/style/OmittableExists.ql 2022-12-21 17:16:34 +01:00
Tony Torralba
ac0c42c5c6 Apply suggestions from code review
Co-authored-by: Erik Krogh Kristensen <erik-krogh@github.com>
2022-12-21 16:16:58 +01:00
Mathias Vorreiter Pedersen
bbf0ec81ab C++: Fix implicit this. 2022-12-21 14:41:51 +00:00
Mathias Vorreiter Pedersen
ff6e8a285d C++: Model semantics of '__except' condition in IR. 2022-12-21 14:08:26 +00:00
Mathias Vorreiter Pedersen
e6a03a6152 C++: Fix exception handling for '__try __except'. 2022-12-21 14:08:26 +00:00
Arthur Baars
ebfc6eba95 Merge pull request #11773 from aibaars/alert-suppression-swift
Swift: add AlertSuppression.ql
2022-12-21 14:32:10 +01:00
Arthur Baars
7111d950c1 Swift: add AlertSuppression.ql 2022-12-21 13:15:26 +01:00
Arthur Baars
dceb142551 Merge pull request #11771 from aibaars/alert-suppression-fix-test
AlertSuppression: fix python test cases
2022-12-21 13:14:59 +01:00
Henry Mercer
ea6a01a9ea Merge pull request #11765 from github/dependabot/github_actions/actions/stale-7
Bump actions/stale from 6 to 7
2022-12-21 11:43:46 +00:00
Tony Torralba
227e099854 Apply code review suggestions
Co-authored-by: Mathias Vorreiter Pedersen <mathiasvp@github.com>
2022-12-21 12:40:29 +01:00
Tony Torralba
aa1d49cb95 Add OmittableExists QL-for-QL query 2022-12-21 12:26:58 +01:00
Arthur Baars
2f16d8d86a AlertSuppression: fix python test cases 2022-12-21 11:26:16 +01:00
Arthur Baars
98c5b81456 Merge pull request #11723 from aibaars/alert-suppression
CodeQL alert suppression
2022-12-21 10:59:57 +01:00
Arthur Baars
035ad65e43 AlertSuppression: move library into util folder 2022-12-21 10:39:57 +01:00
yoff
4480262bd1 Merge pull request #11244 from github/python/support-grouped-exceptions
Python: support grouped exceptions
2022-12-21 10:10:37 +01:00
Tony Torralba
ab73d13d8b Small simplification 2022-12-21 09:58:13 +01:00
Tony Torralba
345c383acc Fix new Android queries' IDs 2022-12-21 09:36:57 +01:00
Tony Torralba
690dd47990 Merge pull request #11764 from github/workflow/coverage/update
Update CSV framework coverage reports
2022-12-21 09:30:29 +01:00
Nora Dimitrijević
aaadf198ab Swift: fix 'ql/redundant-import' 2022-12-20 23:32:38 -05:00
Nora Dimitrijević
fbb14797b1 Merge branch 'main' into swift/extract-mainactor 2022-12-20 23:20:37 -05:00
Nora Dimitrijević
101f42ab3d Revert "Swift: silence QL-for-QL "Redundant override" FP"
This reverts commit 56a72d7c37.
2022-12-20 23:17:45 -05:00
Nora Dimitrijević
f3ebb6e03b Swift: MethodLookupExpr.getMethodRef() [codegen'd]
This refactors SelfApplyExpr.getFunction() as MethodLookupExpr().getMethodRef().

This is simpler, because we are not hiding DeclRefExprs or reinventing hidden AST resolution.
2022-12-20 23:09:02 -05:00
Nora Dimitrijević
4900e4030a Swift: MethodLookupExpr.getMethodRef() [hand-written]
This refactors SelfApplyExpr.getFunction() as MethodLookupExpr().getMethodRef().

This is simpler, because we are not hiding DeclRefExprs or reinventing hidden AST resolution.
2022-12-20 23:08:32 -05:00
dependabot[bot]
a5bb13f2b6 Bump actions/stale from 6 to 7
Bumps [actions/stale](https://github.com/actions/stale) from 6 to 7.
- [Release notes](https://github.com/actions/stale/releases)
- [Changelog](https://github.com/actions/stale/blob/main/CHANGELOG.md)
- [Commits](https://github.com/actions/stale/compare/v6...v7)

---
updated-dependencies:
- dependency-name: actions/stale
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-21 03:12:32 +00:00
github-actions[bot]
eb98bb2842 Add changed framework coverage reports 2022-12-21 00:15:01 +00:00
Owen Mansel-Chan
3eb419eb1a Give context for code examples 2022-12-20 22:20:13 +00:00
Aditya Sharad
d2ee8c08c0 Ruby: Add shared tutorial pack to testing bundle 2022-12-20 10:56:05 -08:00
Mathias Vorreiter Pedersen
f0ba33ae74 C++: Accept test changes. 2022-12-20 18:19:18 +00:00
Erik Krogh Kristensen
a1639c438f Merge pull request #11762 from erik-krogh/fixParent
QL: fix `getAnnotation()` for new-type branches with parameters
2022-12-20 18:18:39 +01:00
erik-krogh
ab9855e196 fix getAnnotation() for new-type branches with parameters 2022-12-20 15:55:54 +01:00
Paolo Tranquilli
454af0d721 Swift: fix locking of output swiftmodule trap 2022-12-20 15:34:18 +01:00
Paolo Tranquilli
a1161c6efe Swift: remove header patch which is not needed any more 2022-12-20 15:28:52 +01:00
Paolo Tranquilli
725861626c Merge branch 'main' into redsun82/swift-open-redirection 2022-12-20 15:28:30 +01:00
Jami
c9258effb6 Merge pull request #11572 from jcogs33/jcogs33/model-top-jdk-apis
Java: model top 100 JDK APIs
2022-12-20 09:13:53 -05:00
Mathias Vorreiter Pedersen
07ab119b8c C++: Add explicit qualifiers. 2022-12-20 13:38:50 +00:00
Mathias Vorreiter Pedersen
d2964a7d4a C++: Also handle '__finally' blocks. 2022-12-20 13:28:33 +00:00
Mathias Vorreiter Pedersen
3c8efa88e0 C++: Handle Microsoft '__try __except' in the existing 'TryStmt' IR logic. 2022-12-20 13:28:28 +00:00
Mathias Vorreiter Pedersen
cd6e421cf5 C++: Add a test with '__try __except' and '__try __finally' in the 'ir' test directory. 2022-12-20 13:28:22 +00:00
Tony Torralba
30aa9b230c Apply suggestions from code review
Co-authored-by: Ben Ahmady <32935794+subatoi@users.noreply.github.com>
2022-12-20 14:14:05 +01:00
erik-krogh
57f429ec5d change this = this to any() 2022-12-20 13:56:25 +01:00
Erik Krogh Kristensen
0cc3232c10 fix typo
Co-authored-by: Arthur Baars <aibaars@github.com>
2022-12-20 13:56:25 +01:00
erik-krogh
0a828f7b31 fix the left()/right() predicates such that they return an Either 2022-12-20 13:56:25 +01:00
erik-krogh
b1001d1a10 make TypeWithToString private inside the shared pack 2022-12-20 13:56:25 +01:00
erik-krogh
0e426090f2 update expected output 2022-12-20 13:56:23 +01:00
Jami
dc0bad3dc5 update change note
Co-authored-by: yo-h <55373593+yo-h@users.noreply.github.com>
2022-12-20 07:55:58 -05:00
erik-krogh
605bfd6e93 move the "I don't care about parent relation on mocks" hack into the predicate, so the tests dont fail 2022-12-20 13:55:49 +01:00
erik-krogh
54072d29f1 add explicit this 2022-12-20 13:55:49 +01:00
erik-krogh
49277f553f model the last parts of the EquivalenceRelation module 2022-12-20 13:55:49 +01:00
erik-krogh
a11e618cfc mock parameters 2022-12-20 13:55:49 +01:00
erik-krogh
4feb48ce5f classless predicate, used to model the edgeSig predicate 2022-12-20 13:55:49 +01:00
erik-krogh
4dc52379ad add a mock TypeExpr, and use it 2022-12-20 13:55:49 +01:00
erik-krogh
5db2f0aba0 mock classes, and add a Mock T class to QlBuiltins 2022-12-20 13:55:49 +01:00
erik-krogh
b7e0d1f8b3 don't include mock Ast nodes in PrintAst.ql 2022-12-20 13:55:49 +01:00
erik-krogh
51d5e881de add an Ast mocking library, and use it to create mocks of the QlBuiltins and EquivalenceRelation modules 2022-12-20 13:55:48 +01:00
erik-krogh
0ca38faa4d add test of buildins 2022-12-20 13:54:38 +01:00
erik-krogh
236e6db996 fix typos 2022-12-20 13:54:02 +01:00
erik-krogh
50a91b5017 shared: add a shared Either type 2022-12-20 13:54:02 +01:00
Erik Krogh Kristensen
073e9bc52f Merge pull request #11173 from erik-krogh/notDead
QL: improve the dead-code query
2022-12-20 13:36:58 +01:00
Erik Krogh Kristensen
b1e6a86a4b Merge pull request #11757 from erik-krogh/treesitter-qldoc
QL/RB: make top TreeSitter.qll comment into a qldoc
2022-12-20 13:36:31 +01:00
Rasmus Lerchedahl Petersen
f5e33ac00a Merge remote-tracking branch 'origin/main' into python/support-grouped-exceptions 2022-12-20 13:31:50 +01:00
Erik Krogh Kristensen
b5b0a64081 Merge pull request #11751 from jacola/main
Fix javascript syntax
2022-12-20 13:02:23 +01:00
Rasmus Lerchedahl Petersen
ad6ed2f629 python: update expectations
extra tests
2022-12-20 13:01:27 +01:00
Erik Krogh Kristensen
6be223ad6d Merge pull request #11756 from aibaars/fix-ql-module-parameter
QL: fix visibility of module parameters
2022-12-20 12:59:07 +01:00
erik-krogh
2ff23a6fc0 make top TreeSitter.qll comment into a qldoc 2022-12-20 11:39:06 +01:00
Arthur Baars
c8255770bc QL: fix visibility of module parameters 2022-12-20 11:22:20 +01:00
Tony Torralba
149cae9603 Merge pull request #10971 from joefarebrother/android-certificate-pinning
Java: Add Android missing certificate pinning query (CWE-295)
2022-12-20 11:03:16 +01:00
Arthur Baars
bad5c65144 Add test 2022-12-20 10:37:57 +01:00
Mathias Vorreiter Pedersen
cbe330eb7b Merge pull request #11693 from jketema/argv-param-flowsource
C++: Define the `argv` flow source in terms the input parameter
2022-12-20 09:30:19 +00:00
Tony Torralba
3e7a819fe7 Simplification 2022-12-20 09:42:25 +01:00
Jeroen Ketema
edc768b43b Merge pull request #11707 from smowton/smowton/fix/java-empty-multiline-comment
Java: handle printing an empty comment (/**/); add relevant tests
2022-12-20 08:07:42 +01:00
Jacques
b99c500435 Fix associated test 2022-12-20 12:51:13 +09:00
Jacques
97b8126385 Fix javascript 2022-12-20 12:45:59 +09:00
Sid Shankar
52cafdf25f Merge pull request #11745 from github/sidshank/remove-lgtm-for-go 2022-12-19 21:49:02 -05:00
Aditya Sharad
bcd711a708 Tutorial: Add separate QLDoc for Person class
By moving the existing doc comment to the top level,
that comment is shown when a user hovers over the module name
in `import tutorial`.
2022-12-19 15:54:12 -08:00
Aditya Sharad
ed29b3e4d6 Shared packs: Depend on codeql/tutorial from all language libraries
This allows `import tutorial` from queries targeting
any language, just like before, while removing the
duplicate copies of `tutorial.qll`.
2022-12-19 15:52:11 -08:00
Aditya Sharad
d772998bc7 Shared packs: Create codeql/tutorial library pack
This contains the QL detective tutorial library
in `tutorial.qll`, so that it can be shared by
all language libraries and referenced on its own.
2022-12-19 15:52:11 -08:00
Nora Dimitrijević
1c64bf4bbc Swift: remove superfluous newline 2022-12-19 18:00:20 -05:00
Nora Dimitrijević
55c6e565f7 Swift: PrintAst.qll nodes() ordering fix not needed
No-double-parents should be sufficient for a stable top-level ordering.
2022-12-19 17:52:20 -05:00
Nora Dimitrijević
8b0da01e0d Swift: allow self./super. sinks in StaticInitializationVector
Assumption: the extra path is not an issue in practice as the body of
the cryptographic library's init methods are not normally extracted,
only the stubs in this test are.
2022-12-19 17:39:44 -05:00
Nora Dimitrijević
3da54ebc61 Swift: give a clearer name to {Self,Super}RefExpr.getMethodDecl 2022-12-19 17:33:13 -05:00
Nora Dimitrijević
56a72d7c37 Swift: silence QL-for-QL "Redundant override" FP 2022-12-19 16:45:31 -05:00
Sid Shankar
ae3e25786f Remove LGTM references from README.md + cleanup 2022-12-19 20:51:01 +00:00
Sid Shankar
35000e5d7e Remove LGTM reference from CONTRIBUTING.md 2022-12-19 20:12:23 +00:00
Jami Cogswell
19deb59d07 Java: sort neutral models alphabetically 2022-12-19 14:22:17 -05:00
Calum Grant
cfd79e2006 Py: Put in commented-out test and update expected 2022-12-19 17:29:48 +00:00
Calum Grant
e982e144a4 JS: Update qltest output 2022-12-19 17:22:51 +00:00
Tony Torralba
a47ef17a0d Update java/ql/src/Security/CWE/CWE-295/AndroidMissingCertificatePinning1.java
Co-authored-by: Edward Minnix III <egregius313@github.com>
2022-12-19 18:11:54 +01:00
Chris Smowton
ebc0b0c4d6 Merge pull request #11665 from smowton/smowton/admin/revert-kotlin-default-method-type-erasure
Kotlin: Revert type erasure within $default functions
2022-12-19 16:33:20 +00:00
Edward Minnix III
39a7c7bb12 Merge pull request #11282 from egregius313/egregiu313/webview-addjavascriptinterface
Java: Query for detecting addJavascriptInterface method calls
2022-12-19 11:28:45 -05:00
Tony Torralba
624c9ff834 Update java/ql/src/Security/CWE/CWE-295/AndroidMissingCertificatePinning1.java 2022-12-19 17:26:41 +01:00
Arthur Baars
a8be5d7274 AlertSuppression: add change notes 2022-12-19 17:02:52 +01:00
Arthur Baars
0f313231bc AlertSuppression: add more tests 2022-12-19 16:43:11 +01:00
Jeroen Ketema
0c710479ec C++: Update experimental test changes 2022-12-19 16:35:24 +01:00
Tony Torralba
0c6ace350f Update java/ql/src/Security/CWE/CWE-295/AndroidMissingCertificatePinning.ql
Co-authored-by: mc <42146119+mchammer01@users.noreply.github.com>
2022-12-19 16:24:39 +01:00
Calum Grant
0894059d33 Ruby: Remove reference to LGTM 2022-12-19 15:15:43 +00:00
Calum Grant
a1d229e445 Python: Remove references to LGTM 2022-12-19 15:15:32 +00:00
Calum Grant
4a37c01c5f JavaScript: Remove references to LGTM 2022-12-19 15:15:17 +00:00
Arthur Baars
c9739b21cb AlertSuppression: add support for //codeql comments 2022-12-19 16:10:28 +01:00
Arthur Baars
c176606be5 AlertSuppression: allow //lgtm comments to scope over the next line 2022-12-19 16:10:26 +01:00
Arthur Baars
016c7a8ca7 Merge pull request #11719 from aibaars/alert-suppression-shared
Shared AlertSuppression library
2022-12-19 16:04:44 +01:00
Henning Makholm
ca1c46331a Merge pull request #11731 from github/hmakholm/pr/no-option
remove com.semmle.util.data.Option from from extractor code interface II
2022-12-19 15:36:51 +01:00
Erik Krogh Kristensen
f136651384 Merge pull request #11575 from erik-krogh/kernelLoad
Rb: add Kernel methods as sinks to path-injection
2022-12-19 15:09:21 +01:00
Jami Cogswell
a8ee633acd Java: apply review suggestions 2022-12-19 09:09:01 -05:00
James Fletcher
55a04e7ff8 Merge pull request #11736 from github/jf205-patch-1
Update query-classification-and-display.md
2022-12-19 14:00:21 +00:00
Jami Cogswell
f37f0a09aa Java: update change note 2022-12-19 08:41:56 -05:00
Jami Cogswell
42ddd66360 Java: add hasApiName predicate 2022-12-19 08:38:12 -05:00
erik-krogh
66be8cda06 remove more of the implementation into ConditionalBypassQuery.qll 2022-12-19 14:37:19 +01:00
Arthur Baars
8be882f815 Update javascript/ql/src/AlertSuppression.ql
Co-authored-by: Erik Krogh Kristensen <erik-krogh@github.com>
2022-12-19 14:35:16 +01:00
erik-krogh
d0af30b40a cleanup the implementation of toString() for `SuperCall 2022-12-19 14:28:01 +01:00
James Fletcher
23047d8246 Delete query-classification-and-display.md 2022-12-19 13:24:52 +00:00
James Fletcher
af5de55d1f Merge pull request #11737 from github/jf205-patch-2
Update supported-queries.md
2022-12-19 13:22:10 +00:00
Arthur Baars
682bf6d3a7 Apply suggestions from code review
Co-authored-by: Erik Krogh Kristensen <erik-krogh@github.com>
2022-12-19 14:16:05 +01:00
Chris Smowton
2ca56e0c1e Java: handle printing an empty comment (/**/); add relevant tests 2022-12-19 14:12:09 +01:00
James Fletcher
75b63bbb0e Update supported-queries.md
Removes mentions of LGTM.
2022-12-19 13:11:31 +00:00
James Fletcher
af60851233 Update query-classification-and-display.md
Removes the section about queries run on LGTM.com.
2022-12-19 12:52:32 +00:00
Jeroen Ketema
edd29f4b0e C++: Add change note 2022-12-19 13:50:50 +01:00
yoff
5f0cde5be7 Merge branch 'main' into python/support-grouped-exceptions 2022-12-19 13:38:25 +01:00
yoff
d4eb2b964c Merge pull request #11699 from erik-krogh/shareHost
Dynamic: Share more regexp code
2022-12-19 13:29:53 +01:00
Jeroen Ketema
ed33b905a6 C++: Simplify cpp/path-injection now argv sources are parameters 2022-12-19 12:54:16 +01:00
Jeroen Ketema
7549915773 C++: Accept test changes 2022-12-19 12:52:35 +01:00
Arthur Baars
06736e3e91 Add .gitattributes for Windows test files 2022-12-19 12:39:01 +01:00
Arthur Baars
f68e18cd9c Python: move AlertSuppression.ql 2022-12-19 12:39:01 +01:00
Arthur Baars
acb5d6e163 Python: use shared AlertSuppression.qll 2022-12-19 12:26:12 +01:00
Arthur Baars
621a108846 Ruby: use shared AlertSuppression.qll 2022-12-19 12:26:06 +01:00
Arthur Baars
453045e276 C#: use shared AlertSuppression.qll 2022-12-19 12:25:50 +01:00
Arthur Baars
ad80822a52 C/C++: use shared AlertSuppression.qll 2022-12-19 12:25:46 +01:00
Arthur Baars
b0e8085765 Go: use shared AlertSuppression.qll 2022-12-19 12:25:21 +01:00
Arthur Baars
23f595bea1 JavaScript: use shared AlertSuppression.qll 2022-12-19 12:25:17 +01:00
Jeroen Ketema
a73bd050f7 C++: Define the argv flow source in terms the input parameter 2022-12-19 12:13:39 +01:00
Jeroen Ketema
2705aebbbc C++: Restrict CWE-119 semmle tests to have a single main function 2022-12-19 12:13:37 +01:00
Tony Torralba
484a16ce1b Update java/ql/src/Security/CWE/CWE-295/AndroidMissingCertificatePinning.ql 2022-12-19 12:10:32 +01:00
Arthur Baars
bc646d407e Java: use shared AlertSuppression.qll 2022-12-19 12:07:28 +01:00
Arthur Baars
072a180093 Util: add AlertSuppression.qll 2022-12-19 12:06:36 +01:00
erik-krogh
442749bb7f JS: add heuristic variants of queries that use RemoteFlowSource 2022-12-19 12:01:22 +01:00
Tony Torralba
a880fecc8b Apply suggestions from code review
Co-authored-by: mc <42146119+mchammer01@users.noreply.github.com>
2022-12-19 11:56:36 +01:00
erik-krogh
2f84b21c7f QL: add getQueryName to QueryDoc 2022-12-19 11:29:20 +01:00
erik-krogh
6c8b1cf4be changes based on Python review 2022-12-19 11:20:31 +01:00
Jean Helie
31f7702a04 Merge pull request #11726 from github/jhelie/fix-endpoint-large-scale-script
ATM: fix script updating endpoint large scale test data
2022-12-19 10:55:30 +01:00
Michael Nebel
0661627248 Merge pull request #11733 from michaelnebel/csharp/updatestats
C#: Add dummy type sizes for the list pattern expressions kinds.
2022-12-19 10:51:06 +01:00
erik-krogh
db49cfb723 Merge branch 'main' into kernelLoad 2022-12-19 09:46:25 +01:00
Erik Krogh Kristensen
08240e2d65 Merge pull request #11661 from erik-krogh/even-faster-atm-ci
ATM: speedup the "ATM - Check query suite" CI job
2022-12-19 09:14:07 +01:00
Michael Nebel
b9f668b320 C#: Add dummy type sizes for the list pattern expressions kinds. 2022-12-19 09:10:35 +01:00
Jami Cogswell
f933fc75cd Java: update another test affected by Integer.parseInt, and one affected by String.length 2022-12-18 21:46:43 -05:00
Jami Cogswell
f3fc68352e Java: update tests affected by Integer.parseInt model 2022-12-18 19:43:32 -05:00
erik-krogh
35e8d6afd4 move getACommonTld into a utility module without parameters 2022-12-18 17:23:45 +01:00
erik-krogh
ba7321ac5c add qldoc to RegExpCharEscape 2022-12-18 17:23:45 +01:00
erik-krogh
26c5480ee6 share {js,rb}/regex/missing-regexp-anchor 2022-12-18 17:23:41 +01:00
turbo
d1d4163b79 Exclude cpp/wrong-use-of-the-umask 2022-12-18 15:55:04 +01:00
turbo
b7c33734b1 Merge remote-tracking branch 'origin/turbo/experimental/combined' into turbo/experimental/combined 2022-12-18 15:44:53 +01:00
turbo
1e5426fca2 Create security-experimental suite helper and all language suite implementations 2022-12-18 15:44:08 +01:00
erik-krogh
355499ea52 move getACommonTld to the shared pack 2022-12-17 17:26:18 +01:00
erik-krogh
f67d0bc8c0 put the shared HostnameRegexp code in the shared regex pack 2022-12-17 17:26:18 +01:00
Jami Cogswell
1d916a2baa Java: clean up 2022-12-16 16:16:56 -05:00
Jami Cogswell
0c22d68a65 Java: update extensible predicate names 2022-12-16 15:40:14 -05:00
Jami
ff652f7dee Merge branch 'main' into jcogs33/model-top-jdk-apis 2022-12-16 15:32:50 -05:00
Jami Cogswell
9762423fbc Java: add more test cases 2022-12-16 15:26:54 -05:00
Henning Makholm
3e85e9f7d9 remove com.semmle.util.data.Option from from extractor code interface II
com.semmle.util.data.Option is going away. Switch the single
cross-repo call that mentions it to use the new Option-less overload
that was introduced in semmle-code PR 44626.
2022-12-16 19:03:20 +01:00
Henry Mercer
30451ee950 Merge pull request #11681 from github/henrymercer/mergeback-3.8
Merge `rc/3.8` back to `main`
2022-12-16 17:43:12 +00:00
Jami Cogswell
83630842b6 Java: add change note 2022-12-16 11:49:52 -05:00
Tom Hvitved
e629568eda Merge pull request #11720 from hvitved/ruby/call-sensitive-initialize-bug-fix
Ruby: Fix bug in call-sensitivity logic for `initialize` calls
2022-12-16 16:36:31 +01:00
Jami Cogswell
c0628035fa Java: reduce code duplication 2022-12-16 10:28:34 -05:00
Owen Mansel-Chan
003edeab80 Merge pull request #11706 from owen-mc/fix/go-callback-type-stubs-2
Go: Use any() to stub getCallbackParameter/ReturnType and getSyntheticGlobalType
2022-12-16 14:43:35 +00:00
Jean Helie
938a7e828c update tests 2022-12-16 15:31:43 +01:00
Jeroen Ketema
32800bca96 Merge pull request #11680 from jketema/predefined-typedef-for-float
C++: Update tests after frontend changes
2022-12-16 15:21:58 +01:00
Michael Nebel
e9d27540c8 Merge pull request #11686 from michaelnebel/csharp/refactorforeach
C#: Re-factor and use `ForEach`.
2022-12-16 14:59:58 +01:00
Jami Cogswell
640b450c47 Java: add message column to qltest 2022-12-16 08:51:18 -05:00
Tom Hvitved
5fba5e4895 Merge pull request #11718 from hvitved/ruby/self-allocate
Ruby: Recognize custom `self.new` methods that return `self.allocate`
2022-12-16 14:46:08 +01:00
Jami Cogswell
bf6148c477 Java: fix bot alert, remove metadata from qltest 2022-12-16 08:44:23 -05:00
Jean Helie
cd0220b248 update autogenerated data for endpoint_large_scale 2022-12-16 14:03:01 +01:00
Jean Helie
904a4bd48b fix script updating endpoint_large_scale test data 2022-12-16 14:03:00 +01:00
Rasmus Lerchedahl Petersen
96ae148118 python: also override `getAHandler
(to get new result type)
2022-12-16 13:40:10 +01:00
Rasmus Lerchedahl Petersen
d216460032 python: unnecessary abstract class
It is enough to make the predicates abstract,
so the whole -`Impl`-construction was unnecessary.
2022-12-16 12:43:41 +01:00
Geoffrey White
640f894b00 Merge branch 'main' into format 2022-12-16 11:42:03 +00:00
Rasmus Lerchedahl Petersen
5094897668 python: unify change notes with fixes 2022-12-16 12:37:25 +01:00
Tom Hvitved
bfc257147c Ruby: Fix bug in call-sensitivity logic for initialize calls 2022-12-16 11:17:15 +01:00
Michael Nebel
b2856c1f5a Merge pull request #11705 from michaelnebel/dataextensiontests
C#/Java: Migrate tests to use implicitly loaded extensions.
2022-12-16 10:50:07 +01:00
Tony Torralba
46ea067449 Add bidirectional import in ExternalFlow.qll 2022-12-16 09:59:48 +01:00
Tom Hvitved
e45edcc159 Merge pull request #11674 from hvitved/dataflow/param-context
Data flow: Track callable in flow-through pruning
2022-12-16 09:25:15 +01:00
Tom Hvitved
accf4ca364 Ruby: Recognize custom self.new methods that return self.allocate 2022-12-16 09:23:36 +01:00
Tom Hvitved
b64083d08e Ruby: Add more call graph tests 2022-12-16 09:21:00 +01:00
Michael Nebel
390b8afb8a C#: Re-factor to use ForEach. 2022-12-16 08:24:09 +01:00
Michael Nebel
0230b8b56f C#: Minor cleanup in the Pattern files. 2022-12-16 08:24:09 +01:00
yoff
4ddb503f61 Update python/ql/lib/change-notes/2022-11-14-grouped-exceptions-breaking.md
Co-authored-by: Rasmus Wriedt Larsen <rasmuswl@github.com>
2022-12-16 08:21:29 +01:00
Michael Nebel
89fcc17182 Merge pull request #11594 from michaelnebel/csharp/listpattern
C#: Support List and Slice patterns.
2022-12-16 08:21:07 +01:00
Jami Cogswell
fdcaa93200 Java: update test case 2022-12-15 23:47:17 -05:00
Jami Cogswell
f01ee9e4c2 Java: remove PR-merging comment 2022-12-15 22:56:15 -05:00
Jami Cogswell
08546549bf Java: update exception models and add test 2022-12-15 22:53:14 -05:00
Jami
fd63348549 Merge pull request #11585 from jcogs33/jcogs33/mad-metrics-query
Java: add MaD metrics query
2022-12-15 19:26:51 -05:00
Nora Dimitrijević
938f724602 Swift: fix db upgrade/downgrade script after pull 2022-12-15 16:37:52 -05:00
Jami Cogswell
96a0950048 Java: update test case 2022-12-15 15:49:53 -05:00
Jami Cogswell
c33bc63aed Java: remove extraneous parentheses 2022-12-15 15:26:04 -05:00
Jami Cogswell
cfeedb5cb4 Java: add float cast 2022-12-15 15:23:28 -05:00
Jami Cogswell
b68a9a51e2 Java: add coverage, generatedCoverage, and manualCoverage metrics 2022-12-15 15:20:08 -05:00
Jami Cogswell
9d10b719d6 Java: add match metric 2022-12-15 15:10:35 -05:00
Jami Cogswell
1c5d4f8048 Java: rename generatedCoverage and manualCoverage 2022-12-15 15:03:00 -05:00
Michael Nebel
c34bde962c Java: Update integration tests to use implicit ext.yml data extensions. 2022-12-15 19:01:29 +01:00
Nora Dimitrijević
ea6c69dd34 Swift: fix test with different linux/macos results
`methodlookup.swift` has one more call to `Builtin.zeroInitializer()`
in macOS than it does in Linux.
2022-12-15 11:48:43 -05:00
Nora Dimitrijević
40fb6f98c9 Merge branch 'main' into swift/extract-mainactor 2022-12-15 11:29:12 -05:00
Nora Dimitrijević
893ec33da0 Swift: update .expected for integration tests 2022-12-15 11:28:02 -05:00
Nora Dimitrijević
60727b1e5e Swift: Fix Builtin(Types) test extraction failure 2022-12-15 10:47:10 -05:00
Geoffrey White
1f7d96a74a Merge branch 'main' into format 2022-12-15 15:17:54 +00:00
Tom Hvitved
f8571dd0b6 Data flow: Work around functionality-induced misoptimization 2022-12-15 15:29:14 +01:00
Tom Hvitved
6eda042229 Data flow: Sync files 2022-12-15 15:29:13 +01:00
Tom Hvitved
adc738cb15 Data flow: Simplify reverse flow-through pruning 2022-12-15 15:29:12 +01:00
Tom Hvitved
d34901ac8c Data flow: Track return position instead of return kind
Reverts bdb205a318.
2022-12-15 15:29:12 +01:00
Tom Hvitved
1820bb4b0b Data flow: Simplify forwards flow-through pruning 2022-12-15 15:29:11 +01:00
Tom Hvitved
cb84b557cf Data flow: Track parameter instead of parameter position
Reverts 70d2a0df8a.
2022-12-15 15:29:11 +01:00
Michael Nebel
2034b00772 C#: Remove deprecated ModelCsv classes. 2022-12-15 15:22:52 +01:00
Michael Nebel
0f038ee93a Java: Remove deprecated ModelCsv classes. 2022-12-15 15:22:44 +01:00
Michael Nebel
f8b1fb465b C#: Downgrade script should convert list- and slice pattern to unknown expression kind. 2022-12-15 14:50:22 +01:00
Michael Nebel
352ae7919b C#: Add change note. 2022-12-15 14:50:22 +01:00
Michael Nebel
b4407eefb2 C#: Add downgrade script. 2022-12-15 14:50:22 +01:00
Michael Nebel
2c9e8bcb2d C#: Add upgrade script. 2022-12-15 14:50:22 +01:00
Michael Nebel
88c8eceb4d C#: Add list pattern test and expected results. 2022-12-15 14:50:21 +01:00
Michael Nebel
e6b4055a5f C#: Add list pattern sample file. 2022-12-15 14:50:21 +01:00
Michael Nebel
98e125fa98 C#: Add library support for list- and slice patterns. 2022-12-15 14:50:21 +01:00
Michael Nebel
cfd3c1fcbe C#: Add extractor support for list- and slice patterns. 2022-12-15 14:50:21 +01:00
Michael Nebel
00354a2f08 C#: Add list- and slice pattern expression kinds and re-generate ExprKind.cs. 2022-12-15 14:50:21 +01:00
Michael Nebel
31c60e545e Java: Update the flow test generator to create ext.yml files. 2022-12-15 14:46:20 +01:00
Paolo Tranquilli
7f505d8715 Swift: do not filter frontend actions 2022-12-15 14:39:43 +01:00
Michael Nebel
6dc798f970 Java: Migrate tests to use implicit ext.yml data extensions. 2022-12-15 14:13:07 +01:00
Rasmus Lerchedahl Petersen
3a8fd910b1 python: do not change autogenerated file 2022-12-15 14:02:52 +01:00
Paolo Tranquilli
208388e04d Swift: hard code libc.dylib path on macOS
Also, handle the corner case where loading libc fails.
2022-12-15 13:30:23 +01:00
Owen Mansel-Chan
76a3fa856f Use any() to stub getSyntheticGlobalType
This is used in all other languages not currently using dataflow type
pruning.
2022-12-15 12:24:23 +00:00
Owen Mansel-Chan
1a1b6a1b93 Use any() to stub getCallbackParameter/ReturnType
This is used in all other languages not currently using dataflow type
pruning.
2022-12-15 12:24:23 +00:00
Michael Nebel
100f64c09a C#: Migrate tests to use the implicitly loaded .ext.yml data extensions. 2022-12-15 13:11:09 +01:00
Rasmus Lerchedahl Petersen
a97bbdd0bc python: rework hierarchy to avoid breaking API 2022-12-15 13:01:04 +01:00
Rasmus Lerchedahl Petersen
997e3599f0 python: make tests valid and more fleshed out 2022-12-15 12:54:16 +01:00
Rasmus Lerchedahl Petersen
8e8d36f35e python: this also works in 3.11 2022-12-15 12:54:14 +01:00
Rasmus Lerchedahl Petersen
3ace1ee69f Python: remove obsolete coments 2022-12-15 12:54:13 +01:00
Tony Torralba
6837af97bc Apply suggestions from code review
Co-authored-by: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
2022-12-15 12:35:54 +01:00
Tony Torralba
11c03fb8c9 Add 'good' test cases 2022-12-15 12:35:47 +01:00
Owen Mansel-Chan
039d582060 Fix date in unrelated change note 2022-12-15 11:04:48 +00:00
Owen Mansel-Chan
06038d575e Improve comments about Fields 2022-12-15 11:04:48 +00:00
Owen Mansel-Chan
e01e40c532 Fix FuncTypeExpr.getNumParameter
It actually counts the number of parameter declarations. We correct it
to do what it says and introduce `FuncTypeExpr.getNumParameterDecls`,
which we then use in `FuncTypeExpr.getUniquelyNumberedChild`.
2022-12-15 11:04:48 +00:00
Paolo Tranquilli
3084eda28a Swift: add swiftmodule hash map testing to frontend_invocations 2022-12-15 10:33:47 +01:00
Paolo Tranquilli
e42ae09e1c Swift: fix interaction between bash wrapper and open redirection on macOS 2022-12-15 09:50:31 +01:00
Jami Cogswell
56acfdf672 Java: update test case 2022-12-15 00:57:08 -05:00
Jami Cogswell
510cd4a163 Java: change negative to neutral 2022-12-15 00:46:03 -05:00
Jami Cogswell
f1ddbbb96f Java: update remaining models 2022-12-15 00:33:35 -05:00
Jami Cogswell
46b8fbc4c9 Java: update remaining models, resolve merge conflict 2022-12-15 00:33:06 -05:00
Jami Cogswell
15069250eb Java: add draft of test case 2022-12-15 00:24:41 -05:00
Jami Cogswell
134577e52b Java: some updates to models 2022-12-15 00:24:41 -05:00
Jami Cogswell
4c590d1190 Java: move most negative models to package.model.yml files 2022-12-15 00:24:41 -05:00
Jami Cogswell
b7016feb44 Java: initial updates based on review comments 2022-12-15 00:24:41 -05:00
Jami Cogswell
b3dbf00ae6 Java: update comment 2022-12-15 00:24:41 -05:00
Jami Cogswell
9d3abc72bf Java: add draft of top 100 jdk models 2022-12-15 00:24:40 -05:00
Nora Dimitrijević
7ea0eada11 Swift: add missing Builtin symbols 2022-12-14 20:03:41 -05:00
turbo
5fd5ebc26e Create security-experimental suite helper and all language suite implementations 2022-12-14 23:35:32 +01:00
Nora Dimitrijević
2d288906a4 Swift: fix db downgrade script 2022-12-14 17:27:11 -05:00
Ed Minnix
72484b9483 Change wording of addJavascriptInterface query description 2022-12-14 16:19:03 -05:00
Nora Dimitrijević
e16b23afc1 Swift: db upgrade/downgrade script 2022-12-14 15:56:05 -05:00
Jami
359e49044f Merge branch 'main' into jcogs33/mad-metrics-query 2022-12-14 15:33:29 -05:00
Nora Dimitrijević
8a3ef31a2c Swift: silence QL-for-QL redundant import warning 2022-12-14 15:22:39 -05:00
Nora Dimitrijević
5faa44389e Swift: Basic acceptance of UnsafeJsEval test
TODO: Fix remaining problem in a separate PR:
- path found to one async `@MainActor` evaluateJavaScript
  call, but not others. Investigate why.
- Remove duplicate paths and those with unnecessary [summary] nodes.
2022-12-14 15:02:15 -05:00
Nora Dimitrijević
95d4c304da Swift: Fix .expected tests
Only UnsafeJsEval remains.
2022-12-14 15:02:15 -05:00
Nora Dimitrijević
6269e6b24d Swift: move getName to Callable (generated)
Now that getStaticTarget returns a Callable.
2022-12-14 14:30:33 -05:00
Nora Dimitrijević
535daf39b7 Swift: move getName to Callable (hand-written)
Now that getStaticTarget returns a Callable.
2022-12-14 14:29:13 -05:00
Nora Dimitrijević
89cd082f0a Swift: {Method,Initializer}CallExpr + SelfRefExpr
Adds a bit of symmetry in the API.

Also, fix a couple of tests that were using the old types.
2022-12-14 14:28:01 -05:00
Nora Dimitrijević
5f03099000 Swift: clarify DotSyntaxBaseIgnoredExpr
- Add docstring with implementation note.
- Avoid `concat` aggregate in toString().

Still, this class should really be cleaned up in the following ways:

- Rename to a sane name at the schema level
- Have subtypes that change the return type of getSubExpr to reflect
  the structure of the desugared closure. E.g. one for methods,
  one for fields.
2022-12-14 14:28:00 -05:00
Nora Dimitrijević
16a119248d Swift: remove toString() = "call to call to ..." 2022-12-14 14:28:00 -05:00
Nora Dimitrijević
91f35a5d53 Swift: isStaticOrClassMethod + isInstanceMethod
Still, we should really be extracting these attributes.
2022-12-14 14:28:00 -05:00
Nora Dimitrijević
6a0b020573 Swift: move methodlookup test to library-tests 2022-12-14 14:28:00 -05:00
Nora Dimitrijević
15d5674d12 Swift: update .expected files based on last commit 2022-12-14 14:28:00 -05:00
Nora Dimitrijević
a620658a66 Swift: fix PrintAst order, double parents, orphan decl refs
The main problem is that a lot of the old DotSyntaxApplyExpr->MethodRefExpr
synth-constructor hacks were not fully generalized to SelfApplyExpr
and OtherConstructorDeclRefExpr.

Also:

- Gave a index-in-parent-based ordering to PrintAst nodes(), to stabilize it more.
- Use a slightly more general SelfApplyExpr->Decl conversion
2022-12-14 14:28:00 -05:00
Nora Dimitrijević
b5bb814112 Swift: fix toString of some invisible DeclRefExprs 2022-12-14 14:28:00 -05:00
Nora Dimitrijević
f6d5e8db5f Swift: update test .expected files 2022-12-14 14:27:59 -05:00
Nora Dimitrijević
799b4c932f Swift: DotSyntaxBaseIgnored calls now have static target
This relies on getStaticTarget() returning a Callable... Not sure how I feel about that, since often we want to say

```
exists(Call c |
  c.getStaticTarget().hasName("...")
)
```

and Callable has a sparse interface. Maybe some AbstractFunctionDecl
methods can be moved to Callable.
2022-12-14 14:24:36 -05:00
Nora Dimitrijević
89bfad0420 Swift: fix MethodLookupExpr.getMethod()
By adding a couple missing cases.
2022-12-14 14:24:36 -05:00
Nora Dimitrijević
c1e746a980 Swift: add InitializerLookupExpr < MethodLookupExpr 2022-12-14 14:24:36 -05:00
Nora Dimitrijević
2af8ec86e6 Swift: init/deinit stringifies with qualifier 2022-12-14 14:24:36 -05:00
Nora Dimitrijević
14b84c6e06 Swift: add MethodDecl.isStatic/0 2022-12-14 14:24:36 -05:00
Nora Dimitrijević
668d79a62d Swift: one more rename 2022-12-14 14:24:36 -05:00
Nora Dimitrijević
2b060b1433 Swift: initial schema change (generated part) 2022-12-14 14:24:35 -05:00
Nora Dimitrijević
0c55561b8e Swift: initial schema change (hand-written part) 2022-12-14 14:22:53 -05:00
Nora Dimitrijević
1ede851cf5 Swift: initial getStaticTarget test 2022-12-14 14:22:53 -05:00
Nora Dimitrijević
99719d0ee1 Swift: initial PrintAst test for Method Lookups 2022-12-14 14:22:53 -05:00
Paolo Tranquilli
793de3196b Revert "Swift: accept test changes"
This reverts commit 26ae8f177b.
2022-12-14 18:34:12 +01:00
Paolo Tranquilli
14fd89d482 Swift: generalize output redirection code 2022-12-14 18:26:48 +01:00
Paolo Tranquilli
45c0c7fe6c Merge branch 'main' into redsun82/swift-open-redirection 2022-12-14 18:26:16 +01:00
turbo
b35a1d4206 Adjust docs referring to experimental queries to include details on new tagging system 2022-12-14 17:16:38 +01:00
turbo
4ec401a3f6 Tag all security queries in supported languages' experimental directories with an experimental tag 2022-12-14 17:15:50 +01:00
erik-krogh
42880f54a6 change ql/to-string-in-logic to a warning query 2022-12-14 14:48:55 +01:00
erik-krogh
1cd1b14e78 remove some more benign results in ql/suggest-instanceof-extension 2022-12-14 14:48:01 +01:00
erik-krogh
35f9f7c71b remove some benign results from ql/suggest-instanceof-extension 2022-12-14 14:47:58 +01:00
erik-krogh
618f48b60b lower the precision of ql/class-predicate-doesnt-use-this to low 2022-12-14 14:31:22 +01:00
erik-krogh
f34f7cc41a exclude test folders from ql/path-problem-query 2022-12-14 14:31:22 +01:00
erik-krogh
3feee23933 fix performance in ql/override-parameter-name and lower the precision to low (it has 1407 results) 2022-12-14 14:31:22 +01:00
erik-krogh
39973df869 include medium precision queries in QL-for-QL 2022-12-14 14:31:22 +01:00
erik-krogh
f6c8e9af1f don't require a member to call a range method before suggesting to use instanceof 2022-12-14 14:31:22 +01:00
Edward Minnix III
40c759e61a Add @name property
Co-authored-by: Sam Browning <106113886+sabrowning1@users.noreply.github.com>
2022-12-13 16:14:28 -05:00
Henry Mercer
a3933fbf4f Bump minor versions of packs we regularly release 2022-12-13 18:59:24 +00:00
Jeroen Ketema
19fb73ce24 C++: Update tests after frontend changes 2022-12-13 19:52:59 +01:00
Henry Mercer
7167f078be Merge branch 'main' into henrymercer/mergeback-3.8 2022-12-13 18:40:53 +00:00
erik-krogh
d95a4a7baf add a second example of how to use module_eval without constructing a code-string 2022-12-13 19:33:45 +01:00
Jami Cogswell
be7b4151af Java: update getNumApis and remove package binding from query body 2022-12-13 12:54:43 -05:00
erik-krogh
ccf520a5cd Merge branch 'main' into unsafeCodeConstruction 2022-12-13 18:31:49 +01:00
Siara
141bc41881 Update docs/codeql/writing-codeql-queries/introduction-to-ql.rst
Co-authored-by: James Fletcher <42464962+jf205@users.noreply.github.com>
2022-12-13 09:22:16 -08:00
Siara
44f91ad723 Update docs/codeql/reusables/codespaces-template-note.rst
Co-authored-by: James Fletcher <42464962+jf205@users.noreply.github.com>
2022-12-13 09:22:07 -08:00
Edward Minnix III
a2c886d367 Grammar and wording changes from docs review
Co-authored-by: Sam Browning <106113886+sabrowning1@users.noreply.github.com>
2022-12-13 11:57:46 -05:00
Jami Cogswell
a33436a39b Java: update hasProvenance 2022-12-13 11:26:23 -05:00
Jami Cogswell
3da2fb933b Java: remove parentheses 2022-12-13 11:08:00 -05:00
Jami Cogswell
028fc29639 Java: group test methods 2022-12-13 11:02:21 -05:00
Tony Torralba
85b3092b16 Add security-severity and fix alert message 2022-12-13 12:01:01 +01:00
Felicity Chapman
cbbce9b98a Update docs/codeql/writing-codeql-queries/introduction-to-ql.rst 2022-12-13 09:56:50 +00:00
Felicity Chapman
6aaaf4267b Update docs/codeql/writing-codeql-queries/introduction-to-ql.rst 2022-12-13 09:37:49 +00:00
Chris Smowton
406a12e797 Remove unused function DeclarationStack.findFirst 2022-12-13 09:34:36 +00:00
Tony Torralba
d72d096c86 Add predicate injection query 2022-12-13 10:27:29 +01:00
SiaraMist
0518eda7ab Remove import tutorial 2022-12-12 17:46:03 -08:00
SiaraMist
dee66354cc Link to template reusable 2022-12-12 17:36:43 -08:00
Siara
094a9f4aa7 Edit reusable 2022-12-12 17:32:02 -08:00
Jami
93d8a03e73 Merge branch 'main' into jcogs33/mad-metrics-query 2022-12-12 20:31:53 -05:00
Siara
028ab325f4 Update docs/codeql/reusables/codespaces-template-note.rst
Co-authored-by: Felicity Chapman <felicitymay@github.com>
2022-12-12 17:28:39 -08:00
Siara
4aa92dfd88 Updates from review comments 2022-12-12 17:13:57 -08:00
Jami Cogswell
a77acd6745 Java: add change note 2022-12-12 17:28:12 -05:00
Jami Cogswell
f0124dae1a Java: replace exists with instanceof 2022-12-12 16:40:19 -05:00
Siara
169a465214 Update docs/codeql/writing-codeql-queries/introduction-to-ql.rst
Co-authored-by: James Fletcher <42464962+jf205@users.noreply.github.com>
2022-12-12 12:54:01 -08:00
Harry Maclean
0340549744 Ruby: Slight rewording 2022-12-13 09:45:31 +13:00
erik-krogh
e0045d2736 filter out string literals from the taint-sink meta query 2022-12-12 21:44:24 +01:00
Jami Cogswell
3526406db0 Java: add tests 2022-12-12 15:10:55 -05:00
Chris Smowton
dd86f7a696 Kotlin: Revert type erasure within $default functions
This imprecise implementation turned out to cause linkage errors, e.g. when type variables in the signatures of member methods were inappropriately erased. For the time being we accept that $default methods despite having erased signatures in keeping with their JVM representation can contain expressions whose types make reference to their
surrounding function or class' type variables, even though they should be out of scope since $default methods are static and don't have type parameters, and need to cope with the inconsistency in QL.
2022-12-12 18:33:22 +00:00
Jami Cogswell
e42d9e4930 Java: switch floats to ints 2022-12-12 11:39:17 -05:00
Jami Cogswell
623068c4b9 Java: add hasProvenance predicate, remove isManuallyGenerated and isBothAutoAndManuallyGenerated 2022-12-12 11:23:46 -05:00
erik-krogh
a1564de126 more ram 2022-12-12 16:35:01 +01:00
erik-krogh
f554e1fef1 more threads 2022-12-12 16:33:07 +01:00
erik-krogh
7526c35c60 speedup the "ATM - Check query suite" CI job 2022-12-12 16:25:25 +01:00
Paolo Tranquilli
250ac686a2 Merge branch 'main' into redsun82/swift-open-redirection 2022-12-12 08:46:23 +01:00
Chris Smowton
2b10e4ba04 Merge pull request #11653 from github/post-release-prep/codeql-cli-2.11.6
Post-release preparation for codeql-cli-2.11.6
2022-12-11 19:24:26 +00:00
github-actions[bot]
343b7b1c8b Post-release preparation for codeql-cli-2.11.6 2022-12-11 18:15:04 +00:00
Chris Smowton
5ae770f339 Merge pull request #11648 from github/release-prep/2.11.6
Release preparation for version 2.11.6
2022-12-11 07:25:21 +00:00
github-actions[bot]
0b2fb4f70a Release preparation for version 2.11.6 2022-12-10 15:49:35 +00:00
Chris Smowton
af08fe8659 Add change note re: Kotlin version limit 2022-12-10 15:32:22 +00:00
Jami Cogswell
270e38d753 Java: add comments and switch getDeclaringType to getCompilationUnit 2022-12-09 19:46:10 -05:00
SiaraMist
401a46d655 Update phrasing and link 2022-12-09 16:45:33 -08:00
Siara
9f75a768ea Update codespaces-template-note.rst 2022-12-09 15:59:27 -08:00
SiaraMist
ae4bc3eb09 Merge branch 'siaramist/codeql-template' of https://github.com/github/codeql into siaramist/codeql-template 2022-12-09 15:45:05 -08:00
SiaraMist
75fc9d0c6a Update reusable name 2022-12-09 15:43:30 -08:00
Jami Cogswell
6854845b75 Java: refactor isManuallyGenerated and isBothAutoAndManuallyGenerated 2022-12-09 18:37:50 -05:00
Siara
d1aacb7260 Add new line to end of reusable 2022-12-09 15:34:31 -08:00
SiaraMist
b4f7239f54 Updates from review 2022-12-09 15:27:04 -08:00
Joe Farebrother
12dc11aa18 Add qldoc 2022-12-09 15:07:49 +00:00
Joe Farebrother
8de5efb28f Add SetDefaultConnectionFactoryMethod class 2022-12-09 13:41:18 +00:00
Joe Farebrother
0dea5daffe Change import for consistency, fix some typos 2022-12-09 13:41:18 +00:00
Joe Farebrother
2be68b2f1d Apply suggestions from code review
Co-authored-by: Tony Torralba <atorralba@users.noreply.github.com>
2022-12-09 13:41:18 +00:00
Joe Farebrother
a14ebb7c03 Fixes 2022-12-09 13:41:18 +00:00
Joe Farebrother
fae4043008 Add change note 2022-12-09 13:41:18 +00:00
Joe Farebrother
603c1c1693 Add the domain used to the alert message 2022-12-09 13:41:18 +00:00
Joe Farebrother
ceb253e6d1 Add qhelp 2022-12-09 13:41:18 +00:00
Joe Farebrother
749ecab6b1 Add security severity 2022-12-09 13:41:18 +00:00
Joe Farebrother
0d6a376a36 Add test cases for TrustManager case 2022-12-09 13:41:18 +00:00
Joe Farebrother
c8aca06190 Implement pinning through a TrustManager
+ Fix that the query was accidentally placed in experimental
2022-12-09 13:41:18 +00:00
Joe Farebrother
4afecf575e Generate more stubs for okhttp and fix tests.
Some generated stubs needed to be manually corrected.
2022-12-09 13:41:17 +00:00
Joe Farebrother
bb402c497b Fix typo in dir name 2022-12-09 13:41:17 +00:00
Joe Farebrother
53c4ada883 Add okhttp tests 2022-12-09 13:41:17 +00:00
Joe Farebrother
c32dc1e674 Implement okhttp support 2022-12-09 13:41:17 +00:00
Joe Farebrother
da7032d3d6 Add qldoc 2022-12-09 13:41:17 +00:00
Joe Farebrother
ea3db5d429 Add test cases 2022-12-09 13:41:17 +00:00
Joe Farebrother
c3da3a9aef Add a bit of additional context to the alert message; fix issue with finding the config file 2022-12-09 13:41:17 +00:00
Joe Farebrother
17348fbd32 Add android certificate pinning query 2022-12-09 13:41:17 +00:00
Paolo Tranquilli
a93e361aca Merge branch 'main' into redsun82/swift-open-redirection 2022-12-09 12:19:38 +01:00
Paolo Tranquilli
7162692656 Swift: exit directly on actions not requiring extraction 2022-12-09 10:00:01 +01:00
Paolo Tranquilli
4a41bb4061 Merge branch 'main' into redsun82/swift-open-redirection 2022-12-09 09:59:21 +01:00
Jami Cogswell
0b2f2a3f88 Java: remove predicates from NegativeSummarizedCallable 2022-12-08 23:46:55 -05:00
Jami Cogswell
2c3adb769b Java: remove MadModeledCallable class and update predicate names 2022-12-08 23:32:07 -05:00
Jami Cogswell
974c000b65 Java: add bindingset for package 2022-12-08 23:17:53 -05:00
Jami Cogswell
a32ed21480 Java: clean up comments and predicates 2022-12-08 23:09:09 -05:00
Jami Cogswell
ca00e0ab9e Java: adjust none and all calculations 2022-12-08 22:14:28 -05:00
Jami Cogswell
6248efd394 Java: adjust column names and metric formulas 2022-12-08 21:13:52 -05:00
Jami Cogswell
9e0027cf5b Java: remove negative models 2022-12-08 20:58:37 -05:00
Jami Cogswell
d558f93972 Java: update DataFlowTargetApi for funcexpr and paramless constructor exclusions 2022-12-08 20:51:40 -05:00
Siara
c1efb7f3f4 Update introduction-to-ql.rst 2022-12-08 16:12:59 -08:00
Siara
986c15cd08 Update introduction-to-ql.rst 2022-12-08 15:58:07 -08:00
Siara
dded684ad6 Update docs/codeql/writing-codeql-queries/introduction-to-ql.rst 2022-12-08 14:43:14 -08:00
Siara
7b6aa09646 Update introduction-to-ql.rst 2022-12-08 14:42:38 -08:00
Siara
b89dd3d8ac Merge branch 'codeql-cli-2.11.5' into siaramist/codeql-template 2022-12-08 14:07:58 -08:00
Siara
2ac736cd74 Update introduction-to-ql.rst 2022-12-08 14:07:39 -08:00
Paolo Tranquilli
26ae8f177b Swift: accept test changes
Downgrading the emit object action to a type check one has some
unexpected side effects, that seem however acceptable:
* experimental false static assertions do not make compilation fail in
  type check mode
* the implicit module loading of `SwiftOnoneSupport` is not happening.
  That module contains some "pre-specializations", it does not seem
  really relevant for analysis
2022-12-08 17:13:00 +01:00
Paolo Tranquilli
d35c5e90ee Swift: remove fishhook 2022-12-08 16:10:44 +01:00
Paolo Tranquilli
bf1b32f210 Swift: rework file redirection
The hash map mechanism that was already in use for reading swiftmodule
files on macOS is now in use also on Linux. The output replacing
mechanism has been also reworked so that:
* frontend module emission modes have the remapping done directly in
  the internal frontend options instead of painstakingly modifying input
  flags (this requires a patch on the swift headers though)
* object emission mode is silenced to be just a type checking pass,
  thus producing no output files
* all other passes but some debugging and version related ones become
  noops

The open file read redirection uses a global weak pointer instance to
maximize robustness in the face of possibly multi-threaded calls to open
happening while `main` is exiting. Possibly overkill, but better safe
than sorry.
2022-12-08 16:10:44 +01:00
Paolo Tranquilli
944adfe727 Swift: allow modifying frontend outputs 2022-12-08 16:10:25 +01:00
Paolo Tranquilli
219ed64b74 Swift: reorganize bazel third party dependencies 2022-12-08 16:10:25 +01:00
erik-krogh
1a6e16f292 Merge branch 'main' into kernelLoad 2022-12-08 15:41:48 +01:00
erik-krogh
f09e10f61f delete redundant cast 2022-12-08 15:34:26 +01:00
Geoffrey White
24ce1c27bc Swift: Autoformat. 2022-12-08 13:09:37 +00:00
Geoffrey White
07ea006cee Swift: Add support for CSV modelled sinks as well. 2022-12-08 11:36:55 +00:00
Geoffrey White
dba344451f Swift: Add UncontrolledFormatStringExtensions.qll. 2022-12-08 11:32:50 +00:00
Jami Cogswell
e9e5f92603 Java: update notModeled for negative numbers 2022-12-07 21:46:52 -05:00
Jami Cogswell
aa7e6d7811 Java: add negative numbers 2022-12-07 17:17:35 -05:00
erik-krogh
9ef4f12261 add change-note 2022-12-07 14:12:43 +01:00
erik-krogh
8ab31bbe1c have getMethodName return the method being called for super-calls 2022-12-07 14:09:36 +01:00
erik-krogh
ee8e0188a6 remove redundant call, the charpred ensures it always holds 2022-12-07 13:23:18 +01:00
erik-krogh
360a99f026 delete getKernelMethod and don't special-case the methodName on super-calls in the Kernel model 2022-12-07 13:14:48 +01:00
erik-krogh
52c0afa03f change getMethodName to getKernelMethod in other files 2022-12-07 10:27:35 +01:00
Jami Cogswell
b82f9b1911 Java: add draft of generated vs manual MaD metrics query 2022-12-06 22:15:19 -05:00
erik-krogh
8f0c0f3c17 add support for super calls to Kernel 2022-12-06 14:25:51 +01:00
erik-krogh
0e9cd1e4b5 factor out methodName to a field in KernelMethodCall 2022-12-06 14:23:46 +01:00
erik-krogh
e24f041661 drive-by: use instanceof KernelMethodCall such that override getAnArgument cannot be mistaken for a method in CallNode 2022-12-06 14:21:48 +01:00
erik-krogh
5849b2c98a drive-by: simplify the imports in PathInjection.ql 2022-12-06 14:09:39 +01:00
erik-krogh
66946ebf6a add Kernel methods as sinks to path-injection 2022-12-06 14:09:15 +01:00
SiaraMist
a1b6bfb270 Initial updates for CodeQL template 2022-12-02 13:07:25 -08:00
Geoffrey White
cf3345ee8f Swift: Revert security-severity on CWE-321, for now. 2022-12-02 12:01:43 +00:00
Geoffrey White
85a0a42da9 Swift: try again to satisfy ql-for-ql. 2022-12-02 10:15:11 +00:00
Geoffrey White
f7ebd1312e Swift: Corrections. 2022-12-01 20:13:56 +00:00
Geoffrey White
157a7829ca Swift: correct the example. 2022-12-01 18:35:10 +00:00
Geoffrey White
ad05cc3cb1 Swift: Separate out a FormatString library as well. 2022-12-01 18:09:46 +00:00
Geoffrey White
43596869e7 Swift: Move query logic to a .qll. 2022-12-01 18:09:45 +00:00
Geoffrey White
87fa159384 Swift: Add security-severity, and correct one for another query that apparently wasn't right. 2022-12-01 18:09:39 +00:00
Geoffrey White
58e9a0436e Swift: Add metadata. 2022-12-01 18:09:33 +00:00
Geoffrey White
2b61f26a64 Swift: Add doc. 2022-12-01 16:32:34 +00:00
Geoffrey White
32c4728f83 Swift: Add tests. 2022-12-01 16:32:33 +00:00
Geoffrey White
a2210959b5 Swift: Uncontrolled format string query (initial version). 2022-12-01 16:32:33 +00:00
Ed Minnix
04829fc38e Java: SQLInjection example for addJavaScriptInterface query 2022-11-30 13:32:28 -05:00
Ed Minnix
d35321f40e Java: change WebView addJavascriptInterface query precision to medium 2022-11-30 11:35:14 -05:00
erik-krogh
fd7442868f fix copy-pate error in UnsafeCodeConstructionQuery.qll 2022-11-28 13:45:24 +01:00
erik-krogh
f75b853ae4 add change-note 2022-11-25 11:08:14 +01:00
erik-krogh
53f24a5281 fix QL-for-QL warning 2022-11-25 10:32:06 +01:00
erik-krogh
0817238177 drive-by: same change in unsafe-shell-command-construction 2022-11-25 10:32:06 +01:00
erik-krogh
378cc1aed2 add support for string-like-literals 2022-11-25 10:32:06 +01:00
erik-krogh
80c92dc3e6 add support for array pushes 2022-11-25 10:32:05 +01:00
erik-krogh
3461404bbb add basic support for arrays 2022-11-25 10:31:35 +01:00
erik-krogh
0f2a48f461 fix QL-for-QL warnings 2022-11-25 10:26:24 +01:00
erik-krogh
2033dd2dcc remove parameters named "code" as source 2022-11-25 10:25:31 +01:00
erik-krogh
e7c6571f52 remove the "send(..)" and similar from unsafe-code-construction 2022-11-25 10:25:31 +01:00
erik-krogh
f1668801d3 add a rb/unsafe-code-construction query
rebase
2022-11-25 10:25:30 +01:00
Harry Maclean
f49507e59a Ruby: Add note about WithElement usage 2022-11-25 16:55:37 +13:00
Harry Maclean
df398fb9a0 Ruby: Add more flow summary tests 2022-11-25 16:55:37 +13:00
Harry Maclean
fe13ac188f Ruby: US spelling 2022-11-25 16:55:37 +13:00
Harry Maclean
0b065001a8 Ruby: Add tests for flow summary behaviour
These test cases are a companion to the flow summary docs, and ensure
that the documentated behaviour matches reality.
2022-11-25 16:55:37 +13:00
Harry Maclean
c0501c189e Ruby: Document ?/any behaviour in output paths 2022-11-25 16:55:37 +13:00
Harry Maclean
5b07c3a746 Ruby: Elaborate WithoutElement docs 2022-11-25 16:55:37 +13:00
Harry Maclean
5e3a817064 Ruby: With[out]Element only valid in input 2022-11-25 16:55:37 +13:00
Harry Maclean
0c2dd1a5a6 Ruby: Flesh out hash-splat docs 2022-11-25 16:55:37 +13:00
Harry Maclean
43f2713925 Ruby: Update test fixture 2022-11-25 16:55:37 +13:00
Harry Maclean
78f604aef1 Ruby: Document Field access path token 2022-11-25 16:55:37 +13:00
Harry Maclean
6f852aad0b Ruby: Document flow summary syntax 2022-11-25 16:55:36 +13:00
Harry Maclean
0a4a8516eb Ruby: simplify Hash#transform_keys! flow summary 2022-11-25 16:55:36 +13:00
erik-krogh
5f6cb1684b move the code-injection tests into a subfolder 2022-11-24 17:23:25 +01:00
yoff
505f454878 Apply suggestions from code review
Co-authored-by: Rasmus Wriedt Larsen <rasmuswl@github.com>
2022-11-16 22:20:19 +01:00
Ed Minnix
38d47d63ec Java: Add change note for addJavascriptInterface query 2022-11-15 23:40:03 -05:00
Ed Minnix
eb8ef72e47 Java: addJavascriptInterface query test case 2022-11-15 23:28:18 -05:00
Ed Minnix
3b96fefc71 Java: Add Android stubs to options file for CWE-079 test cases 2022-11-15 23:26:49 -05:00
Rasmus Lerchedahl Petersen
4f159371f9 Python: add change notes 2022-11-14 17:01:45 +01:00
Rasmus Lerchedahl Petersen
9c7fee225c Python: remove redundant override 2022-11-14 16:45:34 +01:00
Rasmus Lerchedahl Petersen
3ee756694f Python: add missing qldoc
also add to ordinary `except`
2022-11-14 16:45:22 +01:00
Ed Minnix
e09f0861f3 Java: documentation for WebView#addJavascriptInterface query 2022-11-12 09:40:49 -05:00
Ed Minnix
e1ff04cd95 Java: Query for android.webkit.WebView#addJavascriptInterface 2022-11-12 09:40:49 -05:00
Ed Minnix
30cd447f69 Java: Add class to represent android.webkit.WebView#addJavascriptInterface 2022-11-12 09:40:49 -05:00
Rasmus Lerchedahl Petersen
71335a1a97 python: update users of try 2022-11-10 22:20:28 +01:00
Rasmus Lerchedahl Petersen
7d05ba38d5 python: convenience methods for handler types 2022-11-10 22:20:28 +01:00
Rasmus Lerchedahl Petersen
e67515fae7 python: dataflow tests names in exception handlers 2022-11-10 22:20:28 +01:00
Rasmus Lerchedahl Petersen
a7e394b2be python: SSA for names in except* 2022-11-10 22:20:28 +01:00
Rasmus Lerchedahl Petersen
30b58e7921 python: control flow node ExceptGroupStmt
- wrap `getType` and `getName`, considering dominance
- do not implement all the handles predicates
2022-11-10 22:20:27 +01:00
Rasmus Lerchedahl Petersen
9f9a962c03 python: wrap autogenerated ExceptGroupStmt_
also widen type of `Try::getHandler` to `Stmt`.
`ExceptStmt` is now too narrow,
as a handler can also be of type `ExceptGroupStmt`.
2022-11-10 22:20:27 +01:00
Rasmus Lerchedahl Petersen
24d22ccb6e python: regenerated AST 2022-11-10 22:20:27 +01:00
Rasmus Lerchedahl Petersen
9f89325ca7 python: dummy stats for ExceptGroupStmt 2022-11-10 22:20:27 +01:00
Rasmus Lerchedahl Petersen
1fd76f02fd python: db uprade and downgrade scripts 2022-11-10 22:20:27 +01:00
Rasmus Lerchedahl Petersen
856e48c414 python: new dbscheme 2022-11-10 22:20:27 +01:00
erik-krogh
c5fece7a87 QL: improve the dead-code query 2022-11-08 20:20:34 +01:00
Rasmus Lerchedahl Petersen
0a7cfad048 python: inline query tests for command injection
note how the test file is partially annotated
and those annotations can now be expressed

In this particular test file, absolute line numbers
might have been better than relative ones.
We might remove line numbers altogether,
but should check more querries to see how it looks.
2022-11-02 16:21:59 +01:00
Rasmus Lerchedahl Petersen
f486c44b00 python: library for inline query tests
similar to the consistency queires used in js
but based on the inline expectations framework
2022-11-02 16:18:36 +01:00
1964 changed files with 154435 additions and 48931 deletions

View File

@@ -23,20 +23,19 @@ runs:
run: |
MERGE_BASE=$(git cat-file commit $GITHUB_SHA | grep '^parent ' | head -1 | cut -f 2 -d " ")
echo "merge_base=$MERGE_BASE" >> $GITHUB_ENV
- name: Restore read-only cache (PR)
- name: Restore cache (PR)
if: ${{ github.event_name == 'pull_request' }}
uses: erik-krogh/actions-cache@a88d0603fe5fb5606db9f002dfcadeb32b5f84c6
uses: actions/cache/restore@v3
with:
path: '**/.cache'
read-only: true
key: codeql-compile-${{ inputs.key }}-pr-${{ github.sha }}
restore-keys: |
codeql-compile-${{ inputs.key }}-${{ github.base_ref }}-${{ env.merge_base }}
codeql-compile-${{ inputs.key }}-${{ github.base_ref }}-
codeql-compile-${{ inputs.key }}-main-
- name: Fill cache (push)
- name: Fill cache (only branch push)
if: ${{ github.event_name != 'pull_request' }}
uses: erik-krogh/actions-cache@a88d0603fe5fb5606db9f002dfcadeb32b5f84c6
uses: actions/cache@v3
with:
path: '**/.cache'
key: codeql-compile-${{ inputs.key }}-${{ github.ref_name }}-${{ github.sha }} # just fill on main

View File

@@ -19,4 +19,6 @@ runs:
gh extension install github/gh-codeql
gh codeql set-channel "$CHANNEL"
gh codeql version
printf "CODEQL_FETCHED_CODEQL_PATH=" >> "${GITHUB_ENV}"
gh codeql version --format=json | jq -r .unpackedLocation >> "${GITHUB_ENV}"
gh codeql version --format=json | jq -r .unpackedLocation >> "${GITHUB_PATH}"

32
.github/actions/os-version/action.yml vendored Normal file
View File

@@ -0,0 +1,32 @@
name: OS Version
description: Get OS version.
outputs:
version:
description: "OS version"
value: ${{ steps.version.outputs.version }}
runs:
using: composite
steps:
- if: runner.os == 'Linux'
shell: bash
run: |
. /etc/os-release
echo "VERSION=${NAME} ${VERSION}" >> $GITHUB_ENV
- if: runner.os == 'Windows'
shell: powershell
run: |
$objects = systeminfo.exe /FO CSV | ConvertFrom-Csv
"VERSION=$($objects.'OS Name') $($objects.'OS Version')" >> $env:GITHUB_ENV
- if: runner.os == 'macOS'
shell: bash
run: |
echo "VERSION=$(sw_vers -productName) $(sw_vers -productVersion)" >> $GITHUB_ENV
- name: Emit OS version
id: version
shell: bash
run: |
echo "$VERSION"
echo "version=${VERSION}" >> $GITHUB_OUTPUT

View File

@@ -13,7 +13,7 @@ on:
jobs:
atm-check-query-suite:
runs-on: ubuntu-latest
runs-on: ubuntu-latest-xl
steps:
- uses: actions/checkout@v3
@@ -23,6 +23,12 @@ jobs:
with:
channel: release
- name: Cache compilation cache
id: query-cache
uses: ./.github/actions/cache-query-compilation
with:
key: atm-suite
- name: Install ATM model
run: |
set -exu
@@ -50,10 +56,13 @@ jobs:
echo "SARIF_PATH=${SARIF_PATH}" >> "${GITHUB_ENV}"
codeql database analyze \
--threads=0 \
--ram 50000 \
--format sarif-latest \
--output "${SARIF_PATH}" \
--sarif-group-rules-by-pack \
-vv \
--compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" \
-- \
"${DB_PATH}" \
"${QUERY_PACK}/${QUERY_SUITE}"

View File

@@ -26,3 +26,9 @@ jobs:
run: |
gh api 'repos/${{github.repository}}/pulls/${{github.event.number}}/files' --paginate --jq 'any(.[].filename ; test("/change-notes/.*[.]md$"))' |
grep true -c
- name: Fail if the change note filename doesn't match the expected format. The file name must be of the form 'YYYY-MM-DD.md' or 'YYYY-MM-DD-{title}.md', where '{title}' is arbitrary text.
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh api 'repos/${{github.repository}}/pulls/${{github.event.number}}/files' --paginate --jq '[.[].filename | select(test("/change-notes/.*[.]md$"))] | all(test("/change-notes/[0-9]{4}-[0-9]{2}-[0-9]{2}.*[.]md$"))' |
grep true -c

View File

@@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v6
- uses: actions/stale@v7
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-issue-message: 'This issue is stale because it has been open 14 days with no activity. Comment or remove the `Stale` label in order to avoid having this issue closed in 7 days.'

View File

@@ -11,7 +11,7 @@ on:
branches:
- main
paths:
- "java/ql/src/utils/model-generator/**/*.*"
- "java/ql/src/utils/modelgenerator/**/*.*"
- ".github/workflows/mad_modelDiff.yml"
permissions:
@@ -40,12 +40,12 @@ jobs:
- name: Download database
env:
SLUG: ${{ matrix.slug }}
GH_TOKEN: ${{ github.token }}
run: |
set -x
mkdir lib-dbs
SHORTNAME=${SLUG//[^a-zA-Z0-9_]/}
projectId=`curl -s https://lgtm.com/api/v1.0/projects/g/${SLUG} | jq .id`
curl -L "https://lgtm.com/api/v1.0/snapshots/$projectId/java" -o "$SHORTNAME.zip"
gh api -H "Accept: application/zip" "/repos/${SLUG}/code-scanning/codeql/databases/java" > "$SHORTNAME.zip"
unzip -q -d "${SHORTNAME}-db" "${SHORTNAME}.zip"
mkdir "lib-dbs/$SHORTNAME/"
mv "${SHORTNAME}-db/"$(ls -1 "${SHORTNAME}"-db)/* "lib-dbs/${SHORTNAME}/"
@@ -61,7 +61,7 @@ jobs:
DATABASE=$2
cd codeql-$QL_VARIANT
SHORTNAME=`basename $DATABASE`
python java/ql/src/utils/model-generator/GenerateFlowModel.py --with-summaries --with-sinks $DATABASE ${SHORTNAME}.temp.model.yml
python java/ql/src/utils/modelgenerator/GenerateFlowModel.py --with-summaries --with-sinks $DATABASE ${SHORTNAME}.temp.model.yml
mv java/ql/lib/ext/generated/${SHORTNAME}.temp.model.yml $MODELS/${SHORTNAME}Generated_${QL_VARIANT}.model.yml
cd ..
}
@@ -100,4 +100,6 @@ jobs:
with:
name: diffs
path: tmp-models/*.html
# An html file is only produced if the generated models differ.
if-no-files-found: ignore
retention-days: 20

View File

@@ -50,7 +50,7 @@ jobs:
SLUG: ${{ matrix.slug }}
run: |
SHORTNAME=${SLUG//[^a-zA-Z0-9_]/}
java/ql/src/utils/model-generator/RegenerateModels.py "${SLUG}" dbs/${SHORTNAME}
java/ql/src/utils/modelgenerator/RegenerateModels.py "${SLUG}" dbs/${SHORTNAME}
- name: Stage changes
run: |
find java -name "*.model.yml" -print0 | xargs -0 git add

View File

@@ -27,7 +27,7 @@ jobs:
uses: ./.github/actions/find-latest-bundle
- name: Find codeql
id: find-codeql
uses: github/codeql-action/init@77a8d2d10c0b403a8b4aadbd223dc489ecd22683
uses: github/codeql-action/init@45955cb1830b640e2c1603ad72ad542a49d47b96
with:
languages: javascript # does not matter
tools: ${{ steps.find-latest-bundle.outputs.url }}
@@ -38,12 +38,14 @@ jobs:
shell: bash
env:
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
- uses: ./.github/actions/os-version
id: os_version
- name: Cache entire pack
id: cache-pack
uses: actions/cache@v3
with:
path: ${{ runner.temp }}/pack
key: ${{ runner.os }}-pack-${{ hashFiles('ql/**/Cargo.lock') }}-${{ hashFiles('ql/**/*.rs') }}-${{ hashFiles('ql/**/*.ql*') }}-${{ hashFiles('ql/**/qlpack.yml') }}-${{ hashFiles('ql/ql/src/ql.dbscheme*') }}-${{ steps.get-codeql-version.outputs.version }}--${{ hashFiles('.github/workflows/ql-for-ql-build.yml') }}
key: ${{ runner.os }}-${{ steps.os_version.outputs.version }}-pack-${{ hashFiles('ql/**/Cargo.lock') }}-${{ hashFiles('ql/**/*.rs') }}-${{ hashFiles('ql/**/*.ql*') }}-${{ hashFiles('ql/**/qlpack.yml') }}-${{ hashFiles('ql/ql/src/ql.dbscheme*') }}-${{ steps.get-codeql-version.outputs.version }}--${{ hashFiles('.github/workflows/ql-for-ql-build.yml') }}
- name: Cache queries
if: steps.cache-pack.outputs.cache-hit != 'true'
id: cache-queries
@@ -77,7 +79,7 @@ jobs:
ql/target/release/ql-autobuilder.exe
ql/target/release/ql-extractor
ql/target/release/ql-extractor.exe
key: ${{ runner.os }}-extractor-${{ hashFiles('ql/**/Cargo.lock') }}-${{ hashFiles('ql/**/*.rs') }}
key: ${{ runner.os }}-${{ steps.os_version.outputs.version }}-extractor-${{ hashFiles('ql/**/Cargo.lock') }}-${{ hashFiles('ql/**/*.rs') }}
- name: Cache cargo
if: steps.cache-extractor.outputs.cache-hit != 'true' && steps.cache-pack.outputs.cache-hit != 'true'
uses: actions/cache@v3
@@ -86,7 +88,7 @@ jobs:
~/.cargo/registry
~/.cargo/git
ql/target
key: ${{ runner.os }}-rust-cargo-${{ hashFiles('ql/**/Cargo.lock') }}
key: ${{ runner.os }}-${{ steps.os_version.outputs.version }}-rust-cargo-${{ hashFiles('ql/**/Cargo.lock') }}
- name: Check formatting
if: steps.cache-extractor.outputs.cache-hit != 'true' && steps.cache-pack.outputs.cache-hit != 'true'
run: cd ql; cargo fmt --all -- --check
@@ -137,20 +139,20 @@ jobs:
env:
CONF: ./ql-for-ql-config.yml
- name: Initialize CodeQL
uses: github/codeql-action/init@77a8d2d10c0b403a8b4aadbd223dc489ecd22683
uses: github/codeql-action/init@45955cb1830b640e2c1603ad72ad542a49d47b96
with:
languages: ql
db-location: ${{ runner.temp }}/db
config-file: ./ql-for-ql-config.yml
tools: ${{ steps.find-latest-bundle.outputs.url }}
- name: Move pack cache
- name: Move pack queries
run: |
cp -r ${PACK}/.cache ql/ql/src/.cache
cp -r ${PACK}/queries ql/ql/src
env:
PACK: ${{ runner.temp }}/pack
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@77a8d2d10c0b403a8b4aadbd223dc489ecd22683
uses: github/codeql-action/analyze@45955cb1830b640e2c1603ad72ad542a49d47b96
with:
category: "ql-for-ql"
- name: Copy sarif file to CWD
@@ -172,4 +174,4 @@ jobs:
with:
name: ql-for-ql-langs
path: split-sarif
retention-days: 1
retention-days: 1

View File

@@ -25,16 +25,18 @@ jobs:
- name: Find codeql
id: find-codeql
uses: github/codeql-action/init@77a8d2d10c0b403a8b4aadbd223dc489ecd22683
uses: github/codeql-action/init@45955cb1830b640e2c1603ad72ad542a49d47b96
with:
languages: javascript # does not matter
- uses: ./.github/actions/os-version
id: os_version
- uses: actions/cache@v3
with:
path: |
~/.cargo/registry
~/.cargo/git
ql/target
key: ${{ runner.os }}-qltest-cargo-${{ hashFiles('ql/**/Cargo.lock') }}
key: ${{ runner.os }}-${{ steps.os_version.outputs.version }}-qltest-cargo-${{ hashFiles('ql/**/Cargo.lock') }}
- name: Build Extractor
run: cd ql; env "PATH=$PATH:`dirname ${CODEQL}`" ./scripts/create-extractor-pack.sh
env:

View File

@@ -22,28 +22,84 @@ jobs:
- uses: actions/checkout@v3
- name: Find codeql
id: find-codeql
uses: github/codeql-action/init@77a8d2d10c0b403a8b4aadbd223dc489ecd22683
uses: github/codeql-action/init@45955cb1830b640e2c1603ad72ad542a49d47b96
with:
languages: javascript # does not matter
- uses: ./.github/actions/os-version
id: os_version
- uses: actions/cache@v3
with:
path: |
~/.cargo/registry
~/.cargo/git
ql/target
key: ${{ runner.os }}-qltest-cargo-${{ hashFiles('ql/**/Cargo.lock') }}
key: ${{ runner.os }}-${{ steps.os_version.outputs.version }}-qltest-cargo-${{ hashFiles('ql/rust-toolchain.toml', 'ql/**/Cargo.lock') }}
- name: Build extractor
run: |
cd ql;
codeqlpath=$(dirname ${{ steps.find-codeql.outputs.codeql-path }});
env "PATH=$PATH:$codeqlpath" ./scripts/create-extractor-pack.sh
- name: Cache compilation cache
id: query-cache
uses: ./.github/actions/cache-query-compilation
with:
key: ql-for-ql-tests
- 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 }}/ql/extractor-pack" --consistency-queries ql/ql/consistency-queries ql/ql/test
"${CODEQL}" test run --check-databases --check-unused-labels --check-repeated-labels --check-redefined-labels --check-use-before-definition --search-path "${{ github.workspace }}/ql/extractor-pack" --consistency-queries ql/ql/consistency-queries --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}" ql/ql/test
env:
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
- name: Check QL formatting
other-os:
strategy:
matrix:
os: [macos-latest, windows-latest]
needs: [qltest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v3
- name: Install GNU tar
if: runner.os == 'macOS'
run: |
find ql/ql/src "(" -name "*.ql" -or -name "*.qll" ")" -print0 | xargs -0 "${CODEQL}" query format --check-only
brew install gnu-tar
echo "/usr/local/opt/gnu-tar/libexec/gnubin" >> $GITHUB_PATH
- name: Find codeql
id: find-codeql
uses: github/codeql-action/init@77a8d2d10c0b403a8b4aadbd223dc489ecd22683
with:
languages: javascript # does not matter
- uses: ./.github/actions/os-version
id: os_version
- uses: actions/cache@v3
with:
path: |
~/.cargo/registry
~/.cargo/git
ql/target
key: ${{ runner.os }}-${{ steps.os_version.outputs.version }}-qltest-cargo-${{ hashFiles('ql/rust-toolchain.toml', 'ql/**/Cargo.lock') }}
- name: Build extractor
if: runner.os != 'Windows'
run: |
cd ql;
codeqlpath=$(dirname ${{ steps.find-codeql.outputs.codeql-path }});
env "PATH=$PATH:$codeqlpath" ./scripts/create-extractor-pack.sh
- name: Build extractor (Windows)
if: runner.os == 'Windows'
shell: pwsh
run: |
cd ql;
$Env:PATH += ";$(dirname ${{ steps.find-codeql.outputs.codeql-path }})"
pwsh ./scripts/create-extractor-pack.ps1
- name: Run a single QL tests - Unix
if: runner.os != 'Windows'
run: |
"${CODEQL}" test run --check-databases --search-path "${{ github.workspace }}/ql/extractor-pack" ql/ql/test/queries/style/DeadCode/DeadCode.qlref
env:
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
- name: Run a single QL tests - Windows
if: runner.os == 'Windows'
shell: pwsh
run: |
$Env:PATH += ";$(dirname ${{ steps.find-codeql.outputs.codeql-path }})"
codeql test run --check-databases --search-path "${{ github.workspace }}/ql/extractor-pack" ql/ql/test/queries/style/DeadCode/DeadCode.qlref

View File

@@ -48,6 +48,8 @@ jobs:
run: |
brew install gnu-tar
echo "/usr/local/opt/gnu-tar/libexec/gnubin" >> $GITHUB_PATH
- uses: ./.github/actions/os-version
id: os_version
- name: Cache entire extractor
uses: actions/cache@v3
id: cache-extractor
@@ -58,7 +60,7 @@ jobs:
ruby/target/release/ruby-extractor
ruby/target/release/ruby-extractor.exe
ruby/ql/lib/codeql/ruby/ast/internal/TreeSitter.qll
key: ${{ runner.os }}-ruby-extractor-${{ hashFiles('ruby/rust-toolchain.toml', 'ruby/**/Cargo.lock') }}--${{ hashFiles('ruby/**/*.rs') }}
key: ${{ runner.os }}-${{ steps.os_version.outputs.version }}-ruby-extractor-${{ hashFiles('ruby/rust-toolchain.toml', 'ruby/**/Cargo.lock') }}--${{ hashFiles('ruby/**/*.rs') }}
- uses: actions/cache@v3
if: steps.cache-extractor.outputs.cache-hit != 'true'
with:
@@ -66,7 +68,7 @@ jobs:
~/.cargo/registry
~/.cargo/git
ruby/target
key: ${{ runner.os }}-ruby-rust-cargo-${{ hashFiles('ruby/rust-toolchain.toml', 'ruby/**/Cargo.lock') }}
key: ${{ runner.os }}-${{ steps.os_version.outputs.version }}-ruby-rust-cargo-${{ hashFiles('ruby/rust-toolchain.toml', 'ruby/**/Cargo.lock') }}
- name: Check formatting
if: steps.cache-extractor.outputs.cache-hit != 'true'
run: cargo fmt --all -- --check
@@ -115,9 +117,10 @@ jobs:
- name: Build Query Pack
run: |
rm -rf target/packs
codeql pack create ../shared/ssa --output target/packs
codeql pack create ../misc/suite-helpers --output target/packs
codeql pack create ../shared/regex --output target/packs
codeql pack create ../shared/ssa --output target/packs
codeql pack create ../shared/tutorial --output target/packs
codeql pack create ql/lib --output target/packs
codeql pack create -j0 ql/src --output target/packs --compilation-cache "${{ steps.query-cache.outputs.cache-dir }}"
PACK_FOLDER=$(readlink -f target/packs/codeql/ruby-queries/*)
@@ -202,11 +205,6 @@ jobs:
- name: Fetch CodeQL
uses: ./.github/actions/fetch-codeql
- uses: actions/checkout@v3
with:
repository: Shopify/example-ruby-app
ref: 67a0decc5eb550f3a9228eda53925c3afd40dfe9
- name: Download Ruby bundle
uses: actions/download-artifact@v3
with:
@@ -215,26 +213,15 @@ jobs:
- name: Unzip Ruby bundle
shell: bash
run: unzip -q -d "${{ runner.temp }}/ruby-bundle" "${{ runner.temp }}/codeql-ruby-bundle.zip"
- name: Prepare test files
shell: bash
run: |
echo "import codeql.ruby.AST select count(File f)" > "test.ql"
echo "| 4 |" > "test.expected"
echo 'name: sample-tests
version: 0.0.0
dependencies:
codeql/ruby-all: "*"
extractor: ruby
tests: .
' > qlpack.yml
- name: Run QL test
shell: bash
run: |
codeql test run --search-path "${{ runner.temp }}/ruby-bundle" --additional-packs "${{ runner.temp }}/ruby-bundle" .
codeql test run --search-path "${{ runner.temp }}/ruby-bundle" --additional-packs "${{ runner.temp }}/ruby-bundle" ruby/ql/test/library-tests/ast/constants/
- name: Create database
shell: bash
run: |
codeql database create --search-path "${{ runner.temp }}/ruby-bundle" --language ruby --source-root . ../database
codeql database create --search-path "${{ runner.temp }}/ruby-bundle" --language ruby --source-root ruby/ql/test/library-tests/ast/constants/ ../database
- name: Analyze database
shell: bash
run: |

View File

@@ -25,6 +25,7 @@ If you have an idea for a query that you would like to share with other CodeQL u
Each language-specific directory contains further subdirectories that group queries based on their `@tags` or purpose.
- Experimental queries and libraries are stored in the `experimental` subdirectory within each language-specific directory in the [CodeQL repository](https://github.com/github/codeql). For example, experimental Java queries and libraries are stored in `java/ql/src/experimental` and any corresponding tests in `java/ql/test/experimental`.
- Experimental queries need to include `experimental` in their `@tags`
- The structure of an `experimental` subdirectory mirrors the structure of its parent directory.
- Select or create an appropriate directory in `experimental` based on the existing directory structure of `experimental` or its parent directory.

View File

@@ -29,6 +29,7 @@
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/DataFlowImplForContentDataFlow.qll",
"go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl.qll",
"go/ql/lib/semmle/go/dataflow/internal/DataFlowImpl2.qll",
"go/ql/lib/semmle/go/dataflow/internal/DataFlowImplForStringsNewReplacer.qll",
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl.qll",
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl2.qll",
"python/ql/lib/semmle/python/dataflow/new/internal/DataFlowImpl3.qll",
@@ -402,16 +403,6 @@
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/ControlFlowReachability.qll",
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/ControlFlowReachability.qll"
],
"Inline Test Expectations": [
"cpp/ql/test/TestUtilities/InlineExpectationsTest.qll",
"csharp/ql/test/TestUtilities/InlineExpectationsTest.qll",
"java/ql/test/TestUtilities/InlineExpectationsTest.qll",
"python/ql/test/TestUtilities/InlineExpectationsTest.qll",
"ruby/ql/test/TestUtilities/InlineExpectationsTest.qll",
"ql/ql/test/TestUtilities/InlineExpectationsTest.qll",
"go/ql/test/TestUtilities/InlineExpectationsTest.qll",
"swift/ql/test/TestUtilities/InlineExpectationsTest.qll"
],
"C++ ExternalAPIs": [
"cpp/ql/src/Security/CWE/CWE-020/ExternalAPIs.qll",
"cpp/ql/src/Security/CWE/CWE-020/ir/ExternalAPIs.qll"
@@ -505,14 +496,6 @@
"python/ql/lib/semmle/python/dataflow/new/internal/TypeTracker.qll",
"ruby/ql/lib/codeql/ruby/typetracking/TypeTracker.qll"
],
"CodeQL Tutorial": [
"cpp/ql/lib/tutorial.qll",
"csharp/ql/lib/tutorial.qll",
"java/ql/lib/tutorial.qll",
"javascript/ql/lib/tutorial.qll",
"python/ql/lib/tutorial.qll",
"ruby/ql/lib/tutorial.qll"
],
"AccessPathSyntax": [
"csharp/ql/lib/semmle/code/csharp/dataflow/internal/AccessPathSyntax.qll",
"go/ql/lib/semmle/go/dataflow/internal/AccessPathSyntax.qll",
@@ -531,11 +514,6 @@
"ruby/ql/lib/codeql/ruby/internal/ConceptsShared.qll",
"javascript/ql/lib/semmle/javascript/internal/ConceptsShared.qll"
],
"Hostname Regexp queries": [
"javascript/ql/src/Security/CWE-020/HostnameRegexpShared.qll",
"python/ql/src/Security/CWE-020/HostnameRegexpShared.qll",
"ruby/ql/src/queries/security/cwe-020/HostnameRegexpShared.qll"
],
"ApiGraphModels": [
"javascript/ql/lib/semmle/javascript/frameworks/data/internal/ApiGraphModels.qll",
"ruby/ql/lib/codeql/ruby/frameworks/data/internal/ApiGraphModels.qll",

View File

@@ -13,5 +13,5 @@ predicate isExprWithNewBuiltin(Expr expr) {
from Expr expr, int kind, int kind_new, Location location
where
exprs(expr, kind, location) and
if isExprWithNewBuiltin(expr) then kind_new = 0 else kind_new = kind
if isExprWithNewBuiltin(expr) then kind_new = 1 else kind_new = kind
select expr, kind_new, location

View File

@@ -9,5 +9,5 @@ class Location extends @location_expr {
from Expr expr, int kind, int kind_new, Location location
where
exprs(expr, kind, location) and
if expr instanceof @blockassignexpr then kind_new = 0 else kind_new = kind
if expr instanceof @blockassignexpr then kind_new = 1 else kind_new = kind
select expr, kind_new, location

View File

@@ -0,0 +1,11 @@
class BuiltinType extends @builtintype {
string toString() { none() }
}
from BuiltinType type, string name, int kind, int kind_new, int size, int sign, int alignment
where
builtintypes(type, name, kind, size, sign, alignment) and
if type instanceof @float16 or type instanceof @complex_float16
then kind_new = 2
else kind_new = kind
select type, name, kind_new, size, sign, alignment

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,3 @@
description: Introduce (_Complex) _Float16 type
compatibility: backwards
builtintypes.rel: run builtintypes.qlo

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,2 @@
description: Uncomment case splits in dbscheme
compatibility: full

View File

@@ -1,3 +1,32 @@
## 0.5.1
No user-facing changes.
## 0.5.0
### Breaking Changes
The predicates in the `MustFlow::Configuration` class used by the `MustFlow` library (`semmle.code.cpp.ir.dataflow.MustFlow`) have changed to be defined directly in terms of the C++ IR instead of IR dataflow nodes.
### Deprecated APIs
* Deprecated `semmle.code.cpp.ir.dataflow.DefaultTaintTracking`. Use `semmle.code.cpp.ir.dataflow.TaintTracking`.
* Deprecated `semmle.code.cpp.security.TaintTrackingImpl`. Use `semmle.code.cpp.ir.dataflow.TaintTracking`.
* Deprecated `semmle.code.cpp.valuenumbering.GlobalValueNumberingImpl`. Use `semmle.code.cpp.valuenumbering.GlobalValueNumbering`, which exposes the same API.
### Minor Analysis Improvements
* The `ArgvSource` flow source now uses the second parameter of `main` as its source instead of the uses of this parameter.
* The `ArgvSource` flow source has been generalized to handle cases where the argument vector of `main` is not named `argv`.
* The `getaddrinfo` function is now recognized as a flow source.
* The `secure_getenv` and `_wgetenv` functions are now recognized as local flow sources.
* The `scanf` and `fscanf` functions and their variants are now recognized as flow sources.
* Deleted the deprecated `getName` and `getShortName` predicates from the `Folder` class.
## 0.4.6
No user-facing changes.
## 0.4.5
No user-facing changes.

View File

@@ -1,6 +0,0 @@
---
category: deprecated
---
* Deprecated `semmle.code.cpp.valuenumbering.GlobalValueNumberingImpl`. Use `semmle.code.cpp.valuenumbering.GlobalValueNumbering`, which exposes the same API.

View File

@@ -1,4 +0,0 @@
---
category: breaking
---
The predicates in the `MustFlow::Configuration` class used by the `MustFlow` library (`semmle.code.cpp.ir.dataflow.MustFlow`) have changed to be defined directly in terms of the C++ IR instead of IR dataflow nodes.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* Deleted the deprecated `getName` and `getShortName` predicates from the `Folder` class.

View File

@@ -1,6 +0,0 @@
---
category: deprecated
---
* Deprecated `semmle.code.cpp.ir.dataflow.DefaultTaintTracking`. Use `semmle.code.cpp.ir.dataflow.TaintTracking`.
* Deprecated `semmle.code.cpp.security.TaintTrackingImpl`. Use `semmle.code.cpp.ir.dataflow.TaintTracking`.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* The `getaddrinfo` function is now recognized as a flow source.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* The `secure_getenv` and `_wgetenv` functions are now recognized as local flow sources.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* The `scanf` and `fscanf` functions and their variants are now recognized as flow sources.

View File

@@ -1,4 +0,0 @@
---
category: minorAnalysis
---
* The `ArgvSource` flow source has been generalized to handle cases where the argument vector of `main` is not named `argv`.

View File

@@ -0,0 +1,3 @@
## 0.4.6
No user-facing changes.

View File

@@ -0,0 +1,20 @@
## 0.5.0
### Breaking Changes
The predicates in the `MustFlow::Configuration` class used by the `MustFlow` library (`semmle.code.cpp.ir.dataflow.MustFlow`) have changed to be defined directly in terms of the C++ IR instead of IR dataflow nodes.
### Deprecated APIs
* Deprecated `semmle.code.cpp.ir.dataflow.DefaultTaintTracking`. Use `semmle.code.cpp.ir.dataflow.TaintTracking`.
* Deprecated `semmle.code.cpp.security.TaintTrackingImpl`. Use `semmle.code.cpp.ir.dataflow.TaintTracking`.
* Deprecated `semmle.code.cpp.valuenumbering.GlobalValueNumberingImpl`. Use `semmle.code.cpp.valuenumbering.GlobalValueNumbering`, which exposes the same API.
### Minor Analysis Improvements
* The `ArgvSource` flow source now uses the second parameter of `main` as its source instead of the uses of this parameter.
* The `ArgvSource` flow source has been generalized to handle cases where the argument vector of `main` is not named `argv`.
* The `getaddrinfo` function is now recognized as a flow source.
* The `secure_getenv` and `_wgetenv` functions are now recognized as local flow sources.
* The `scanf` and `fscanf` functions and their variants are now recognized as flow sources.
* Deleted the deprecated `getName` and `getShortName` predicates from the `Folder` class.

View File

@@ -0,0 +1,3 @@
## 0.5.1
No user-facing changes.

View File

@@ -1,2 +1,2 @@
---
lastReleaseVersion: 0.4.5
lastReleaseVersion: 0.5.1

View File

@@ -123,6 +123,13 @@ private predicate constructorCallTypeMention(ConstructorCall cc, TypeMention tm)
)
}
/** Holds if `loc` has the container `container` and is on the line starting at `startLine`. */
pragma[nomagic]
private predicate hasContainerAndStartLine(Location loc, Container container, int startLine) {
loc.getStartLine() = startLine and
loc.getContainer() = container
}
/**
* Gets an element, of kind `kind`, that element `e` uses, if any.
* Attention: This predicate yields multiple definitions for a single location.
@@ -159,9 +166,9 @@ Top definitionOf(Top e, string kind) {
// Multiple type mentions can be generated when a typedef is used, and
// in such cases we want to exclude all but the originating typedef.
not exists(Type secondary |
exists(TypeMention tm, File f, int startline, int startcol |
exists(File f, int startline, int startcol |
typeMentionStartLoc(e, result, f, startline, startcol) and
typeMentionStartLoc(tm, secondary, f, startline, startcol) and
typeMentionStartLoc(_, secondary, f, startline, startcol) and
(
result = secondary.(TypedefType).getBaseType() or
result = secondary.(TypedefType).getBaseType().(SpecifiedType).getBaseType()
@@ -184,11 +191,9 @@ Top definitionOf(Top e, string kind) {
kind = "I" and
result = e.(Include).getIncludedFile() and
// exclude `#include` directives containing macros
not exists(MacroInvocation mi, Location l1, Location l2 |
l1 = e.(Include).getLocation() and
l2 = mi.getLocation() and
l1.getContainer() = l2.getContainer() and
l1.getStartLine() = l2.getStartLine()
not exists(MacroInvocation mi, Container container, int startLine |
hasContainerAndStartLine(e.(Include).getLocation(), container, startLine) and
hasContainerAndStartLine(mi.getLocation(), container, startLine)
// (an #include directive must be always on it's own line)
)
) and

View File

@@ -622,7 +622,11 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
}
private module Stage1 implements StageSig {
class Ap = Unit;
class Ap extends int {
// workaround for bad functionality-induced joins (happens when using `Unit`)
pragma[nomagic]
Ap() { this in [0 .. 1] and this < 1 }
}
private class Cc = boolean;
@@ -872,9 +876,9 @@ private module Stage1 implements StageSig {
pragma[nomagic]
private predicate revFlowOut(ReturnPosition pos, Configuration config) {
exists(DataFlowCall call, NodeEx out |
exists(NodeEx out |
revFlow(out, _, config) and
viableReturnPosOutNodeCandFwd1(call, pos, out, config)
viableReturnPosOutNodeCandFwd1(_, pos, out, config)
)
}
@@ -1327,8 +1331,8 @@ private module MkStage<StageSig PrevStage> {
*/
pragma[nomagic]
additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, ApApprox apa, Configuration config
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
ApApprox apa, Configuration config
) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
PrevStage::revFlow(node, state, apa, config) and
@@ -1337,21 +1341,21 @@ private module MkStage<StageSig PrevStage> {
pragma[inline]
additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
Configuration config
) {
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
}
pragma[nomagic]
private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, ApApprox apa, Configuration config
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
ApApprox apa, Configuration config
) {
sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and
summaryCtx = TParameterPositionNone() and
summaryCtx = TParamNodeNone() and
ap = getApNil(node) and
apa = getApprox(ap)
or
@@ -1372,7 +1376,7 @@ private module MkStage<StageSig PrevStage> {
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
summaryCtx = TParamNodeNone() and
argAp = apNone()
)
or
@@ -1380,7 +1384,7 @@ private module MkStage<StageSig PrevStage> {
fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
summaryCtx = TParamNodeNone() and
argAp = apNone() and
ap = getApNil(node) and
apa = getApprox(ap)
@@ -1390,7 +1394,7 @@ private module MkStage<StageSig PrevStage> {
fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStateStep(mid, state0, node, state, config) and
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
summaryCtx = TParamNodeNone() and
argAp = apNone() and
ap = getApNil(node) and
apa = getApprox(ap)
@@ -1414,10 +1418,10 @@ private module MkStage<StageSig PrevStage> {
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
if PrevStage::parameterMayFlowThrough(node, apa, config)
then (
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
summaryCtx = TParamNodeSome(node.asNode()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
summaryCtx = TParamNodeNone() and argAp = apNone()
)
or
// flow out of a callable
@@ -1433,16 +1437,19 @@ private module MkStage<StageSig PrevStage> {
)
or
// flow through a callable
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
exists(
DataFlowCall call, CcCall ccc, RetNodeEx ret, boolean allowsFieldFlow, ApApprox innerArgApa
|
fwdFlowThrough(call, cc, state, ccc, summaryCtx, argAp, ap, apa, ret, innerArgApa, config) and
flowThroughOutOfCall(call, ccc, ret, node, allowsFieldFlow, innerArgApa, apa, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
pragma[nomagic]
private predicate fwdFlowStore(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType, ApApprox apa1 |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
@@ -1473,8 +1480,8 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate fwdFlowRead0(
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ApNonNil ap, Configuration config
NodeEx node1, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, ApNonNil ap,
Configuration config
) {
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, _, _, config)
@@ -1483,7 +1490,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
) {
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and
@@ -1493,7 +1500,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
ParamNodeOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
) {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
@@ -1505,64 +1512,38 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate fwdFlowRetFromArg(
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
RetNodeEx ret, FlowState state, CcCall ccc, ParamNodeEx summaryCtx, Ap argAp, ApApprox argApa,
Ap ap, ApApprox apa, Configuration config
) {
exists(DataFlowCallable c, ReturnKindExt kind |
exists(ReturnKindExt kind |
fwdFlow(pragma[only_bind_into](ret), state, ccc,
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
getApprox(argAp) = argApa and
c = ret.getEnclosingCallable() and
TParamNodeSome(pragma[only_bind_into](summaryCtx.asNode())),
pragma[only_bind_into](apSome(argAp)), ap, pragma[only_bind_into](apa),
pragma[only_bind_into](config)) and
kind = ret.getKind() and
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
parameterFlowThroughAllowed(p, kind)
parameterFlowThroughAllowed(summaryCtx, kind) and
argApa = getApprox(argAp) and
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config))
)
}
pragma[inline]
private predicate fwdFlowInMayFlowThrough(
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
private predicate fwdFlowThrough0(
DataFlowCall call, Cc cc, FlowState state, CcCall ccc, ParamNodeOption summaryCtx,
ApOption argAp, Ap ap, ApApprox apa, RetNodeEx ret, ParamNodeEx innerSummaryCtx,
Ap innerArgAp, ApApprox innerArgApa, Configuration config
) {
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(param, apa, config)
}
// dedup before joining with `flowThroughOutOfCall`
pragma[nomagic]
private predicate fwdFlowInMayFlowThroughProj(
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
}
/**
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
* in the flow covered by `fwdFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate fwdFlowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
ApApprox argApa, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
fwdFlowRetFromArg(ret, state, ccc, innerSummaryCtx, innerArgAp, innerArgApa, ap, apa, config) and
fwdFlowIsEntered(call, cc, ccc, summaryCtx, argAp, innerSummaryCtx, innerArgAp, config)
}
pragma[nomagic]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
ApApprox apa, Configuration config
private predicate fwdFlowThrough(
DataFlowCall call, Cc cc, FlowState state, CcCall ccc, ParamNodeOption summaryCtx,
ApOption argAp, Ap ap, ApApprox apa, RetNodeEx ret, ApApprox innerArgApa, Configuration config
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
config) and
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
)
fwdFlowThrough0(call, cc, state, ccc, summaryCtx, argAp, ap, apa, ret, _, _, innerArgApa,
config)
}
/**
@@ -1571,12 +1552,14 @@ private module MkStage<StageSig PrevStage> {
*/
pragma[nomagic]
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ParameterPosition pos, Ap ap, Configuration config
DataFlowCall call, Cc cc, CcCall innerCc, ParamNodeOption summaryCtx, ApOption argAp,
ParamNodeEx p, Ap ap, Configuration config
) {
exists(ParamNodeEx param |
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
pos = param.getPosition()
exists(ApApprox apa |
fwdFlowIn(call, pragma[only_bind_into](p), _, cc, innerCc, summaryCtx, argAp, ap,
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(p, apa, config) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config))
)
}
@@ -1596,23 +1579,31 @@ private module MkStage<StageSig PrevStage> {
fwdFlowConsCand(ap1, c, ap2, config)
}
pragma[nomagic]
private predicate returnFlowsThrough0(
DataFlowCall call, FlowState state, CcCall ccc, Ap ap, ApApprox apa, RetNodeEx ret,
ParamNodeEx innerSummaryCtx, Ap innerArgAp, ApApprox innerArgApa, Configuration config
) {
fwdFlowThrough0(call, _, state, ccc, _, _, ap, apa, ret, innerSummaryCtx, innerArgAp,
innerArgApa, config)
}
pragma[nomagic]
private predicate returnFlowsThrough(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
RetNodeEx ret, ReturnPosition pos, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
Ap ap, Configuration config
) {
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
kind = ret.getKind() and
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
exists(DataFlowCall call, ApApprox apa, boolean allowsFieldFlow, ApApprox innerArgApa |
returnFlowsThrough0(call, state, ccc, ap, apa, ret, p, argAp, innerArgApa, config) and
flowThroughOutOfCall(call, ccc, ret, _, allowsFieldFlow, innerArgApa, apa, config) and
pos = ret.getReturnPosition() and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
pragma[nomagic]
private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp, Ap ap,
Configuration config
) {
exists(ApApprox argApa |
@@ -1620,7 +1611,7 @@ private module MkStage<StageSig PrevStage> {
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
pragma[only_bind_into](config)) and
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), ap,
pragma[only_bind_into](config)) and
if allowsFieldFlow = false then argAp instanceof ApNil else any()
)
@@ -1639,12 +1630,13 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate flowOutOfCallAp(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, NodeEx out, boolean allowsFieldFlow,
Ap ap, Configuration config
) {
exists(ApApprox apa |
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
fwdFlow(ret, _, _, _, _, ap, apa, config)
flowOutOfCallApa(call, ret, _, out, allowsFieldFlow, apa, config) and
fwdFlow(ret, _, _, _, _, ap, apa, config) and
pos = ret.getReturnPosition()
)
}
@@ -1739,17 +1731,17 @@ private module MkStage<StageSig PrevStage> {
)
or
// flow through a callable
exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
exists(DataFlowCall call, ParamNodeEx p, Ap innerReturnAp |
revFlowThrough(call, returnCtx, p, state, _, returnAp, ap, innerReturnAp, config) and
flowThroughIntoCall(call, node, p, _, ap, innerReturnAp, config)
)
or
// flow out of a callable
exists(ReturnKindExt kind |
revFlowOut(_, node, kind, state, _, _, ap, config) and
if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
exists(ReturnPosition pos |
revFlowOut(_, node, pos, state, _, _, ap, config) and
if returnFlowsThrough(node, pos, state, _, _, _, ap, config)
then (
returnCtx = TReturnCtxMaybeFlowThrough(kind) and
returnCtx = TReturnCtxMaybeFlowThrough(pos) and
returnAp = apSome(ap)
) else (
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
@@ -1782,47 +1774,33 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate revFlowOut(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, FlowState state, ReturnCtx returnCtx,
ApOption returnAp, Ap ap, Configuration config
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
flowOutOfCallAp(call, ret, pos, out, allowsFieldFlow, ap, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
/**
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
* in the flow covered by `revFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate revFlowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
Configuration config
) {
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
revFlowIsReturned(call, _, _, _, _, config)
}
pragma[nomagic]
private predicate revFlowParamToReturn(
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
ParamNodeEx p, FlowState state, ReturnPosition pos, Ap returnAp, Ap ap, Configuration config
) {
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind)
revFlow(pragma[only_bind_into](p), state, TReturnCtxMaybeFlowThrough(pos), apSome(returnAp),
pragma[only_bind_into](ap), pragma[only_bind_into](config)) and
parameterFlowThroughAllowed(p, pos.getKind()) and
PrevStage::parameterMayFlowThrough(p, getApprox(ap), config)
}
pragma[nomagic]
private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
Configuration config
private predicate revFlowThrough(
DataFlowCall call, ReturnCtx returnCtx, ParamNodeEx p, FlowState state, ReturnPosition pos,
ApOption returnAp, Ap ap, Ap innerReturnAp, Configuration config
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
)
revFlowParamToReturn(p, state, pos, innerReturnAp, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, pos, innerReturnAp, config)
}
/**
@@ -1832,12 +1810,12 @@ private module MkStage<StageSig PrevStage> {
*/
pragma[nomagic]
private predicate revFlowIsReturned(
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnPosition pos, Ap ap,
Configuration config
) {
exists(RetNodeEx ret, FlowState state, CcCall ccc |
revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
revFlowOut(call, ret, pos, state, returnCtx, returnAp, ap, config) and
returnFlowsThrough(ret, pos, state, ccc, _, _, ap, config) and
matchesCall(ccc, call)
)
}
@@ -1915,17 +1893,17 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
ParamNodeEx p, Ap ap, ReturnPosition pos, Ap returnAp, Configuration config
) {
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind)
revFlow(p, _, TReturnCtxMaybeFlowThrough(pos), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, pos.getKind())
}
pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(RetNodeEx ret, ReturnKindExt kind |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, _, config)
exists(ReturnPosition pos |
returnFlowsThrough(_, pos, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, pos, _, config)
)
}
@@ -1933,20 +1911,21 @@ private module MkStage<StageSig PrevStage> {
predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
) {
exists(ParamNodeEx p |
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
parameterFlowsThroughRev(p, argAp, kind, ap, config)
exists(ParamNodeEx p, ReturnPosition pos |
returnFlowsThrough(ret, pos, _, _, p, argAp, ap, config) and
parameterFlowsThroughRev(p, argAp, pos, ap, config) and
kind = pos.getKind()
)
}
pragma[nomagic]
predicate revFlowInToReturnIsReturned(
private predicate revFlowThroughArg(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
Ap ap, Configuration config
) {
exists(ReturnKindExt returnKind0, Ap returnAp0 |
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
exists(ParamNodeEx p, Ap innerReturnAp |
revFlowThrough(call, returnCtx, p, state, _, returnAp, ap, innerReturnAp, config) and
flowThroughIntoCall(call, arg, p, _, ap, innerReturnAp, config)
)
}
@@ -1954,7 +1933,7 @@ private module MkStage<StageSig PrevStage> {
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
revFlowThroughArg(call, arg, state, returnCtx, returnAp, ap, config)
)
}
@@ -1967,8 +1946,9 @@ private module MkStage<StageSig PrevStage> {
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
tuples =
count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
count(NodeEx n, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap |
fwdFlow(n, state, cc, summaryCtx, argAp, ap, config)
)
or
fwd = false and
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
@@ -2823,13 +2803,12 @@ private Configuration unbindConf(Configuration conf) {
pragma[nomagic]
private predicate nodeMayUseSummary0(
NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
Configuration config
NodeEx n, ParamNodeEx p, FlowState state, AccessPathApprox apa, Configuration config
) {
exists(AccessPathApprox apa0 |
c = n.getEnclosingCallable() and
Stage5::parameterMayFlowThrough(p, _, _) and
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParamNodeSome(p.asNode()),
TAccessPathApproxSome(apa), apa0, config)
)
}
@@ -2838,10 +2817,9 @@ pragma[nomagic]
private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) {
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
exists(ParamNodeEx p |
Stage5::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos)
nodeMayUseSummary0(n, p, state, apa, config)
)
}
@@ -3771,8 +3749,8 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap,
AccessPathApprox apa, Configuration config
) {
exists(PathNodeMid mid, RetNodeEx ret |
pathNode(mid, ret, state, cc, sc, ap, config, _) and
exists(RetNodeEx ret |
pathNode(_, ret, state, cc, sc, ap, config, _) and
kind = ret.getKind() and
apa = ap.getApprox() and
parameterFlowThroughAllowed(sc.getParamNode(), kind)
@@ -4234,17 +4212,15 @@ private module FlowExploration {
ap = TRevPartialNil() and
exists(config.explorationLimit())
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
not clearsContentEx(node, ap.getHead()) and
(
notExpectsContent(node) or
expectsContentEx(node, ap.getHead())
) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
)
revPartialPathStep(_, node, state, sc1, sc2, sc3, ap, config) and
not clearsContentEx(node, ap.getHead()) and
(
notExpectsContent(node) or
expectsContentEx(node, ap.getHead())
) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
}
pragma[nomagic]
@@ -4252,19 +4228,17 @@ private module FlowExploration {
NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
TSummaryCtx3 sc3, PartialAccessPath ap, Configuration config
) {
exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
not clearsContentEx(node, ap.getHead().getContent()) and
(
notExpectsContent(node) or
expectsContentEx(node, ap.getHead().getContent())
) and
if node.asNode() instanceof CastingNode
then compatibleTypes(node.getDataFlowType(), ap.getType())
else any()
)
partialPathStep(_, node, state, cc, sc1, sc2, sc3, ap, config) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
not clearsContentEx(node, ap.getHead().getContent()) and
(
notExpectsContent(node) or
expectsContentEx(node, ap.getHead().getContent())
) and
if node.asNode() instanceof CastingNode
then compatibleTypes(node.getDataFlowType(), ap.getType())
else any()
}
/**

View File

@@ -622,7 +622,11 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
}
private module Stage1 implements StageSig {
class Ap = Unit;
class Ap extends int {
// workaround for bad functionality-induced joins (happens when using `Unit`)
pragma[nomagic]
Ap() { this in [0 .. 1] and this < 1 }
}
private class Cc = boolean;
@@ -872,9 +876,9 @@ private module Stage1 implements StageSig {
pragma[nomagic]
private predicate revFlowOut(ReturnPosition pos, Configuration config) {
exists(DataFlowCall call, NodeEx out |
exists(NodeEx out |
revFlow(out, _, config) and
viableReturnPosOutNodeCandFwd1(call, pos, out, config)
viableReturnPosOutNodeCandFwd1(_, pos, out, config)
)
}
@@ -1327,8 +1331,8 @@ private module MkStage<StageSig PrevStage> {
*/
pragma[nomagic]
additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, ApApprox apa, Configuration config
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
ApApprox apa, Configuration config
) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
PrevStage::revFlow(node, state, apa, config) and
@@ -1337,21 +1341,21 @@ private module MkStage<StageSig PrevStage> {
pragma[inline]
additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
Configuration config
) {
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
}
pragma[nomagic]
private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, ApApprox apa, Configuration config
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
ApApprox apa, Configuration config
) {
sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and
summaryCtx = TParameterPositionNone() and
summaryCtx = TParamNodeNone() and
ap = getApNil(node) and
apa = getApprox(ap)
or
@@ -1372,7 +1376,7 @@ private module MkStage<StageSig PrevStage> {
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
summaryCtx = TParamNodeNone() and
argAp = apNone()
)
or
@@ -1380,7 +1384,7 @@ private module MkStage<StageSig PrevStage> {
fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
summaryCtx = TParamNodeNone() and
argAp = apNone() and
ap = getApNil(node) and
apa = getApprox(ap)
@@ -1390,7 +1394,7 @@ private module MkStage<StageSig PrevStage> {
fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStateStep(mid, state0, node, state, config) and
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
summaryCtx = TParamNodeNone() and
argAp = apNone() and
ap = getApNil(node) and
apa = getApprox(ap)
@@ -1414,10 +1418,10 @@ private module MkStage<StageSig PrevStage> {
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
if PrevStage::parameterMayFlowThrough(node, apa, config)
then (
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
summaryCtx = TParamNodeSome(node.asNode()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
summaryCtx = TParamNodeNone() and argAp = apNone()
)
or
// flow out of a callable
@@ -1433,16 +1437,19 @@ private module MkStage<StageSig PrevStage> {
)
or
// flow through a callable
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
exists(
DataFlowCall call, CcCall ccc, RetNodeEx ret, boolean allowsFieldFlow, ApApprox innerArgApa
|
fwdFlowThrough(call, cc, state, ccc, summaryCtx, argAp, ap, apa, ret, innerArgApa, config) and
flowThroughOutOfCall(call, ccc, ret, node, allowsFieldFlow, innerArgApa, apa, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
pragma[nomagic]
private predicate fwdFlowStore(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType, ApApprox apa1 |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
@@ -1473,8 +1480,8 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate fwdFlowRead0(
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ApNonNil ap, Configuration config
NodeEx node1, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, ApNonNil ap,
Configuration config
) {
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, _, _, config)
@@ -1483,7 +1490,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
) {
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and
@@ -1493,7 +1500,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
ParamNodeOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
) {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
@@ -1505,64 +1512,38 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate fwdFlowRetFromArg(
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
RetNodeEx ret, FlowState state, CcCall ccc, ParamNodeEx summaryCtx, Ap argAp, ApApprox argApa,
Ap ap, ApApprox apa, Configuration config
) {
exists(DataFlowCallable c, ReturnKindExt kind |
exists(ReturnKindExt kind |
fwdFlow(pragma[only_bind_into](ret), state, ccc,
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
getApprox(argAp) = argApa and
c = ret.getEnclosingCallable() and
TParamNodeSome(pragma[only_bind_into](summaryCtx.asNode())),
pragma[only_bind_into](apSome(argAp)), ap, pragma[only_bind_into](apa),
pragma[only_bind_into](config)) and
kind = ret.getKind() and
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
parameterFlowThroughAllowed(p, kind)
parameterFlowThroughAllowed(summaryCtx, kind) and
argApa = getApprox(argAp) and
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config))
)
}
pragma[inline]
private predicate fwdFlowInMayFlowThrough(
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
private predicate fwdFlowThrough0(
DataFlowCall call, Cc cc, FlowState state, CcCall ccc, ParamNodeOption summaryCtx,
ApOption argAp, Ap ap, ApApprox apa, RetNodeEx ret, ParamNodeEx innerSummaryCtx,
Ap innerArgAp, ApApprox innerArgApa, Configuration config
) {
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(param, apa, config)
}
// dedup before joining with `flowThroughOutOfCall`
pragma[nomagic]
private predicate fwdFlowInMayFlowThroughProj(
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
}
/**
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
* in the flow covered by `fwdFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate fwdFlowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
ApApprox argApa, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
fwdFlowRetFromArg(ret, state, ccc, innerSummaryCtx, innerArgAp, innerArgApa, ap, apa, config) and
fwdFlowIsEntered(call, cc, ccc, summaryCtx, argAp, innerSummaryCtx, innerArgAp, config)
}
pragma[nomagic]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
ApApprox apa, Configuration config
private predicate fwdFlowThrough(
DataFlowCall call, Cc cc, FlowState state, CcCall ccc, ParamNodeOption summaryCtx,
ApOption argAp, Ap ap, ApApprox apa, RetNodeEx ret, ApApprox innerArgApa, Configuration config
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
config) and
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
)
fwdFlowThrough0(call, cc, state, ccc, summaryCtx, argAp, ap, apa, ret, _, _, innerArgApa,
config)
}
/**
@@ -1571,12 +1552,14 @@ private module MkStage<StageSig PrevStage> {
*/
pragma[nomagic]
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ParameterPosition pos, Ap ap, Configuration config
DataFlowCall call, Cc cc, CcCall innerCc, ParamNodeOption summaryCtx, ApOption argAp,
ParamNodeEx p, Ap ap, Configuration config
) {
exists(ParamNodeEx param |
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
pos = param.getPosition()
exists(ApApprox apa |
fwdFlowIn(call, pragma[only_bind_into](p), _, cc, innerCc, summaryCtx, argAp, ap,
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(p, apa, config) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config))
)
}
@@ -1596,23 +1579,31 @@ private module MkStage<StageSig PrevStage> {
fwdFlowConsCand(ap1, c, ap2, config)
}
pragma[nomagic]
private predicate returnFlowsThrough0(
DataFlowCall call, FlowState state, CcCall ccc, Ap ap, ApApprox apa, RetNodeEx ret,
ParamNodeEx innerSummaryCtx, Ap innerArgAp, ApApprox innerArgApa, Configuration config
) {
fwdFlowThrough0(call, _, state, ccc, _, _, ap, apa, ret, innerSummaryCtx, innerArgAp,
innerArgApa, config)
}
pragma[nomagic]
private predicate returnFlowsThrough(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
RetNodeEx ret, ReturnPosition pos, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
Ap ap, Configuration config
) {
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
kind = ret.getKind() and
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
exists(DataFlowCall call, ApApprox apa, boolean allowsFieldFlow, ApApprox innerArgApa |
returnFlowsThrough0(call, state, ccc, ap, apa, ret, p, argAp, innerArgApa, config) and
flowThroughOutOfCall(call, ccc, ret, _, allowsFieldFlow, innerArgApa, apa, config) and
pos = ret.getReturnPosition() and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
pragma[nomagic]
private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp, Ap ap,
Configuration config
) {
exists(ApApprox argApa |
@@ -1620,7 +1611,7 @@ private module MkStage<StageSig PrevStage> {
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
pragma[only_bind_into](config)) and
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), ap,
pragma[only_bind_into](config)) and
if allowsFieldFlow = false then argAp instanceof ApNil else any()
)
@@ -1639,12 +1630,13 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate flowOutOfCallAp(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, NodeEx out, boolean allowsFieldFlow,
Ap ap, Configuration config
) {
exists(ApApprox apa |
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
fwdFlow(ret, _, _, _, _, ap, apa, config)
flowOutOfCallApa(call, ret, _, out, allowsFieldFlow, apa, config) and
fwdFlow(ret, _, _, _, _, ap, apa, config) and
pos = ret.getReturnPosition()
)
}
@@ -1739,17 +1731,17 @@ private module MkStage<StageSig PrevStage> {
)
or
// flow through a callable
exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
exists(DataFlowCall call, ParamNodeEx p, Ap innerReturnAp |
revFlowThrough(call, returnCtx, p, state, _, returnAp, ap, innerReturnAp, config) and
flowThroughIntoCall(call, node, p, _, ap, innerReturnAp, config)
)
or
// flow out of a callable
exists(ReturnKindExt kind |
revFlowOut(_, node, kind, state, _, _, ap, config) and
if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
exists(ReturnPosition pos |
revFlowOut(_, node, pos, state, _, _, ap, config) and
if returnFlowsThrough(node, pos, state, _, _, _, ap, config)
then (
returnCtx = TReturnCtxMaybeFlowThrough(kind) and
returnCtx = TReturnCtxMaybeFlowThrough(pos) and
returnAp = apSome(ap)
) else (
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
@@ -1782,47 +1774,33 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate revFlowOut(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, FlowState state, ReturnCtx returnCtx,
ApOption returnAp, Ap ap, Configuration config
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
flowOutOfCallAp(call, ret, pos, out, allowsFieldFlow, ap, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
/**
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
* in the flow covered by `revFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate revFlowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
Configuration config
) {
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
revFlowIsReturned(call, _, _, _, _, config)
}
pragma[nomagic]
private predicate revFlowParamToReturn(
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
ParamNodeEx p, FlowState state, ReturnPosition pos, Ap returnAp, Ap ap, Configuration config
) {
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind)
revFlow(pragma[only_bind_into](p), state, TReturnCtxMaybeFlowThrough(pos), apSome(returnAp),
pragma[only_bind_into](ap), pragma[only_bind_into](config)) and
parameterFlowThroughAllowed(p, pos.getKind()) and
PrevStage::parameterMayFlowThrough(p, getApprox(ap), config)
}
pragma[nomagic]
private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
Configuration config
private predicate revFlowThrough(
DataFlowCall call, ReturnCtx returnCtx, ParamNodeEx p, FlowState state, ReturnPosition pos,
ApOption returnAp, Ap ap, Ap innerReturnAp, Configuration config
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
)
revFlowParamToReturn(p, state, pos, innerReturnAp, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, pos, innerReturnAp, config)
}
/**
@@ -1832,12 +1810,12 @@ private module MkStage<StageSig PrevStage> {
*/
pragma[nomagic]
private predicate revFlowIsReturned(
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnPosition pos, Ap ap,
Configuration config
) {
exists(RetNodeEx ret, FlowState state, CcCall ccc |
revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
revFlowOut(call, ret, pos, state, returnCtx, returnAp, ap, config) and
returnFlowsThrough(ret, pos, state, ccc, _, _, ap, config) and
matchesCall(ccc, call)
)
}
@@ -1915,17 +1893,17 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
ParamNodeEx p, Ap ap, ReturnPosition pos, Ap returnAp, Configuration config
) {
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind)
revFlow(p, _, TReturnCtxMaybeFlowThrough(pos), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, pos.getKind())
}
pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(RetNodeEx ret, ReturnKindExt kind |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, _, config)
exists(ReturnPosition pos |
returnFlowsThrough(_, pos, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, pos, _, config)
)
}
@@ -1933,20 +1911,21 @@ private module MkStage<StageSig PrevStage> {
predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
) {
exists(ParamNodeEx p |
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
parameterFlowsThroughRev(p, argAp, kind, ap, config)
exists(ParamNodeEx p, ReturnPosition pos |
returnFlowsThrough(ret, pos, _, _, p, argAp, ap, config) and
parameterFlowsThroughRev(p, argAp, pos, ap, config) and
kind = pos.getKind()
)
}
pragma[nomagic]
predicate revFlowInToReturnIsReturned(
private predicate revFlowThroughArg(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
Ap ap, Configuration config
) {
exists(ReturnKindExt returnKind0, Ap returnAp0 |
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
exists(ParamNodeEx p, Ap innerReturnAp |
revFlowThrough(call, returnCtx, p, state, _, returnAp, ap, innerReturnAp, config) and
flowThroughIntoCall(call, arg, p, _, ap, innerReturnAp, config)
)
}
@@ -1954,7 +1933,7 @@ private module MkStage<StageSig PrevStage> {
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
revFlowThroughArg(call, arg, state, returnCtx, returnAp, ap, config)
)
}
@@ -1967,8 +1946,9 @@ private module MkStage<StageSig PrevStage> {
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
tuples =
count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
count(NodeEx n, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap |
fwdFlow(n, state, cc, summaryCtx, argAp, ap, config)
)
or
fwd = false and
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
@@ -2823,13 +2803,12 @@ private Configuration unbindConf(Configuration conf) {
pragma[nomagic]
private predicate nodeMayUseSummary0(
NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
Configuration config
NodeEx n, ParamNodeEx p, FlowState state, AccessPathApprox apa, Configuration config
) {
exists(AccessPathApprox apa0 |
c = n.getEnclosingCallable() and
Stage5::parameterMayFlowThrough(p, _, _) and
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParamNodeSome(p.asNode()),
TAccessPathApproxSome(apa), apa0, config)
)
}
@@ -2838,10 +2817,9 @@ pragma[nomagic]
private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) {
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
exists(ParamNodeEx p |
Stage5::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos)
nodeMayUseSummary0(n, p, state, apa, config)
)
}
@@ -3771,8 +3749,8 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap,
AccessPathApprox apa, Configuration config
) {
exists(PathNodeMid mid, RetNodeEx ret |
pathNode(mid, ret, state, cc, sc, ap, config, _) and
exists(RetNodeEx ret |
pathNode(_, ret, state, cc, sc, ap, config, _) and
kind = ret.getKind() and
apa = ap.getApprox() and
parameterFlowThroughAllowed(sc.getParamNode(), kind)
@@ -4234,17 +4212,15 @@ private module FlowExploration {
ap = TRevPartialNil() and
exists(config.explorationLimit())
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
not clearsContentEx(node, ap.getHead()) and
(
notExpectsContent(node) or
expectsContentEx(node, ap.getHead())
) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
)
revPartialPathStep(_, node, state, sc1, sc2, sc3, ap, config) and
not clearsContentEx(node, ap.getHead()) and
(
notExpectsContent(node) or
expectsContentEx(node, ap.getHead())
) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
}
pragma[nomagic]
@@ -4252,19 +4228,17 @@ private module FlowExploration {
NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
TSummaryCtx3 sc3, PartialAccessPath ap, Configuration config
) {
exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
not clearsContentEx(node, ap.getHead().getContent()) and
(
notExpectsContent(node) or
expectsContentEx(node, ap.getHead().getContent())
) and
if node.asNode() instanceof CastingNode
then compatibleTypes(node.getDataFlowType(), ap.getType())
else any()
)
partialPathStep(_, node, state, cc, sc1, sc2, sc3, ap, config) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
not clearsContentEx(node, ap.getHead().getContent()) and
(
notExpectsContent(node) or
expectsContentEx(node, ap.getHead().getContent())
) and
if node.asNode() instanceof CastingNode
then compatibleTypes(node.getDataFlowType(), ap.getType())
else any()
}
/**

View File

@@ -622,7 +622,11 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
}
private module Stage1 implements StageSig {
class Ap = Unit;
class Ap extends int {
// workaround for bad functionality-induced joins (happens when using `Unit`)
pragma[nomagic]
Ap() { this in [0 .. 1] and this < 1 }
}
private class Cc = boolean;
@@ -872,9 +876,9 @@ private module Stage1 implements StageSig {
pragma[nomagic]
private predicate revFlowOut(ReturnPosition pos, Configuration config) {
exists(DataFlowCall call, NodeEx out |
exists(NodeEx out |
revFlow(out, _, config) and
viableReturnPosOutNodeCandFwd1(call, pos, out, config)
viableReturnPosOutNodeCandFwd1(_, pos, out, config)
)
}
@@ -1327,8 +1331,8 @@ private module MkStage<StageSig PrevStage> {
*/
pragma[nomagic]
additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, ApApprox apa, Configuration config
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
ApApprox apa, Configuration config
) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
PrevStage::revFlow(node, state, apa, config) and
@@ -1337,21 +1341,21 @@ private module MkStage<StageSig PrevStage> {
pragma[inline]
additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
Configuration config
) {
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
}
pragma[nomagic]
private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, ApApprox apa, Configuration config
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
ApApprox apa, Configuration config
) {
sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and
summaryCtx = TParameterPositionNone() and
summaryCtx = TParamNodeNone() and
ap = getApNil(node) and
apa = getApprox(ap)
or
@@ -1372,7 +1376,7 @@ private module MkStage<StageSig PrevStage> {
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
summaryCtx = TParamNodeNone() and
argAp = apNone()
)
or
@@ -1380,7 +1384,7 @@ private module MkStage<StageSig PrevStage> {
fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
summaryCtx = TParamNodeNone() and
argAp = apNone() and
ap = getApNil(node) and
apa = getApprox(ap)
@@ -1390,7 +1394,7 @@ private module MkStage<StageSig PrevStage> {
fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStateStep(mid, state0, node, state, config) and
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
summaryCtx = TParamNodeNone() and
argAp = apNone() and
ap = getApNil(node) and
apa = getApprox(ap)
@@ -1414,10 +1418,10 @@ private module MkStage<StageSig PrevStage> {
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
if PrevStage::parameterMayFlowThrough(node, apa, config)
then (
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
summaryCtx = TParamNodeSome(node.asNode()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
summaryCtx = TParamNodeNone() and argAp = apNone()
)
or
// flow out of a callable
@@ -1433,16 +1437,19 @@ private module MkStage<StageSig PrevStage> {
)
or
// flow through a callable
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
exists(
DataFlowCall call, CcCall ccc, RetNodeEx ret, boolean allowsFieldFlow, ApApprox innerArgApa
|
fwdFlowThrough(call, cc, state, ccc, summaryCtx, argAp, ap, apa, ret, innerArgApa, config) and
flowThroughOutOfCall(call, ccc, ret, node, allowsFieldFlow, innerArgApa, apa, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
pragma[nomagic]
private predicate fwdFlowStore(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType, ApApprox apa1 |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
@@ -1473,8 +1480,8 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate fwdFlowRead0(
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ApNonNil ap, Configuration config
NodeEx node1, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, ApNonNil ap,
Configuration config
) {
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, _, _, config)
@@ -1483,7 +1490,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
) {
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and
@@ -1493,7 +1500,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
ParamNodeOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
) {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
@@ -1505,64 +1512,38 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate fwdFlowRetFromArg(
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
RetNodeEx ret, FlowState state, CcCall ccc, ParamNodeEx summaryCtx, Ap argAp, ApApprox argApa,
Ap ap, ApApprox apa, Configuration config
) {
exists(DataFlowCallable c, ReturnKindExt kind |
exists(ReturnKindExt kind |
fwdFlow(pragma[only_bind_into](ret), state, ccc,
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
getApprox(argAp) = argApa and
c = ret.getEnclosingCallable() and
TParamNodeSome(pragma[only_bind_into](summaryCtx.asNode())),
pragma[only_bind_into](apSome(argAp)), ap, pragma[only_bind_into](apa),
pragma[only_bind_into](config)) and
kind = ret.getKind() and
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
parameterFlowThroughAllowed(p, kind)
parameterFlowThroughAllowed(summaryCtx, kind) and
argApa = getApprox(argAp) and
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config))
)
}
pragma[inline]
private predicate fwdFlowInMayFlowThrough(
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
private predicate fwdFlowThrough0(
DataFlowCall call, Cc cc, FlowState state, CcCall ccc, ParamNodeOption summaryCtx,
ApOption argAp, Ap ap, ApApprox apa, RetNodeEx ret, ParamNodeEx innerSummaryCtx,
Ap innerArgAp, ApApprox innerArgApa, Configuration config
) {
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(param, apa, config)
}
// dedup before joining with `flowThroughOutOfCall`
pragma[nomagic]
private predicate fwdFlowInMayFlowThroughProj(
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
}
/**
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
* in the flow covered by `fwdFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate fwdFlowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
ApApprox argApa, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
fwdFlowRetFromArg(ret, state, ccc, innerSummaryCtx, innerArgAp, innerArgApa, ap, apa, config) and
fwdFlowIsEntered(call, cc, ccc, summaryCtx, argAp, innerSummaryCtx, innerArgAp, config)
}
pragma[nomagic]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
ApApprox apa, Configuration config
private predicate fwdFlowThrough(
DataFlowCall call, Cc cc, FlowState state, CcCall ccc, ParamNodeOption summaryCtx,
ApOption argAp, Ap ap, ApApprox apa, RetNodeEx ret, ApApprox innerArgApa, Configuration config
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
config) and
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
)
fwdFlowThrough0(call, cc, state, ccc, summaryCtx, argAp, ap, apa, ret, _, _, innerArgApa,
config)
}
/**
@@ -1571,12 +1552,14 @@ private module MkStage<StageSig PrevStage> {
*/
pragma[nomagic]
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ParameterPosition pos, Ap ap, Configuration config
DataFlowCall call, Cc cc, CcCall innerCc, ParamNodeOption summaryCtx, ApOption argAp,
ParamNodeEx p, Ap ap, Configuration config
) {
exists(ParamNodeEx param |
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
pos = param.getPosition()
exists(ApApprox apa |
fwdFlowIn(call, pragma[only_bind_into](p), _, cc, innerCc, summaryCtx, argAp, ap,
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(p, apa, config) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config))
)
}
@@ -1596,23 +1579,31 @@ private module MkStage<StageSig PrevStage> {
fwdFlowConsCand(ap1, c, ap2, config)
}
pragma[nomagic]
private predicate returnFlowsThrough0(
DataFlowCall call, FlowState state, CcCall ccc, Ap ap, ApApprox apa, RetNodeEx ret,
ParamNodeEx innerSummaryCtx, Ap innerArgAp, ApApprox innerArgApa, Configuration config
) {
fwdFlowThrough0(call, _, state, ccc, _, _, ap, apa, ret, innerSummaryCtx, innerArgAp,
innerArgApa, config)
}
pragma[nomagic]
private predicate returnFlowsThrough(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
RetNodeEx ret, ReturnPosition pos, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
Ap ap, Configuration config
) {
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
kind = ret.getKind() and
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
exists(DataFlowCall call, ApApprox apa, boolean allowsFieldFlow, ApApprox innerArgApa |
returnFlowsThrough0(call, state, ccc, ap, apa, ret, p, argAp, innerArgApa, config) and
flowThroughOutOfCall(call, ccc, ret, _, allowsFieldFlow, innerArgApa, apa, config) and
pos = ret.getReturnPosition() and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
pragma[nomagic]
private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp, Ap ap,
Configuration config
) {
exists(ApApprox argApa |
@@ -1620,7 +1611,7 @@ private module MkStage<StageSig PrevStage> {
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
pragma[only_bind_into](config)) and
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), ap,
pragma[only_bind_into](config)) and
if allowsFieldFlow = false then argAp instanceof ApNil else any()
)
@@ -1639,12 +1630,13 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate flowOutOfCallAp(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, NodeEx out, boolean allowsFieldFlow,
Ap ap, Configuration config
) {
exists(ApApprox apa |
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
fwdFlow(ret, _, _, _, _, ap, apa, config)
flowOutOfCallApa(call, ret, _, out, allowsFieldFlow, apa, config) and
fwdFlow(ret, _, _, _, _, ap, apa, config) and
pos = ret.getReturnPosition()
)
}
@@ -1739,17 +1731,17 @@ private module MkStage<StageSig PrevStage> {
)
or
// flow through a callable
exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
exists(DataFlowCall call, ParamNodeEx p, Ap innerReturnAp |
revFlowThrough(call, returnCtx, p, state, _, returnAp, ap, innerReturnAp, config) and
flowThroughIntoCall(call, node, p, _, ap, innerReturnAp, config)
)
or
// flow out of a callable
exists(ReturnKindExt kind |
revFlowOut(_, node, kind, state, _, _, ap, config) and
if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
exists(ReturnPosition pos |
revFlowOut(_, node, pos, state, _, _, ap, config) and
if returnFlowsThrough(node, pos, state, _, _, _, ap, config)
then (
returnCtx = TReturnCtxMaybeFlowThrough(kind) and
returnCtx = TReturnCtxMaybeFlowThrough(pos) and
returnAp = apSome(ap)
) else (
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
@@ -1782,47 +1774,33 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate revFlowOut(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, FlowState state, ReturnCtx returnCtx,
ApOption returnAp, Ap ap, Configuration config
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
flowOutOfCallAp(call, ret, pos, out, allowsFieldFlow, ap, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
/**
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
* in the flow covered by `revFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate revFlowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
Configuration config
) {
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
revFlowIsReturned(call, _, _, _, _, config)
}
pragma[nomagic]
private predicate revFlowParamToReturn(
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
ParamNodeEx p, FlowState state, ReturnPosition pos, Ap returnAp, Ap ap, Configuration config
) {
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind)
revFlow(pragma[only_bind_into](p), state, TReturnCtxMaybeFlowThrough(pos), apSome(returnAp),
pragma[only_bind_into](ap), pragma[only_bind_into](config)) and
parameterFlowThroughAllowed(p, pos.getKind()) and
PrevStage::parameterMayFlowThrough(p, getApprox(ap), config)
}
pragma[nomagic]
private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
Configuration config
private predicate revFlowThrough(
DataFlowCall call, ReturnCtx returnCtx, ParamNodeEx p, FlowState state, ReturnPosition pos,
ApOption returnAp, Ap ap, Ap innerReturnAp, Configuration config
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
)
revFlowParamToReturn(p, state, pos, innerReturnAp, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, pos, innerReturnAp, config)
}
/**
@@ -1832,12 +1810,12 @@ private module MkStage<StageSig PrevStage> {
*/
pragma[nomagic]
private predicate revFlowIsReturned(
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnPosition pos, Ap ap,
Configuration config
) {
exists(RetNodeEx ret, FlowState state, CcCall ccc |
revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
revFlowOut(call, ret, pos, state, returnCtx, returnAp, ap, config) and
returnFlowsThrough(ret, pos, state, ccc, _, _, ap, config) and
matchesCall(ccc, call)
)
}
@@ -1915,17 +1893,17 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
ParamNodeEx p, Ap ap, ReturnPosition pos, Ap returnAp, Configuration config
) {
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind)
revFlow(p, _, TReturnCtxMaybeFlowThrough(pos), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, pos.getKind())
}
pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(RetNodeEx ret, ReturnKindExt kind |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, _, config)
exists(ReturnPosition pos |
returnFlowsThrough(_, pos, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, pos, _, config)
)
}
@@ -1933,20 +1911,21 @@ private module MkStage<StageSig PrevStage> {
predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
) {
exists(ParamNodeEx p |
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
parameterFlowsThroughRev(p, argAp, kind, ap, config)
exists(ParamNodeEx p, ReturnPosition pos |
returnFlowsThrough(ret, pos, _, _, p, argAp, ap, config) and
parameterFlowsThroughRev(p, argAp, pos, ap, config) and
kind = pos.getKind()
)
}
pragma[nomagic]
predicate revFlowInToReturnIsReturned(
private predicate revFlowThroughArg(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
Ap ap, Configuration config
) {
exists(ReturnKindExt returnKind0, Ap returnAp0 |
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
exists(ParamNodeEx p, Ap innerReturnAp |
revFlowThrough(call, returnCtx, p, state, _, returnAp, ap, innerReturnAp, config) and
flowThroughIntoCall(call, arg, p, _, ap, innerReturnAp, config)
)
}
@@ -1954,7 +1933,7 @@ private module MkStage<StageSig PrevStage> {
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
revFlowThroughArg(call, arg, state, returnCtx, returnAp, ap, config)
)
}
@@ -1967,8 +1946,9 @@ private module MkStage<StageSig PrevStage> {
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
tuples =
count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
count(NodeEx n, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap |
fwdFlow(n, state, cc, summaryCtx, argAp, ap, config)
)
or
fwd = false and
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
@@ -2823,13 +2803,12 @@ private Configuration unbindConf(Configuration conf) {
pragma[nomagic]
private predicate nodeMayUseSummary0(
NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
Configuration config
NodeEx n, ParamNodeEx p, FlowState state, AccessPathApprox apa, Configuration config
) {
exists(AccessPathApprox apa0 |
c = n.getEnclosingCallable() and
Stage5::parameterMayFlowThrough(p, _, _) and
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParamNodeSome(p.asNode()),
TAccessPathApproxSome(apa), apa0, config)
)
}
@@ -2838,10 +2817,9 @@ pragma[nomagic]
private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) {
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
exists(ParamNodeEx p |
Stage5::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos)
nodeMayUseSummary0(n, p, state, apa, config)
)
}
@@ -3771,8 +3749,8 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap,
AccessPathApprox apa, Configuration config
) {
exists(PathNodeMid mid, RetNodeEx ret |
pathNode(mid, ret, state, cc, sc, ap, config, _) and
exists(RetNodeEx ret |
pathNode(_, ret, state, cc, sc, ap, config, _) and
kind = ret.getKind() and
apa = ap.getApprox() and
parameterFlowThroughAllowed(sc.getParamNode(), kind)
@@ -4234,17 +4212,15 @@ private module FlowExploration {
ap = TRevPartialNil() and
exists(config.explorationLimit())
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
not clearsContentEx(node, ap.getHead()) and
(
notExpectsContent(node) or
expectsContentEx(node, ap.getHead())
) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
)
revPartialPathStep(_, node, state, sc1, sc2, sc3, ap, config) and
not clearsContentEx(node, ap.getHead()) and
(
notExpectsContent(node) or
expectsContentEx(node, ap.getHead())
) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
}
pragma[nomagic]
@@ -4252,19 +4228,17 @@ private module FlowExploration {
NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
TSummaryCtx3 sc3, PartialAccessPath ap, Configuration config
) {
exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
not clearsContentEx(node, ap.getHead().getContent()) and
(
notExpectsContent(node) or
expectsContentEx(node, ap.getHead().getContent())
) and
if node.asNode() instanceof CastingNode
then compatibleTypes(node.getDataFlowType(), ap.getType())
else any()
)
partialPathStep(_, node, state, cc, sc1, sc2, sc3, ap, config) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
not clearsContentEx(node, ap.getHead().getContent()) and
(
notExpectsContent(node) or
expectsContentEx(node, ap.getHead().getContent())
) and
if node.asNode() instanceof CastingNode
then compatibleTypes(node.getDataFlowType(), ap.getType())
else any()
}
/**

View File

@@ -622,7 +622,11 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
}
private module Stage1 implements StageSig {
class Ap = Unit;
class Ap extends int {
// workaround for bad functionality-induced joins (happens when using `Unit`)
pragma[nomagic]
Ap() { this in [0 .. 1] and this < 1 }
}
private class Cc = boolean;
@@ -872,9 +876,9 @@ private module Stage1 implements StageSig {
pragma[nomagic]
private predicate revFlowOut(ReturnPosition pos, Configuration config) {
exists(DataFlowCall call, NodeEx out |
exists(NodeEx out |
revFlow(out, _, config) and
viableReturnPosOutNodeCandFwd1(call, pos, out, config)
viableReturnPosOutNodeCandFwd1(_, pos, out, config)
)
}
@@ -1327,8 +1331,8 @@ private module MkStage<StageSig PrevStage> {
*/
pragma[nomagic]
additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, ApApprox apa, Configuration config
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
ApApprox apa, Configuration config
) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
PrevStage::revFlow(node, state, apa, config) and
@@ -1337,21 +1341,21 @@ private module MkStage<StageSig PrevStage> {
pragma[inline]
additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
Configuration config
) {
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
}
pragma[nomagic]
private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, ApApprox apa, Configuration config
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
ApApprox apa, Configuration config
) {
sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and
summaryCtx = TParameterPositionNone() and
summaryCtx = TParamNodeNone() and
ap = getApNil(node) and
apa = getApprox(ap)
or
@@ -1372,7 +1376,7 @@ private module MkStage<StageSig PrevStage> {
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
summaryCtx = TParamNodeNone() and
argAp = apNone()
)
or
@@ -1380,7 +1384,7 @@ private module MkStage<StageSig PrevStage> {
fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
summaryCtx = TParamNodeNone() and
argAp = apNone() and
ap = getApNil(node) and
apa = getApprox(ap)
@@ -1390,7 +1394,7 @@ private module MkStage<StageSig PrevStage> {
fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStateStep(mid, state0, node, state, config) and
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
summaryCtx = TParamNodeNone() and
argAp = apNone() and
ap = getApNil(node) and
apa = getApprox(ap)
@@ -1414,10 +1418,10 @@ private module MkStage<StageSig PrevStage> {
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
if PrevStage::parameterMayFlowThrough(node, apa, config)
then (
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
summaryCtx = TParamNodeSome(node.asNode()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
summaryCtx = TParamNodeNone() and argAp = apNone()
)
or
// flow out of a callable
@@ -1433,16 +1437,19 @@ private module MkStage<StageSig PrevStage> {
)
or
// flow through a callable
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
exists(
DataFlowCall call, CcCall ccc, RetNodeEx ret, boolean allowsFieldFlow, ApApprox innerArgApa
|
fwdFlowThrough(call, cc, state, ccc, summaryCtx, argAp, ap, apa, ret, innerArgApa, config) and
flowThroughOutOfCall(call, ccc, ret, node, allowsFieldFlow, innerArgApa, apa, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
pragma[nomagic]
private predicate fwdFlowStore(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType, ApApprox apa1 |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
@@ -1473,8 +1480,8 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate fwdFlowRead0(
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ApNonNil ap, Configuration config
NodeEx node1, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, ApNonNil ap,
Configuration config
) {
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, _, _, config)
@@ -1483,7 +1490,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
) {
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and
@@ -1493,7 +1500,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
ParamNodeOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
) {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
@@ -1505,64 +1512,38 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate fwdFlowRetFromArg(
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
RetNodeEx ret, FlowState state, CcCall ccc, ParamNodeEx summaryCtx, Ap argAp, ApApprox argApa,
Ap ap, ApApprox apa, Configuration config
) {
exists(DataFlowCallable c, ReturnKindExt kind |
exists(ReturnKindExt kind |
fwdFlow(pragma[only_bind_into](ret), state, ccc,
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
getApprox(argAp) = argApa and
c = ret.getEnclosingCallable() and
TParamNodeSome(pragma[only_bind_into](summaryCtx.asNode())),
pragma[only_bind_into](apSome(argAp)), ap, pragma[only_bind_into](apa),
pragma[only_bind_into](config)) and
kind = ret.getKind() and
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
parameterFlowThroughAllowed(p, kind)
parameterFlowThroughAllowed(summaryCtx, kind) and
argApa = getApprox(argAp) and
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config))
)
}
pragma[inline]
private predicate fwdFlowInMayFlowThrough(
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
private predicate fwdFlowThrough0(
DataFlowCall call, Cc cc, FlowState state, CcCall ccc, ParamNodeOption summaryCtx,
ApOption argAp, Ap ap, ApApprox apa, RetNodeEx ret, ParamNodeEx innerSummaryCtx,
Ap innerArgAp, ApApprox innerArgApa, Configuration config
) {
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(param, apa, config)
}
// dedup before joining with `flowThroughOutOfCall`
pragma[nomagic]
private predicate fwdFlowInMayFlowThroughProj(
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
}
/**
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
* in the flow covered by `fwdFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate fwdFlowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
ApApprox argApa, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
fwdFlowRetFromArg(ret, state, ccc, innerSummaryCtx, innerArgAp, innerArgApa, ap, apa, config) and
fwdFlowIsEntered(call, cc, ccc, summaryCtx, argAp, innerSummaryCtx, innerArgAp, config)
}
pragma[nomagic]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
ApApprox apa, Configuration config
private predicate fwdFlowThrough(
DataFlowCall call, Cc cc, FlowState state, CcCall ccc, ParamNodeOption summaryCtx,
ApOption argAp, Ap ap, ApApprox apa, RetNodeEx ret, ApApprox innerArgApa, Configuration config
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
config) and
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
)
fwdFlowThrough0(call, cc, state, ccc, summaryCtx, argAp, ap, apa, ret, _, _, innerArgApa,
config)
}
/**
@@ -1571,12 +1552,14 @@ private module MkStage<StageSig PrevStage> {
*/
pragma[nomagic]
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ParameterPosition pos, Ap ap, Configuration config
DataFlowCall call, Cc cc, CcCall innerCc, ParamNodeOption summaryCtx, ApOption argAp,
ParamNodeEx p, Ap ap, Configuration config
) {
exists(ParamNodeEx param |
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
pos = param.getPosition()
exists(ApApprox apa |
fwdFlowIn(call, pragma[only_bind_into](p), _, cc, innerCc, summaryCtx, argAp, ap,
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(p, apa, config) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config))
)
}
@@ -1596,23 +1579,31 @@ private module MkStage<StageSig PrevStage> {
fwdFlowConsCand(ap1, c, ap2, config)
}
pragma[nomagic]
private predicate returnFlowsThrough0(
DataFlowCall call, FlowState state, CcCall ccc, Ap ap, ApApprox apa, RetNodeEx ret,
ParamNodeEx innerSummaryCtx, Ap innerArgAp, ApApprox innerArgApa, Configuration config
) {
fwdFlowThrough0(call, _, state, ccc, _, _, ap, apa, ret, innerSummaryCtx, innerArgAp,
innerArgApa, config)
}
pragma[nomagic]
private predicate returnFlowsThrough(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
RetNodeEx ret, ReturnPosition pos, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
Ap ap, Configuration config
) {
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
kind = ret.getKind() and
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
exists(DataFlowCall call, ApApprox apa, boolean allowsFieldFlow, ApApprox innerArgApa |
returnFlowsThrough0(call, state, ccc, ap, apa, ret, p, argAp, innerArgApa, config) and
flowThroughOutOfCall(call, ccc, ret, _, allowsFieldFlow, innerArgApa, apa, config) and
pos = ret.getReturnPosition() and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
pragma[nomagic]
private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp, Ap ap,
Configuration config
) {
exists(ApApprox argApa |
@@ -1620,7 +1611,7 @@ private module MkStage<StageSig PrevStage> {
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
pragma[only_bind_into](config)) and
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), ap,
pragma[only_bind_into](config)) and
if allowsFieldFlow = false then argAp instanceof ApNil else any()
)
@@ -1639,12 +1630,13 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate flowOutOfCallAp(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, NodeEx out, boolean allowsFieldFlow,
Ap ap, Configuration config
) {
exists(ApApprox apa |
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
fwdFlow(ret, _, _, _, _, ap, apa, config)
flowOutOfCallApa(call, ret, _, out, allowsFieldFlow, apa, config) and
fwdFlow(ret, _, _, _, _, ap, apa, config) and
pos = ret.getReturnPosition()
)
}
@@ -1739,17 +1731,17 @@ private module MkStage<StageSig PrevStage> {
)
or
// flow through a callable
exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
exists(DataFlowCall call, ParamNodeEx p, Ap innerReturnAp |
revFlowThrough(call, returnCtx, p, state, _, returnAp, ap, innerReturnAp, config) and
flowThroughIntoCall(call, node, p, _, ap, innerReturnAp, config)
)
or
// flow out of a callable
exists(ReturnKindExt kind |
revFlowOut(_, node, kind, state, _, _, ap, config) and
if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
exists(ReturnPosition pos |
revFlowOut(_, node, pos, state, _, _, ap, config) and
if returnFlowsThrough(node, pos, state, _, _, _, ap, config)
then (
returnCtx = TReturnCtxMaybeFlowThrough(kind) and
returnCtx = TReturnCtxMaybeFlowThrough(pos) and
returnAp = apSome(ap)
) else (
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
@@ -1782,47 +1774,33 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate revFlowOut(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, FlowState state, ReturnCtx returnCtx,
ApOption returnAp, Ap ap, Configuration config
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
flowOutOfCallAp(call, ret, pos, out, allowsFieldFlow, ap, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
/**
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
* in the flow covered by `revFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate revFlowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
Configuration config
) {
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
revFlowIsReturned(call, _, _, _, _, config)
}
pragma[nomagic]
private predicate revFlowParamToReturn(
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
ParamNodeEx p, FlowState state, ReturnPosition pos, Ap returnAp, Ap ap, Configuration config
) {
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind)
revFlow(pragma[only_bind_into](p), state, TReturnCtxMaybeFlowThrough(pos), apSome(returnAp),
pragma[only_bind_into](ap), pragma[only_bind_into](config)) and
parameterFlowThroughAllowed(p, pos.getKind()) and
PrevStage::parameterMayFlowThrough(p, getApprox(ap), config)
}
pragma[nomagic]
private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
Configuration config
private predicate revFlowThrough(
DataFlowCall call, ReturnCtx returnCtx, ParamNodeEx p, FlowState state, ReturnPosition pos,
ApOption returnAp, Ap ap, Ap innerReturnAp, Configuration config
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
)
revFlowParamToReturn(p, state, pos, innerReturnAp, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, pos, innerReturnAp, config)
}
/**
@@ -1832,12 +1810,12 @@ private module MkStage<StageSig PrevStage> {
*/
pragma[nomagic]
private predicate revFlowIsReturned(
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnPosition pos, Ap ap,
Configuration config
) {
exists(RetNodeEx ret, FlowState state, CcCall ccc |
revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
revFlowOut(call, ret, pos, state, returnCtx, returnAp, ap, config) and
returnFlowsThrough(ret, pos, state, ccc, _, _, ap, config) and
matchesCall(ccc, call)
)
}
@@ -1915,17 +1893,17 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
ParamNodeEx p, Ap ap, ReturnPosition pos, Ap returnAp, Configuration config
) {
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind)
revFlow(p, _, TReturnCtxMaybeFlowThrough(pos), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, pos.getKind())
}
pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(RetNodeEx ret, ReturnKindExt kind |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, _, config)
exists(ReturnPosition pos |
returnFlowsThrough(_, pos, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, pos, _, config)
)
}
@@ -1933,20 +1911,21 @@ private module MkStage<StageSig PrevStage> {
predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
) {
exists(ParamNodeEx p |
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
parameterFlowsThroughRev(p, argAp, kind, ap, config)
exists(ParamNodeEx p, ReturnPosition pos |
returnFlowsThrough(ret, pos, _, _, p, argAp, ap, config) and
parameterFlowsThroughRev(p, argAp, pos, ap, config) and
kind = pos.getKind()
)
}
pragma[nomagic]
predicate revFlowInToReturnIsReturned(
private predicate revFlowThroughArg(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
Ap ap, Configuration config
) {
exists(ReturnKindExt returnKind0, Ap returnAp0 |
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
exists(ParamNodeEx p, Ap innerReturnAp |
revFlowThrough(call, returnCtx, p, state, _, returnAp, ap, innerReturnAp, config) and
flowThroughIntoCall(call, arg, p, _, ap, innerReturnAp, config)
)
}
@@ -1954,7 +1933,7 @@ private module MkStage<StageSig PrevStage> {
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
revFlowThroughArg(call, arg, state, returnCtx, returnAp, ap, config)
)
}
@@ -1967,8 +1946,9 @@ private module MkStage<StageSig PrevStage> {
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
tuples =
count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
count(NodeEx n, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap |
fwdFlow(n, state, cc, summaryCtx, argAp, ap, config)
)
or
fwd = false and
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
@@ -2823,13 +2803,12 @@ private Configuration unbindConf(Configuration conf) {
pragma[nomagic]
private predicate nodeMayUseSummary0(
NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
Configuration config
NodeEx n, ParamNodeEx p, FlowState state, AccessPathApprox apa, Configuration config
) {
exists(AccessPathApprox apa0 |
c = n.getEnclosingCallable() and
Stage5::parameterMayFlowThrough(p, _, _) and
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParamNodeSome(p.asNode()),
TAccessPathApproxSome(apa), apa0, config)
)
}
@@ -2838,10 +2817,9 @@ pragma[nomagic]
private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) {
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
exists(ParamNodeEx p |
Stage5::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos)
nodeMayUseSummary0(n, p, state, apa, config)
)
}
@@ -3771,8 +3749,8 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap,
AccessPathApprox apa, Configuration config
) {
exists(PathNodeMid mid, RetNodeEx ret |
pathNode(mid, ret, state, cc, sc, ap, config, _) and
exists(RetNodeEx ret |
pathNode(_, ret, state, cc, sc, ap, config, _) and
kind = ret.getKind() and
apa = ap.getApprox() and
parameterFlowThroughAllowed(sc.getParamNode(), kind)
@@ -4234,17 +4212,15 @@ private module FlowExploration {
ap = TRevPartialNil() and
exists(config.explorationLimit())
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
not clearsContentEx(node, ap.getHead()) and
(
notExpectsContent(node) or
expectsContentEx(node, ap.getHead())
) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
)
revPartialPathStep(_, node, state, sc1, sc2, sc3, ap, config) and
not clearsContentEx(node, ap.getHead()) and
(
notExpectsContent(node) or
expectsContentEx(node, ap.getHead())
) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
}
pragma[nomagic]
@@ -4252,19 +4228,17 @@ private module FlowExploration {
NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
TSummaryCtx3 sc3, PartialAccessPath ap, Configuration config
) {
exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
not clearsContentEx(node, ap.getHead().getContent()) and
(
notExpectsContent(node) or
expectsContentEx(node, ap.getHead().getContent())
) and
if node.asNode() instanceof CastingNode
then compatibleTypes(node.getDataFlowType(), ap.getType())
else any()
)
partialPathStep(_, node, state, cc, sc1, sc2, sc3, ap, config) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
not clearsContentEx(node, ap.getHead().getContent()) and
(
notExpectsContent(node) or
expectsContentEx(node, ap.getHead().getContent())
) and
if node.asNode() instanceof CastingNode
then compatibleTypes(node.getDataFlowType(), ap.getType())
else any()
}
/**

View File

@@ -916,15 +916,15 @@ private module Cached {
TDataFlowCallSome(DataFlowCall call)
cached
newtype TParameterPositionOption =
TParameterPositionNone() or
TParameterPositionSome(ParameterPosition pos)
newtype TParamNodeOption =
TParamNodeNone() or
TParamNodeSome(ParamNode p)
cached
newtype TReturnCtx =
TReturnCtxNone() or
TReturnCtxNoFlowThrough() or
TReturnCtxMaybeFlowThrough(ReturnKindExt kind)
TReturnCtxMaybeFlowThrough(ReturnPosition pos)
cached
newtype TTypedContentApprox =
@@ -1343,15 +1343,15 @@ class DataFlowCallOption extends TDataFlowCallOption {
}
}
/** An optional `ParameterPosition`. */
class ParameterPositionOption extends TParameterPositionOption {
/** An optional `ParamNode`. */
class ParamNodeOption extends TParamNodeOption {
string toString() {
this = TParameterPositionNone() and
this = TParamNodeNone() and
result = "(none)"
or
exists(ParameterPosition pos |
this = TParameterPositionSome(pos) and
result = pos.toString()
exists(ParamNode p |
this = TParamNodeSome(p) and
result = p.toString()
)
}
}
@@ -1363,7 +1363,7 @@ class ParameterPositionOption extends TParameterPositionOption {
*
* - `TReturnCtxNone()`: no return flow.
* - `TReturnCtxNoFlowThrough()`: return flow, but flow through is not possible.
* - `TReturnCtxMaybeFlowThrough(ReturnKindExt kind)`: return flow, of kind `kind`, and
* - `TReturnCtxMaybeFlowThrough(ReturnPosition pos)`: return flow, of kind `pos`, and
* flow through may be possible.
*/
class ReturnCtx extends TReturnCtx {
@@ -1374,9 +1374,9 @@ class ReturnCtx extends TReturnCtx {
this = TReturnCtxNoFlowThrough() and
result = "(no flow through)"
or
exists(ReturnKindExt kind |
this = TReturnCtxMaybeFlowThrough(kind) and
result = kind.toString()
exists(ReturnPosition pos |
this = TReturnCtxMaybeFlowThrough(pos) and
result = pos.toString()
)
}
}

View File

@@ -45,6 +45,16 @@ module Consistency {
) {
none()
}
/** Holds if `(c, pos, p)` should be excluded from the consistency test `uniqueParameterNodeAtPosition`. */
predicate uniqueParameterNodeAtPositionExclude(DataFlowCallable c, ParameterPosition pos, Node p) {
none()
}
/** Holds if `(c, pos, p)` should be excluded from the consistency test `uniqueParameterNodePosition`. */
predicate uniqueParameterNodePositionExclude(DataFlowCallable c, ParameterPosition pos, Node p) {
none()
}
}
private class RelevantNode extends Node {
@@ -101,9 +111,7 @@ module Consistency {
exists(int c |
c =
strictcount(Node n |
not exists(string filepath, int startline, int startcolumn, int endline, int endcolumn |
n.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
) and
not n.hasLocationInfo(_, _, _, _, _) and
not any(ConsistencyConfiguration conf).missingLocationExclude(n)
) and
msg = "Nodes without location: " + c
@@ -248,6 +256,7 @@ module Consistency {
query predicate uniqueParameterNodeAtPosition(
DataFlowCallable c, ParameterPosition pos, Node p, string msg
) {
not any(ConsistencyConfiguration conf).uniqueParameterNodeAtPositionExclude(c, pos, p) and
isParameterNode(p, c, pos) and
not exists(unique(Node p0 | isParameterNode(p0, c, pos))) and
msg = "Parameters with overlapping positions."
@@ -256,6 +265,7 @@ module Consistency {
query predicate uniqueParameterNodePosition(
DataFlowCallable c, ParameterPosition pos, Node p, string msg
) {
not any(ConsistencyConfiguration conf).uniqueParameterNodePositionExclude(c, pos, p) and
isParameterNode(p, c, pos) and
not exists(unique(ParameterPosition pos0 | isParameterNode(p, c, pos0))) and
msg = "Parameter node with multiple positions."

View File

@@ -218,7 +218,7 @@ private predicate allocation(Instruction array, Length length, int delta) {
length.(VNLength).getInstruction().getConvertedResultExpression() = lengthExpr
)
or
not exists(int d | deconstructMallocSizeExpr(alloc.getSizeExpr(), _, d)) and
not deconstructMallocSizeExpr(alloc.getSizeExpr(), _, _) and
length.(VNLength).getInstruction().getConvertedResultExpression() = alloc.getSizeExpr() and
delta = 0
)

View File

@@ -543,9 +543,7 @@ private predicate boundedPhiCand(
PhiInstruction phi, boolean upper, Bound b, int delta, boolean fromBackEdge, int origdelta,
Reason reason
) {
exists(PhiInputOperand op |
boundedPhiInp(phi, op, b, delta, upper, fromBackEdge, origdelta, reason)
)
boundedPhiInp(phi, _, b, delta, upper, fromBackEdge, origdelta, reason)
}
/**

View File

@@ -0,0 +1,29 @@
private import RangeAnalysisStage
module FloatDelta implements DeltaSig {
class Delta = float;
bindingset[d]
bindingset[result]
float toFloat(Delta d) { result = d }
bindingset[d]
bindingset[result]
int toInt(Delta d) { result = d }
bindingset[n]
bindingset[result]
Delta fromInt(int n) { result = n }
bindingset[f]
Delta fromFloat(float f) {
result =
min(float diff, float res |
diff = (res - f) and res = f.ceil()
or
diff = (f - res) and res = f.floor()
|
res order by diff
)
}
}

View File

@@ -14,321 +14,328 @@ private import ModulusAnalysisSpecific::Private
private import experimental.semmle.code.cpp.semantic.Semantic
private import ConstantAnalysis
private import RangeUtils
private import RangeAnalysisStage
/**
* Holds if `e + delta` equals `v` at `pos`.
*/
private predicate valueFlowStepSsa(SemSsaVariable v, SemSsaReadPosition pos, SemExpr e, int delta) {
semSsaUpdateStep(v, e, delta) and pos.hasReadOfVar(v)
or
exists(SemGuard guard, boolean testIsTrue |
pos.hasReadOfVar(v) and
guard = semEqFlowCond(v, e, delta, true, testIsTrue) and
semGuardDirectlyControlsSsaRead(guard, pos, testIsTrue)
)
}
/**
* Holds if `add` is the addition of `larg` and `rarg`, neither of which are
* `ConstantIntegerExpr`s.
*/
private predicate nonConstAddition(SemExpr add, SemExpr larg, SemExpr rarg) {
exists(SemAddExpr a | a = add |
larg = a.getLeftOperand() and
rarg = a.getRightOperand()
) and
not larg instanceof SemConstantIntegerExpr and
not rarg instanceof SemConstantIntegerExpr
}
/**
* Holds if `sub` is the subtraction of `larg` and `rarg`, where `rarg` is not
* a `ConstantIntegerExpr`.
*/
private predicate nonConstSubtraction(SemExpr sub, SemExpr larg, SemExpr rarg) {
exists(SemSubExpr s | s = sub |
larg = s.getLeftOperand() and
rarg = s.getRightOperand()
) and
not rarg instanceof SemConstantIntegerExpr
}
/** Gets an expression that is the remainder modulo `mod` of `arg`. */
private SemExpr modExpr(SemExpr arg, int mod) {
exists(SemRemExpr rem |
result = rem and
arg = rem.getLeftOperand() and
rem.getRightOperand().(SemConstantIntegerExpr).getIntValue() = mod and
mod >= 2
)
or
exists(SemConstantIntegerExpr c |
mod = 2.pow([1 .. 30]) and
c.getIntValue() = mod - 1 and
result.(SemBitAndExpr).hasOperands(arg, c)
)
}
/**
* Gets a guard that tests whether `v` is congruent with `val` modulo `mod` on
* its `testIsTrue` branch.
*/
private SemGuard moduloCheck(SemSsaVariable v, int val, int mod, boolean testIsTrue) {
exists(SemExpr rem, SemConstantIntegerExpr c, int r, boolean polarity |
result.isEquality(rem, c, polarity) and
c.getIntValue() = r and
rem = modExpr(v.getAUse(), mod) and
(
testIsTrue = polarity and val = r
or
testIsTrue = polarity.booleanNot() and
mod = 2 and
val = 1 - r and
(r = 0 or r = 1)
)
)
}
/**
* Holds if a guard ensures that `v` at `pos` is congruent with `val` modulo `mod`.
*/
private predicate moduloGuardedRead(SemSsaVariable v, SemSsaReadPosition pos, int val, int mod) {
exists(SemGuard guard, boolean testIsTrue |
pos.hasReadOfVar(v) and
guard = moduloCheck(v, val, mod, testIsTrue) and
semGuardControlsSsaRead(guard, pos, testIsTrue)
)
}
/** Holds if `factor` is a power of 2 that divides `mask`. */
bindingset[mask]
private predicate andmaskFactor(int mask, int factor) {
mask % factor = 0 and
factor = 2.pow([1 .. 30])
}
/** Holds if `e` is evenly divisible by `factor`. */
private predicate evenlyDivisibleExpr(SemExpr e, int factor) {
exists(SemConstantIntegerExpr c, int k | k = c.getIntValue() |
e.(SemMulExpr).getAnOperand() = c and factor = k.abs() and factor >= 2
or
e.(SemShiftLeftExpr).getRightOperand() = c and factor = 2.pow(k) and k > 0
or
e.(SemBitAndExpr).getAnOperand() = c and factor = max(int f | andmaskFactor(k, f))
)
}
/**
* Holds if `rix` is the number of input edges to `phi`.
*/
private predicate maxPhiInputRank(SemSsaPhiNode phi, int rix) {
rix = max(int r | rankedPhiInput(phi, _, _, r))
}
/**
* Gets the remainder of `val` modulo `mod`.
*
* For `mod = 0` the result equals `val` and for `mod > 1` the result is within
* the range `[0 .. mod-1]`.
*/
bindingset[val, mod]
private int remainder(int val, int mod) {
mod = 0 and result = val
or
mod > 1 and result = ((val % mod) + mod) % mod
}
/**
* Holds if `inp` is an input to `phi` and equals `phi` modulo `mod` along `edge`.
*/
private predicate phiSelfModulus(
SemSsaPhiNode phi, SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge, int mod
) {
exists(SemSsaBound phibound, int v, int m |
edge.phiInput(phi, inp) and
phibound.getAVariable() = phi and
ssaModulus(inp, edge, phibound, v, m) and
mod = m.gcd(v) and
mod != 1
)
}
/**
* Holds if `b + val` modulo `mod` is a candidate congruence class for `phi`.
*/
private predicate phiModulusInit(SemSsaPhiNode phi, SemBound b, int val, int mod) {
exists(SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge |
edge.phiInput(phi, inp) and
ssaModulus(inp, edge, b, val, mod)
)
}
/**
* Holds if all inputs to `phi` numbered `1` to `rix` are equal to `b + val` modulo `mod`.
*/
pragma[nomagic]
private predicate phiModulusRankStep(SemSsaPhiNode phi, SemBound b, int val, int mod, int rix) {
/*
* base case. If any phi input is equal to `b + val` modulo `mod`, that's a potential congruence
* class for the phi node.
module ModulusAnalysis<DeltaSig D, BoundSig<D> Bounds, UtilSig<D> U> {
/**
* Holds if `e + delta` equals `v` at `pos`.
*/
private predicate valueFlowStepSsa(SemSsaVariable v, SemSsaReadPosition pos, SemExpr e, int delta) {
U::semSsaUpdateStep(v, e, D::fromInt(delta)) and pos.hasReadOfVar(v)
or
exists(SemGuard guard, boolean testIsTrue |
pos.hasReadOfVar(v) and
guard = U::semEqFlowCond(v, e, D::fromInt(delta), true, testIsTrue) and
semGuardDirectlyControlsSsaRead(guard, pos, testIsTrue)
)
}
rix = 0 and
phiModulusInit(phi, b, val, mod)
or
exists(SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge, int v1, int m1 |
mod != 1 and
val = remainder(v1, mod)
|
/**
* Holds if `add` is the addition of `larg` and `rarg`, neither of which are
* `ConstantIntegerExpr`s.
*/
private predicate nonConstAddition(SemExpr add, SemExpr larg, SemExpr rarg) {
exists(SemAddExpr a | a = add |
larg = a.getLeftOperand() and
rarg = a.getRightOperand()
) and
not larg instanceof SemConstantIntegerExpr and
not rarg instanceof SemConstantIntegerExpr
}
/**
* Holds if `sub` is the subtraction of `larg` and `rarg`, where `rarg` is not
* a `ConstantIntegerExpr`.
*/
private predicate nonConstSubtraction(SemExpr sub, SemExpr larg, SemExpr rarg) {
exists(SemSubExpr s | s = sub |
larg = s.getLeftOperand() and
rarg = s.getRightOperand()
) and
not rarg instanceof SemConstantIntegerExpr
}
/** Gets an expression that is the remainder modulo `mod` of `arg`. */
private SemExpr modExpr(SemExpr arg, int mod) {
exists(SemRemExpr rem |
result = rem and
arg = rem.getLeftOperand() and
rem.getRightOperand().(SemConstantIntegerExpr).getIntValue() = mod and
mod >= 2
)
or
exists(SemConstantIntegerExpr c |
mod = 2.pow([1 .. 30]) and
c.getIntValue() = mod - 1 and
result.(SemBitAndExpr).hasOperands(arg, c)
)
}
/**
* Gets a guard that tests whether `v` is congruent with `val` modulo `mod` on
* its `testIsTrue` branch.
*/
private SemGuard moduloCheck(SemSsaVariable v, int val, int mod, boolean testIsTrue) {
exists(SemExpr rem, SemConstantIntegerExpr c, int r, boolean polarity |
result.isEquality(rem, c, polarity) and
c.getIntValue() = r and
rem = modExpr(v.getAUse(), mod) and
(
testIsTrue = polarity and val = r
or
testIsTrue = polarity.booleanNot() and
mod = 2 and
val = 1 - r and
(r = 0 or r = 1)
)
)
}
/**
* Holds if a guard ensures that `v` at `pos` is congruent with `val` modulo `mod`.
*/
private predicate moduloGuardedRead(SemSsaVariable v, SemSsaReadPosition pos, int val, int mod) {
exists(SemGuard guard, boolean testIsTrue |
pos.hasReadOfVar(v) and
guard = moduloCheck(v, val, mod, testIsTrue) and
semGuardControlsSsaRead(guard, pos, testIsTrue)
)
}
/** Holds if `factor` is a power of 2 that divides `mask`. */
bindingset[mask]
private predicate andmaskFactor(int mask, int factor) {
mask % factor = 0 and
factor = 2.pow([1 .. 30])
}
/** Holds if `e` is evenly divisible by `factor`. */
private predicate evenlyDivisibleExpr(SemExpr e, int factor) {
exists(SemConstantIntegerExpr c, int k | k = c.getIntValue() |
e.(SemMulExpr).getAnOperand() = c and factor = k.abs() and factor >= 2
or
e.(SemShiftLeftExpr).getRightOperand() = c and factor = 2.pow(k) and k > 0
or
e.(SemBitAndExpr).getAnOperand() = c and factor = max(int f | andmaskFactor(k, f))
)
}
/**
* Holds if `rix` is the number of input edges to `phi`.
*/
private predicate maxPhiInputRank(SemSsaPhiNode phi, int rix) {
rix = max(int r | rankedPhiInput(phi, _, _, r))
}
/**
* Gets the remainder of `val` modulo `mod`.
*
* For `mod = 0` the result equals `val` and for `mod > 1` the result is within
* the range `[0 .. mod-1]`.
*/
bindingset[val, mod]
private int remainder(int val, int mod) {
mod = 0 and result = val
or
mod > 1 and result = ((val % mod) + mod) % mod
}
/**
* Holds if `inp` is an input to `phi` and equals `phi` modulo `mod` along `edge`.
*/
private predicate phiSelfModulus(
SemSsaPhiNode phi, SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge, int mod
) {
exists(Bounds::SemSsaBound phibound, int v, int m |
edge.phiInput(phi, inp) and
phibound.getAVariable() = phi and
ssaModulus(inp, edge, phibound, v, m) and
mod = m.gcd(v) and
mod != 1
)
}
/**
* Holds if `b + val` modulo `mod` is a candidate congruence class for `phi`.
*/
private predicate phiModulusInit(SemSsaPhiNode phi, Bounds::SemBound b, int val, int mod) {
exists(SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge |
edge.phiInput(phi, inp) and
ssaModulus(inp, edge, b, val, mod)
)
}
/**
* Holds if all inputs to `phi` numbered `1` to `rix` are equal to `b + val` modulo `mod`.
*/
pragma[nomagic]
private predicate phiModulusRankStep(
SemSsaPhiNode phi, Bounds::SemBound b, int val, int mod, int rix
) {
/*
* Recursive case. If `inp` = `b + v2` mod `m2`, we combine that with the preceding potential
* congruence class `b + v1` mod `m1`. The result will be the congruence class of `v1` modulo
* the greatest common denominator of `m1`, `m2`, and `v1 - v2`.
* base case. If any phi input is equal to `b + val` modulo `mod`, that's a potential congruence
* class for the phi node.
*/
exists(int v2, int m2 |
rankedPhiInput(pragma[only_bind_out](phi), inp, edge, rix) and
phiModulusRankStep(phi, b, v1, m1, rix - 1) and
ssaModulus(inp, edge, b, v2, m2) and
mod = m1.gcd(m2).gcd(v1 - v2)
rix = 0 and
phiModulusInit(phi, b, val, mod)
or
exists(SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge, int v1, int m1 |
mod != 1 and
val = remainder(v1, mod)
|
/*
* Recursive case. If `inp` = `b + v2` mod `m2`, we combine that with the preceding potential
* congruence class `b + v1` mod `m1`. The result will be the congruence class of `v1` modulo
* the greatest common denominator of `m1`, `m2`, and `v1 - v2`.
*/
exists(int v2, int m2 |
rankedPhiInput(pragma[only_bind_out](phi), inp, edge, rix) and
phiModulusRankStep(phi, b, v1, m1, rix - 1) and
ssaModulus(inp, edge, b, v2, m2) and
mod = m1.gcd(m2).gcd(v1 - v2)
)
or
/*
* Recursive case. If `inp` = `phi` mod `m2`, we combine that with the preceding potential
* congruence class `b + v1` mod `m1`. The result will be a congruence class modulo the greatest
* common denominator of `m1` and `m2`.
*/
exists(int m2 |
rankedPhiInput(phi, inp, edge, rix) and
phiModulusRankStep(phi, b, v1, m1, rix - 1) and
phiSelfModulus(phi, inp, edge, m2) and
mod = m1.gcd(m2)
)
)
or
/*
* Recursive case. If `inp` = `phi` mod `m2`, we combine that with the preceding potential
* congruence class `b + v1` mod `m1`. The result will be a congruence class modulo the greatest
* common denominator of `m1` and `m2`.
*/
}
exists(int m2 |
rankedPhiInput(phi, inp, edge, rix) and
phiModulusRankStep(phi, b, v1, m1, rix - 1) and
phiSelfModulus(phi, inp, edge, m2) and
mod = m1.gcd(m2)
/**
* Holds if `phi` is equal to `b + val` modulo `mod`.
*/
private predicate phiModulus(SemSsaPhiNode phi, Bounds::SemBound b, int val, int mod) {
exists(int r |
maxPhiInputRank(phi, r) and
phiModulusRankStep(phi, b, val, mod, r)
)
)
}
}
/**
* Holds if `phi` is equal to `b + val` modulo `mod`.
*/
private predicate phiModulus(SemSsaPhiNode phi, SemBound b, int val, int mod) {
exists(int r |
maxPhiInputRank(phi, r) and
phiModulusRankStep(phi, b, val, mod, r)
)
}
/**
* Holds if `v` at `pos` is equal to `b + val` modulo `mod`.
*/
private predicate ssaModulus(SemSsaVariable v, SemSsaReadPosition pos, SemBound b, int val, int mod) {
phiModulus(v, b, val, mod) and pos.hasReadOfVar(v)
or
b.(SemSsaBound).getAVariable() = v and pos.hasReadOfVar(v) and val = 0 and mod = 0
or
exists(SemExpr e, int val0, int delta |
semExprModulus(e, b, val0, mod) and
valueFlowStepSsa(v, pos, e, delta) and
val = remainder(val0 + delta, mod)
)
or
moduloGuardedRead(v, pos, val, mod) and b instanceof SemZeroBound
}
/**
* Holds if `e` is equal to `b + val` modulo `mod`.
*
* There are two cases for the modulus:
* - `mod = 0`: The equality `e = b + val` is an ordinary equality.
* - `mod > 1`: `val` lies within the range `[0 .. mod-1]`.
*/
cached
predicate semExprModulus(SemExpr e, SemBound b, int val, int mod) {
not ignoreExprModulus(e) and
(
e = b.getExpr(val) and mod = 0
/**
* Holds if `v` at `pos` is equal to `b + val` modulo `mod`.
*/
private predicate ssaModulus(
SemSsaVariable v, SemSsaReadPosition pos, Bounds::SemBound b, int val, int mod
) {
phiModulus(v, b, val, mod) and pos.hasReadOfVar(v)
or
evenlyDivisibleExpr(e, mod) and
val = 0 and
b instanceof SemZeroBound
b.(Bounds::SemSsaBound).getAVariable() = v and pos.hasReadOfVar(v) and val = 0 and mod = 0
or
exists(SemSsaVariable v, SemSsaReadPositionBlock bb |
ssaModulus(v, bb, b, val, mod) and
e = v.getAUse() and
bb.getAnExpr() = e
)
or
exists(SemExpr mid, int val0, int delta |
semExprModulus(mid, b, val0, mod) and
semValueFlowStep(e, mid, delta) and
exists(SemExpr e, int val0, int delta |
semExprModulus(e, b, val0, mod) and
valueFlowStepSsa(v, pos, e, delta) and
val = remainder(val0 + delta, mod)
)
or
exists(SemConditionalExpr cond, int v1, int v2, int m1, int m2 |
cond = e and
condExprBranchModulus(cond, true, b, v1, m1) and
condExprBranchModulus(cond, false, b, v2, m2) and
mod = m1.gcd(m2).gcd(v1 - v2) and
mod != 1 and
val = remainder(v1, mod)
)
or
exists(SemBound b1, SemBound b2, int v1, int v2, int m1, int m2 |
addModulus(e, true, b1, v1, m1) and
addModulus(e, false, b2, v2, m2) and
mod = m1.gcd(m2) and
mod != 1 and
val = remainder(v1 + v2, mod)
|
b = b1 and b2 instanceof SemZeroBound
moduloGuardedRead(v, pos, val, mod) and b instanceof Bounds::SemZeroBound
}
/**
* Holds if `e` is equal to `b + val` modulo `mod`.
*
* There are two cases for the modulus:
* - `mod = 0`: The equality `e = b + val` is an ordinary equality.
* - `mod > 1`: `val` lies within the range `[0 .. mod-1]`.
*/
cached
predicate semExprModulus(SemExpr e, Bounds::SemBound b, int val, int mod) {
not ignoreExprModulus(e) and
(
e = b.getExpr(D::fromInt(val)) and mod = 0
or
b = b2 and b1 instanceof SemZeroBound
evenlyDivisibleExpr(e, mod) and
val = 0 and
b instanceof Bounds::SemZeroBound
or
exists(SemSsaVariable v, SemSsaReadPositionBlock bb |
ssaModulus(v, bb, b, val, mod) and
e = v.getAUse() and
bb.getAnExpr() = e
)
or
exists(SemExpr mid, int val0, int delta |
semExprModulus(mid, b, val0, mod) and
U::semValueFlowStep(e, mid, D::fromInt(delta)) and
val = remainder(val0 + delta, mod)
)
or
exists(SemConditionalExpr cond, int v1, int v2, int m1, int m2 |
cond = e and
condExprBranchModulus(cond, true, b, v1, m1) and
condExprBranchModulus(cond, false, b, v2, m2) and
mod = m1.gcd(m2).gcd(v1 - v2) and
mod != 1 and
val = remainder(v1, mod)
)
or
exists(Bounds::SemBound b1, Bounds::SemBound b2, int v1, int v2, int m1, int m2 |
addModulus(e, true, b1, v1, m1) and
addModulus(e, false, b2, v2, m2) and
mod = m1.gcd(m2) and
mod != 1 and
val = remainder(v1 + v2, mod)
|
b = b1 and b2 instanceof Bounds::SemZeroBound
or
b = b2 and b1 instanceof Bounds::SemZeroBound
)
or
exists(int v1, int v2, int m1, int m2 |
subModulus(e, true, b, v1, m1) and
subModulus(e, false, any(Bounds::SemZeroBound zb), v2, m2) and
mod = m1.gcd(m2) and
mod != 1 and
val = remainder(v1 - v2, mod)
)
)
or
exists(int v1, int v2, int m1, int m2 |
subModulus(e, true, b, v1, m1) and
subModulus(e, false, any(SemZeroBound zb), v2, m2) and
mod = m1.gcd(m2) and
mod != 1 and
val = remainder(v1 - v2, mod)
}
private predicate condExprBranchModulus(
SemConditionalExpr cond, boolean branch, Bounds::SemBound b, int val, int mod
) {
semExprModulus(cond.getBranchExpr(branch), b, val, mod)
}
private predicate addModulus(SemExpr add, boolean isLeft, Bounds::SemBound b, int val, int mod) {
exists(SemExpr larg, SemExpr rarg | nonConstAddition(add, larg, rarg) |
semExprModulus(larg, b, val, mod) and isLeft = true
or
semExprModulus(rarg, b, val, mod) and isLeft = false
)
)
}
}
private predicate condExprBranchModulus(
SemConditionalExpr cond, boolean branch, SemBound b, int val, int mod
) {
semExprModulus(cond.getBranchExpr(branch), b, val, mod)
}
private predicate addModulus(SemExpr add, boolean isLeft, SemBound b, int val, int mod) {
exists(SemExpr larg, SemExpr rarg | nonConstAddition(add, larg, rarg) |
semExprModulus(larg, b, val, mod) and isLeft = true
or
semExprModulus(rarg, b, val, mod) and isLeft = false
)
}
private predicate subModulus(SemExpr sub, boolean isLeft, SemBound b, int val, int mod) {
exists(SemExpr larg, SemExpr rarg | nonConstSubtraction(sub, larg, rarg) |
semExprModulus(larg, b, val, mod) and isLeft = true
or
semExprModulus(rarg, b, val, mod) and isLeft = false
)
}
/**
* Holds if `inp` is an input to `phi` along `edge` and this input has index `r`
* in an arbitrary 1-based numbering of the input edges to `phi`.
*/
private predicate rankedPhiInput(
SemSsaPhiNode phi, SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge, int r
) {
edge.phiInput(phi, inp) and
edge =
rank[r](SemSsaReadPositionPhiInputEdge e |
e.phiInput(phi, _)
|
e order by e.getOrigBlock().getUniqueId()
private predicate subModulus(SemExpr sub, boolean isLeft, Bounds::SemBound b, int val, int mod) {
exists(SemExpr larg, SemExpr rarg | nonConstSubtraction(sub, larg, rarg) |
semExprModulus(larg, b, val, mod) and isLeft = true
or
semExprModulus(rarg, b, val, mod) and isLeft = false
)
}
/**
* Holds if `inp` is an input to `phi` along `edge` and this input has index `r`
* in an arbitrary 1-based numbering of the input edges to `phi`.
*/
private predicate rankedPhiInput(
SemSsaPhiNode phi, SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge, int r
) {
edge.phiInput(phi, inp) and
edge =
rank[r](SemSsaReadPositionPhiInputEdge e |
e.phiInput(phi, _)
|
e order by e.getOrigBlock().getUniqueId()
)
}
}

View File

@@ -1,832 +1,24 @@
/**
* Provides classes and predicates for range analysis.
*
* An inferred bound can either be a specific integer, the abstract value of an
* SSA variable, or the abstract value of an interesting expression. The latter
* category includes array lengths that are not SSA variables.
*
* If an inferred bound relies directly on a condition, then this condition is
* reported as the reason for the bound.
*/
/*
* This library tackles range analysis as a flow problem. Consider e.g.:
* ```
* len = arr.length;
* if (x < len) { ... y = x-1; ... y ... }
* ```
* In this case we would like to infer `y <= arr.length - 2`, and this is
* accomplished by tracking the bound through a sequence of steps:
* ```
* arr.length --> len = .. --> x < len --> x-1 --> y = .. --> y
* ```
*
* In its simplest form the step relation `E1 --> E2` relates two expressions
* such that `E1 <= B` implies `E2 <= B` for any `B` (with a second separate
* step relation handling lower bounds). Examples of such steps include
* assignments `E2 = E1` and conditions `x <= E1` where `E2` is a use of `x`
* guarded by the condition.
*
* In order to handle subtractions and additions with constants, and strict
* comparisons, the step relation is augmented with an integer delta. With this
* generalization `E1 --(delta)--> E2` relates two expressions and an integer
* such that `E1 <= B` implies `E2 <= B + delta` for any `B`. This corresponds
* to the predicate `boundFlowStep`.
*
* The complete range analysis is then implemented as the transitive closure of
* the step relation summing the deltas along the way. If `E1` transitively
* steps to `E2`, `delta` is the sum of deltas along the path, and `B` is an
* interesting bound equal to the value of `E1` then `E2 <= B + delta`. This
* corresponds to the predicate `bounded`.
*
* Phi nodes need a little bit of extra handling. Consider `x0 = phi(x1, x2)`.
* There are essentially two cases:
* - If `x1 <= B + d1` and `x2 <= B + d2` then `x0 <= B + max(d1,d2)`.
* - If `x1 <= B + d1` and `x2 <= x0 + d2` with `d2 <= 0` then `x0 <= B + d1`.
* The first case is for whenever a bound can be proven without taking looping
* into account. The second case is relevant when `x2` comes from a back-edge
* where we can prove that the variable has been non-increasing through the
* loop-iteration as this means that any upper bound that holds prior to the
* loop also holds for the variable during the loop.
* This generalizes to a phi node with `n` inputs, so if
* `x0 = phi(x1, ..., xn)` and `xi <= B + delta` for one of the inputs, then we
* also have `x0 <= B + delta` if we can prove either:
* - `xj <= B + d` with `d <= delta` or
* - `xj <= x0 + d` with `d <= 0`
* for each input `xj`.
*
* As all inferred bounds can be related directly to a path in the source code
* the only source of non-termination is if successive redundant (and thereby
* increasingly worse) bounds are calculated along a loop in the source code.
* We prevent this by weakening the bound to a small finite set of bounds when
* a path follows a second back-edge (we postpone weakening till the second
* back-edge as a precise bound might require traversing a loop once).
*/
private import RangeAnalysisSpecific as Specific
private import RangeAnalysisStage
private import RangeAnalysisSpecific
private import experimental.semmle.code.cpp.semantic.analysis.FloatDelta
private import RangeUtils
private import SignAnalysisCommon
private import ModulusAnalysis
private import experimental.semmle.code.cpp.semantic.Semantic
private import ConstantAnalysis
private import experimental.semmle.code.cpp.semantic.SemanticBound as SemanticBound
cached
private module RangeAnalysisCache {
cached
module RangeAnalysisPublic {
/**
* Holds if `b + delta` is a valid bound for `e`.
* - `upper = true` : `e <= b + delta`
* - `upper = false` : `e >= b + delta`
*
* The reason for the bound is given by `reason` and may be either a condition
* or `NoReason` if the bound was proven directly without the use of a bounding
* condition.
*/
cached
predicate semBounded(SemExpr e, SemBound b, int delta, boolean upper, SemReason reason) {
bounded(e, b, delta, upper, _, _, reason) and
bestBound(e, b, delta, upper)
}
module Bounds implements BoundSig<FloatDelta> {
class SemBound instanceof SemanticBound::SemBound {
string toString() { result = super.toString() }
SemExpr getExpr(float delta) { result = super.getExpr(delta) }
}
/**
* Holds if `guard = boundFlowCond(_, _, _, _, _) or guard = eqFlowCond(_, _, _, _, _)`.
*/
cached
predicate possibleReason(SemGuard guard) {
guard = boundFlowCond(_, _, _, _, _) or guard = semEqFlowCond(_, _, _, _, _)
class SemZeroBound extends SemBound instanceof SemanticBound::SemZeroBound { }
class SemSsaBound extends SemBound instanceof SemanticBound::SemSsaBound {
SemSsaVariable getAVariable() { result = this.(SemanticBound::SemSsaBound).getAVariable() }
}
}
private import RangeAnalysisCache
import RangeAnalysisPublic
private module CppRangeAnalysis =
RangeStage<FloatDelta, Bounds, CppLangImpl, RangeUtil<FloatDelta, CppLangImpl>>;
/**
* Holds if `b + delta` is a valid bound for `e` and this is the best such delta.
* - `upper = true` : `e <= b + delta`
* - `upper = false` : `e >= b + delta`
*/
private predicate bestBound(SemExpr e, SemBound b, int delta, boolean upper) {
delta = min(int d | bounded(e, b, d, upper, _, _, _)) and upper = true
or
delta = max(int d | bounded(e, b, d, upper, _, _, _)) and upper = false
}
/**
* Holds if `comp` corresponds to:
* - `upper = true` : `v <= e + delta` or `v < e + delta`
* - `upper = false` : `v >= e + delta` or `v > e + delta`
*/
private predicate boundCondition(
SemRelationalExpr comp, SemSsaVariable v, SemExpr e, int delta, boolean upper
) {
comp.getLesserOperand() = semSsaRead(v, delta) and e = comp.getGreaterOperand() and upper = true
or
comp.getGreaterOperand() = semSsaRead(v, delta) and e = comp.getLesserOperand() and upper = false
or
exists(SemSubExpr sub, SemConstantIntegerExpr c, int d |
// (v - d) - e < c
comp.getLesserOperand() = sub and
comp.getGreaterOperand() = c and
sub.getLeftOperand() = semSsaRead(v, d) and
sub.getRightOperand() = e and
upper = true and
delta = d + c.getIntValue()
or
// (v - d) - e > c
comp.getGreaterOperand() = sub and
comp.getLesserOperand() = c and
sub.getLeftOperand() = semSsaRead(v, d) and
sub.getRightOperand() = e and
upper = false and
delta = d + c.getIntValue()
or
// e - (v - d) < c
comp.getLesserOperand() = sub and
comp.getGreaterOperand() = c and
sub.getLeftOperand() = e and
sub.getRightOperand() = semSsaRead(v, d) and
upper = false and
delta = d - c.getIntValue()
or
// e - (v - d) > c
comp.getGreaterOperand() = sub and
comp.getLesserOperand() = c and
sub.getLeftOperand() = e and
sub.getRightOperand() = semSsaRead(v, d) and
upper = true and
delta = d - c.getIntValue()
)
}
/**
* Holds if `comp` is a comparison between `x` and `y` for which `y - x` has a
* fixed value modulo some `mod > 1`, such that the comparison can be
* strengthened by `strengthen` when evaluating to `testIsTrue`.
*/
private predicate modulusComparison(SemRelationalExpr comp, boolean testIsTrue, int strengthen) {
exists(
SemBound b, int v1, int v2, int mod1, int mod2, int mod, boolean resultIsStrict, int d, int k
|
// If `x <= y` and `x =(mod) b + v1` and `y =(mod) b + v2` then
// `0 <= y - x =(mod) v2 - v1`. By choosing `k =(mod) v2 - v1` with
// `0 <= k < mod` we get `k <= y - x`. If the resulting comparison is
// strict then the strengthening amount is instead `k - 1` modulo `mod`:
// `x < y` means `0 <= y - x - 1 =(mod) k - 1` so `k - 1 <= y - x - 1` and
// thus `k - 1 < y - x` with `0 <= k - 1 < mod`.
semExprModulus(comp.getLesserOperand(), b, v1, mod1) and
semExprModulus(comp.getGreaterOperand(), b, v2, mod2) and
mod = mod1.gcd(mod2) and
mod != 1 and
(testIsTrue = true or testIsTrue = false) and
(
if comp.isStrict()
then resultIsStrict = testIsTrue
else resultIsStrict = testIsTrue.booleanNot()
) and
(
resultIsStrict = true and d = 1
or
resultIsStrict = false and d = 0
) and
(
testIsTrue = true and k = v2 - v1
or
testIsTrue = false and k = v1 - v2
) and
strengthen = (((k - d) % mod) + mod) % mod
)
}
/**
* Gets a condition that tests whether `v` is bounded by `e + delta`.
*
* If the condition evaluates to `testIsTrue`:
* - `upper = true` : `v <= e + delta`
* - `upper = false` : `v >= e + delta`
*/
private SemGuard boundFlowCond(
SemSsaVariable v, SemExpr e, int delta, boolean upper, boolean testIsTrue
) {
exists(
SemRelationalExpr comp, int d1, int d2, int d3, int strengthen, boolean compIsUpper,
boolean resultIsStrict
|
comp = result.asExpr() and
boundCondition(comp, v, e, d1, compIsUpper) and
(testIsTrue = true or testIsTrue = false) and
upper = compIsUpper.booleanXor(testIsTrue.booleanNot()) and
(
if comp.isStrict()
then resultIsStrict = testIsTrue
else resultIsStrict = testIsTrue.booleanNot()
) and
(
if
getTrackedTypeForSsaVariable(v) instanceof SemIntegerType or
getTrackedTypeForSsaVariable(v) instanceof SemAddressType
then
upper = true and strengthen = -1
or
upper = false and strengthen = 1
else strengthen = 0
) and
(
exists(int k | modulusComparison(comp, testIsTrue, k) and d2 = strengthen * k)
or
not modulusComparison(comp, testIsTrue, _) and d2 = 0
) and
// A strict inequality `x < y` can be strengthened to `x <= y - 1`.
(
resultIsStrict = true and d3 = strengthen
or
resultIsStrict = false and d3 = 0
) and
delta = d1 + d2 + d3
)
or
exists(boolean testIsTrue0 |
semImplies_v2(result, testIsTrue, boundFlowCond(v, e, delta, upper, testIsTrue0), testIsTrue0)
)
or
result = semEqFlowCond(v, e, delta, true, testIsTrue) and
(upper = true or upper = false)
or
// guard that tests whether `v2` is bounded by `e + delta + d1 - d2` and
// exists a guard `guardEq` such that `v = v2 - d1 + d2`.
exists(SemSsaVariable v2, SemGuard guardEq, boolean eqIsTrue, int d1, int d2 |
guardEq = semEqFlowCond(v, semSsaRead(v2, d1), d2, true, eqIsTrue) and
result = boundFlowCond(v2, e, delta + d1 - d2, upper, testIsTrue) and
// guardEq needs to control guard
guardEq.directlyControls(result.getBasicBlock(), eqIsTrue)
)
}
private newtype TSemReason =
TSemNoReason() or
TSemCondReason(SemGuard guard) { possibleReason(guard) }
/**
* A reason for an inferred bound. This can either be `CondReason` if the bound
* is due to a specific condition, or `NoReason` if the bound is inferred
* without going through a bounding condition.
*/
abstract class SemReason extends TSemReason {
/** Gets a textual representation of this reason. */
abstract string toString();
}
/**
* A reason for an inferred bound that indicates that the bound is inferred
* without going through a bounding condition.
*/
class SemNoReason extends SemReason, TSemNoReason {
override string toString() { result = "NoReason" }
}
/** A reason for an inferred bound pointing to a condition. */
class SemCondReason extends SemReason, TSemCondReason {
/** Gets the condition that is the reason for the bound. */
SemGuard getCond() { this = TSemCondReason(result) }
override string toString() { result = getCond().toString() }
}
/**
* Holds if `e + delta` is a valid bound for `v` at `pos`.
* - `upper = true` : `v <= e + delta`
* - `upper = false` : `v >= e + delta`
*/
private predicate boundFlowStepSsa(
SemSsaVariable v, SemSsaReadPosition pos, SemExpr e, int delta, boolean upper, SemReason reason
) {
semSsaUpdateStep(v, e, delta) and
pos.hasReadOfVar(v) and
(upper = true or upper = false) and
reason = TSemNoReason()
or
exists(SemGuard guard, boolean testIsTrue |
pos.hasReadOfVar(v) and
guard = boundFlowCond(v, e, delta, upper, testIsTrue) and
semGuardDirectlyControlsSsaRead(guard, pos, testIsTrue) and
reason = TSemCondReason(guard)
)
}
/** Holds if `v != e + delta` at `pos` and `v` is of integral type. */
private predicate unequalFlowStepIntegralSsa(
SemSsaVariable v, SemSsaReadPosition pos, SemExpr e, int delta, SemReason reason
) {
getTrackedTypeForSsaVariable(v) instanceof SemIntegerType and
exists(SemGuard guard, boolean testIsTrue |
pos.hasReadOfVar(v) and
guard = semEqFlowCond(v, e, delta, false, testIsTrue) and
semGuardDirectlyControlsSsaRead(guard, pos, testIsTrue) and
reason = TSemCondReason(guard)
)
}
/**
* An expression that does conversion, boxing, or unboxing
*/
private class ConvertOrBoxExpr extends SemUnaryExpr {
ConvertOrBoxExpr() {
this instanceof SemConvertExpr
or
this instanceof SemBoxExpr
or
this instanceof SemUnboxExpr
}
}
/**
* A cast that can be ignored for the purpose of range analysis.
*/
private class SafeCastExpr extends ConvertOrBoxExpr {
SafeCastExpr() {
conversionCannotOverflow(getTrackedType(pragma[only_bind_into](getOperand())),
getTrackedType(this))
}
}
/**
* Holds if `typ` is a small integral type with the given lower and upper bounds.
*/
private predicate typeBound(SemIntegerType typ, int lowerbound, int upperbound) {
exists(int bitSize | bitSize = typ.getByteSize() * 8 |
bitSize < 32 and
(
if typ.isSigned()
then (
upperbound = 1.bitShiftLeft(bitSize - 1) - 1 and
lowerbound = -upperbound - 1
) else (
lowerbound = 0 and
upperbound = 1.bitShiftLeft(bitSize) - 1
)
)
)
}
/**
* A cast to a small integral type that may overflow or underflow.
*/
private class NarrowingCastExpr extends ConvertOrBoxExpr {
NarrowingCastExpr() {
not this instanceof SafeCastExpr and
typeBound(getTrackedType(this), _, _)
}
/** Gets the lower bound of the resulting type. */
int getLowerBound() { typeBound(getTrackedType(this), result, _) }
/** Gets the upper bound of the resulting type. */
int getUpperBound() { typeBound(getTrackedType(this), _, result) }
}
/** Holds if `e >= 1` as determined by sign analysis. */
private predicate strictlyPositiveIntegralExpr(SemExpr e) {
semStrictlyPositive(e) and getTrackedType(e) instanceof SemIntegerType
}
/** Holds if `e <= -1` as determined by sign analysis. */
private predicate strictlyNegativeIntegralExpr(SemExpr e) {
semStrictlyNegative(e) and getTrackedType(e) instanceof SemIntegerType
}
/**
* Holds if `e1 + delta` is a valid bound for `e2`.
* - `upper = true` : `e2 <= e1 + delta`
* - `upper = false` : `e2 >= e1 + delta`
*/
private predicate boundFlowStep(SemExpr e2, SemExpr e1, int delta, boolean upper) {
semValueFlowStep(e2, e1, delta) and
(upper = true or upper = false)
or
e2.(SafeCastExpr).getOperand() = e1 and
delta = 0 and
(upper = true or upper = false)
or
exists(SemExpr x | e2.(SemAddExpr).hasOperands(e1, x) |
// `x instanceof ConstantIntegerExpr` is covered by valueFlowStep
not x instanceof SemConstantIntegerExpr and
not e1 instanceof SemConstantIntegerExpr and
if strictlyPositiveIntegralExpr(x)
then upper = false and delta = 1
else
if semPositive(x)
then upper = false and delta = 0
else
if strictlyNegativeIntegralExpr(x)
then upper = true and delta = -1
else
if semNegative(x)
then upper = true and delta = 0
else none()
)
or
exists(SemExpr x, SemSubExpr sub |
e2 = sub and
sub.getLeftOperand() = e1 and
sub.getRightOperand() = x
|
// `x instanceof ConstantIntegerExpr` is covered by valueFlowStep
not x instanceof SemConstantIntegerExpr and
if strictlyPositiveIntegralExpr(x)
then upper = true and delta = -1
else
if semPositive(x)
then upper = true and delta = 0
else
if strictlyNegativeIntegralExpr(x)
then upper = false and delta = 1
else
if semNegative(x)
then upper = false and delta = 0
else none()
)
or
e2.(SemRemExpr).getRightOperand() = e1 and
semPositive(e1) and
delta = -1 and
upper = true
or
e2.(SemRemExpr).getLeftOperand() = e1 and semPositive(e1) and delta = 0 and upper = true
or
e2.(SemBitAndExpr).getAnOperand() = e1 and
semPositive(e1) and
delta = 0 and
upper = true
or
e2.(SemBitOrExpr).getAnOperand() = e1 and
semPositive(e2) and
delta = 0 and
upper = false
or
Specific::hasBound(e2, e1, delta, upper)
}
/** Holds if `e2 = e1 * factor` and `factor > 0`. */
private predicate boundFlowStepMul(SemExpr e2, SemExpr e1, int factor) {
exists(SemConstantIntegerExpr c, int k | k = c.getIntValue() and k > 0 |
e2.(SemMulExpr).hasOperands(e1, c) and factor = k
or
exists(SemShiftLeftExpr e |
e = e2 and e.getLeftOperand() = e1 and e.getRightOperand() = c and factor = 2.pow(k)
)
)
}
/**
* Holds if `e2 = e1 / factor` and `factor > 0`.
*
* This conflates division, right shift, and unsigned right shift and is
* therefore only valid for non-negative numbers.
*/
private predicate boundFlowStepDiv(SemExpr e2, SemExpr e1, int factor) {
exists(SemConstantIntegerExpr c, int k | k = c.getIntValue() and k > 0 |
exists(SemDivExpr e |
e = e2 and e.getLeftOperand() = e1 and e.getRightOperand() = c and factor = k
)
or
exists(SemShiftRightExpr e |
e = e2 and e.getLeftOperand() = e1 and e.getRightOperand() = c and factor = 2.pow(k)
)
or
exists(SemShiftRightUnsignedExpr e |
e = e2 and e.getLeftOperand() = e1 and e.getRightOperand() = c and factor = 2.pow(k)
)
)
}
/**
* Holds if `b + delta` is a valid bound for `v` at `pos`.
* - `upper = true` : `v <= b + delta`
* - `upper = false` : `v >= b + delta`
*/
private predicate boundedSsa(
SemSsaVariable v, SemSsaReadPosition pos, SemBound b, int delta, boolean upper,
boolean fromBackEdge, int origdelta, SemReason reason
) {
exists(SemExpr mid, int d1, int d2, SemReason r1, SemReason r2 |
boundFlowStepSsa(v, pos, mid, d1, upper, r1) and
bounded(mid, b, d2, upper, fromBackEdge, origdelta, r2) and
// upper = true: v <= mid + d1 <= b + d1 + d2 = b + delta
// upper = false: v >= mid + d1 >= b + d1 + d2 = b + delta
delta = d1 + d2 and
(if r1 instanceof SemNoReason then reason = r2 else reason = r1)
)
or
exists(int d, SemReason r1, SemReason r2 |
boundedSsa(v, pos, b, d, upper, fromBackEdge, origdelta, r2) or
boundedPhi(v, b, d, upper, fromBackEdge, origdelta, r2)
|
unequalIntegralSsa(v, pos, b, d, r1) and
(
upper = true and delta = d - 1
or
upper = false and delta = d + 1
) and
(
reason = r1
or
reason = r2 and not r2 instanceof SemNoReason
)
)
}
/**
* Holds if `v != b + delta` at `pos` and `v` is of integral type.
*/
private predicate unequalIntegralSsa(
SemSsaVariable v, SemSsaReadPosition pos, SemBound b, int delta, SemReason reason
) {
exists(SemExpr e, int d1, int d2 |
unequalFlowStepIntegralSsa(v, pos, e, d1, reason) and
boundedUpper(e, b, d1) and
boundedLower(e, b, d2) and
delta = d2 + d1
)
}
/**
* Holds if `b + delta` is an upper bound for `e`.
*
* This predicate only exists to prevent a bad standard order in `unequalIntegralSsa`.
*/
pragma[nomagic]
private predicate boundedUpper(SemExpr e, SemBound b, int delta) {
bounded(e, b, delta, true, _, _, _)
}
/**
* Holds if `b + delta` is a lower bound for `e`.
*
* This predicate only exists to prevent a bad standard order in `unequalIntegralSsa`.
*/
pragma[nomagic]
private predicate boundedLower(SemExpr e, SemBound b, int delta) {
bounded(e, b, delta, false, _, _, _)
}
/** Weakens a delta to lie in the range `[-1..1]`. */
bindingset[delta, upper]
private int weakenDelta(boolean upper, int delta) {
delta in [-1 .. 1] and result = delta
or
upper = true and result = -1 and delta < -1
or
upper = false and result = 1 and delta > 1
}
/**
* Holds if `b + delta` is a valid bound for `inp` when used as an input to
* `phi` along `edge`.
* - `upper = true` : `inp <= b + delta`
* - `upper = false` : `inp >= b + delta`
*/
private predicate boundedPhiInp(
SemSsaPhiNode phi, SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge, SemBound b, int delta,
boolean upper, boolean fromBackEdge, int origdelta, SemReason reason
) {
edge.phiInput(phi, inp) and
exists(int d, boolean fromBackEdge0 |
boundedSsa(inp, edge, b, d, upper, fromBackEdge0, origdelta, reason)
or
boundedPhi(inp, b, d, upper, fromBackEdge0, origdelta, reason)
or
b.(SemSsaBound).getAVariable() = inp and
d = 0 and
(upper = true or upper = false) and
fromBackEdge0 = false and
origdelta = 0 and
reason = TSemNoReason()
|
if semBackEdge(phi, inp, edge)
then
fromBackEdge = true and
(
fromBackEdge0 = true and delta = weakenDelta(upper, d - origdelta) + origdelta
or
fromBackEdge0 = false and delta = d
)
else (
delta = d and fromBackEdge = fromBackEdge0
)
)
}
/**
* Holds if `b + delta` is a valid bound for `inp` when used as an input to
* `phi` along `edge`.
* - `upper = true` : `inp <= b + delta`
* - `upper = false` : `inp >= b + delta`
*
* Equivalent to `boundedPhiInp(phi, inp, edge, b, delta, upper, _, _, _)`.
*/
pragma[noinline]
private predicate boundedPhiInp1(
SemSsaPhiNode phi, SemBound b, boolean upper, SemSsaVariable inp,
SemSsaReadPositionPhiInputEdge edge, int delta
) {
boundedPhiInp(phi, inp, edge, b, delta, upper, _, _, _)
}
/**
* Holds if `phi` is a valid bound for `inp` when used as an input to `phi`
* along `edge`.
* - `upper = true` : `inp <= phi`
* - `upper = false` : `inp >= phi`
*/
private predicate selfBoundedPhiInp(
SemSsaPhiNode phi, SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge, boolean upper
) {
exists(int d, SemSsaBound phibound |
phibound.getAVariable() = phi and
boundedPhiInp(phi, inp, edge, phibound, d, upper, _, _, _) and
(
upper = true and d <= 0
or
upper = false and d >= 0
)
)
}
/**
* Holds if `b + delta` is a valid bound for some input, `inp`, to `phi`, and
* thus a candidate bound for `phi`.
* - `upper = true` : `inp <= b + delta`
* - `upper = false` : `inp >= b + delta`
*/
pragma[noinline]
private predicate boundedPhiCand(
SemSsaPhiNode phi, boolean upper, SemBound b, int delta, boolean fromBackEdge, int origdelta,
SemReason reason
) {
exists(SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge |
boundedPhiInp(phi, inp, edge, b, delta, upper, fromBackEdge, origdelta, reason)
)
}
/**
* Holds if the candidate bound `b + delta` for `phi` is valid for the phi input
* `inp` along `edge`.
*/
private predicate boundedPhiCandValidForEdge(
SemSsaPhiNode phi, SemBound b, int delta, boolean upper, boolean fromBackEdge, int origdelta,
SemReason reason, SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge
) {
boundedPhiCand(phi, upper, b, delta, fromBackEdge, origdelta, reason) and
(
exists(int d | boundedPhiInp1(phi, b, upper, inp, edge, d) | upper = true and d <= delta)
or
exists(int d | boundedPhiInp1(phi, b, upper, inp, edge, d) | upper = false and d >= delta)
or
selfBoundedPhiInp(phi, inp, edge, upper)
)
}
/**
* Holds if `b + delta` is a valid bound for `phi`.
* - `upper = true` : `phi <= b + delta`
* - `upper = false` : `phi >= b + delta`
*/
private predicate boundedPhi(
SemSsaPhiNode phi, SemBound b, int delta, boolean upper, boolean fromBackEdge, int origdelta,
SemReason reason
) {
forex(SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge | edge.phiInput(phi, inp) |
boundedPhiCandValidForEdge(phi, b, delta, upper, fromBackEdge, origdelta, reason, inp, edge)
)
}
/**
* Holds if `e` has an upper (for `upper = true`) or lower
* (for `upper = false`) bound of `b`.
*/
private predicate baseBound(SemExpr e, int b, boolean upper) {
Specific::hasConstantBound(e, b, upper)
or
upper = false and
b = 0 and
semPositive(e.(SemBitAndExpr).getAnOperand()) and
// REVIEW: We let the language opt out here to preserve original results.
not Specific::ignoreZeroLowerBound(e)
}
/**
* Holds if the value being cast has an upper (for `upper = true`) or lower
* (for `upper = false`) bound within the bounds of the resulting type.
* For `upper = true` this means that the cast will not overflow and for
* `upper = false` this means that the cast will not underflow.
*/
private predicate safeNarrowingCast(NarrowingCastExpr cast, boolean upper) {
exists(int bound | bounded(cast.getOperand(), any(SemZeroBound zb), bound, upper, _, _, _) |
upper = true and bound <= cast.getUpperBound()
or
upper = false and bound >= cast.getLowerBound()
)
}
pragma[noinline]
private predicate boundedCastExpr(
NarrowingCastExpr cast, SemBound b, int delta, boolean upper, boolean fromBackEdge, int origdelta,
SemReason reason
) {
bounded(cast.getOperand(), b, delta, upper, fromBackEdge, origdelta, reason)
}
/**
* Holds if `b + delta` is a valid bound for `e`.
* - `upper = true` : `e <= b + delta`
* - `upper = false` : `e >= b + delta`
*/
private predicate bounded(
SemExpr e, SemBound b, int delta, boolean upper, boolean fromBackEdge, int origdelta,
SemReason reason
) {
not Specific::ignoreExprBound(e) and
(
e = b.getExpr(delta) and
(upper = true or upper = false) and
fromBackEdge = false and
origdelta = delta and
reason = TSemNoReason()
or
baseBound(e, delta, upper) and
b instanceof SemZeroBound and
fromBackEdge = false and
origdelta = delta and
reason = TSemNoReason()
or
exists(SemSsaVariable v, SemSsaReadPositionBlock bb |
boundedSsa(v, bb, b, delta, upper, fromBackEdge, origdelta, reason) and
e = v.getAUse() and
bb.getBlock() = e.getBasicBlock()
)
or
exists(SemExpr mid, int d1, int d2 |
boundFlowStep(e, mid, d1, upper) and
// Constants have easy, base-case bounds, so let's not infer any recursive bounds.
not e instanceof SemConstantIntegerExpr and
bounded(mid, b, d2, upper, fromBackEdge, origdelta, reason) and
// upper = true: e <= mid + d1 <= b + d1 + d2 = b + delta
// upper = false: e >= mid + d1 >= b + d1 + d2 = b + delta
delta = d1 + d2
)
or
exists(SemSsaPhiNode phi |
boundedPhi(phi, b, delta, upper, fromBackEdge, origdelta, reason) and
e = phi.getAUse()
)
or
exists(SemExpr mid, int factor, int d |
boundFlowStepMul(e, mid, factor) and
not e instanceof SemConstantIntegerExpr and
bounded(mid, b, d, upper, fromBackEdge, origdelta, reason) and
b instanceof SemZeroBound and
delta = d * factor
)
or
exists(SemExpr mid, int factor, int d |
boundFlowStepDiv(e, mid, factor) and
not e instanceof SemConstantIntegerExpr and
bounded(mid, b, d, upper, fromBackEdge, origdelta, reason) and
b instanceof SemZeroBound and
d >= 0 and
delta = d / factor
)
or
exists(NarrowingCastExpr cast |
cast = e and
safeNarrowingCast(cast, upper.booleanNot()) and
boundedCastExpr(cast, b, delta, upper, fromBackEdge, origdelta, reason)
)
or
exists(
SemConditionalExpr cond, int d1, int d2, boolean fbe1, boolean fbe2, int od1, int od2,
SemReason r1, SemReason r2
|
cond = e and
boundedConditionalExpr(cond, b, upper, true, d1, fbe1, od1, r1) and
boundedConditionalExpr(cond, b, upper, false, d2, fbe2, od2, r2) and
(
delta = d1 and fromBackEdge = fbe1 and origdelta = od1 and reason = r1
or
delta = d2 and fromBackEdge = fbe2 and origdelta = od2 and reason = r2
)
|
upper = true and delta = d1.maximum(d2)
or
upper = false and delta = d1.minimum(d2)
)
)
}
private predicate boundedConditionalExpr(
SemConditionalExpr cond, SemBound b, boolean upper, boolean branch, int delta,
boolean fromBackEdge, int origdelta, SemReason reason
) {
bounded(cond.getBranchExpr(branch), b, delta, upper, fromBackEdge, origdelta, reason)
}
import CppRangeAnalysis

View File

@@ -3,86 +3,90 @@
*/
private import experimental.semmle.code.cpp.semantic.Semantic
private import RangeAnalysisStage
private import experimental.semmle.code.cpp.semantic.analysis.FloatDelta
/**
* Holds if the specified expression should be excluded from the result of `ssaRead()`.
*
* This predicate is to keep the results identical to the original Java implementation. It should be
* removed once we have the new implementation matching the old results exactly.
*/
predicate ignoreSsaReadCopy(SemExpr e) { none() }
module CppLangImpl implements LangSig<FloatDelta> {
/**
* Holds if the specified expression should be excluded from the result of `ssaRead()`.
*
* This predicate is to keep the results identical to the original Java implementation. It should be
* removed once we have the new implementation matching the old results exactly.
*/
predicate ignoreSsaReadCopy(SemExpr e) { none() }
/**
* Ignore the bound on this expression.
*
* This predicate is to keep the results identical to the original Java implementation. It should be
* removed once we have the new implementation matching the old results exactly.
*/
predicate ignoreExprBound(SemExpr e) { none() }
/**
* Ignore the bound on this expression.
*
* This predicate is to keep the results identical to the original Java implementation. It should be
* removed once we have the new implementation matching the old results exactly.
*/
predicate ignoreExprBound(SemExpr e) { none() }
/**
* Ignore any inferred zero lower bound on this expression.
*
* This predicate is to keep the results identical to the original Java implementation. It should be
* removed once we have the new implementation matching the old results exactly.
*/
predicate ignoreZeroLowerBound(SemExpr e) { none() }
/**
* Ignore any inferred zero lower bound on this expression.
*
* This predicate is to keep the results identical to the original Java implementation. It should be
* removed once we have the new implementation matching the old results exactly.
*/
predicate ignoreZeroLowerBound(SemExpr e) { none() }
/**
* Holds if the specified expression should be excluded from the result of `ssaRead()`.
*
* This predicate is to keep the results identical to the original Java implementation. It should be
* removed once we have the new implementation matching the old results exactly.
*/
predicate ignoreSsaReadArithmeticExpr(SemExpr e) { none() }
/**
* Holds if the specified expression should be excluded from the result of `ssaRead()`.
*
* This predicate is to keep the results identical to the original Java implementation. It should be
* removed once we have the new implementation matching the old results exactly.
*/
predicate ignoreSsaReadArithmeticExpr(SemExpr e) { none() }
/**
* Holds if the specified variable should be excluded from the result of `ssaRead()`.
*
* This predicate is to keep the results identical to the original Java implementation. It should be
* removed once we have the new implementation matching the old results exactly.
*/
predicate ignoreSsaReadAssignment(SemSsaVariable v) { none() }
/**
* Holds if the specified variable should be excluded from the result of `ssaRead()`.
*
* This predicate is to keep the results identical to the original Java implementation. It should be
* removed once we have the new implementation matching the old results exactly.
*/
predicate ignoreSsaReadAssignment(SemSsaVariable v) { none() }
/**
* Adds additional results to `ssaRead()` that are specific to Java.
*
* This predicate handles propagation of offsets for post-increment and post-decrement expressions
* in exactly the same way as the old Java implementation. Once the new implementation matches the
* old one, we should remove this predicate and propagate deltas for all similar patterns, whether
* or not they come from a post-increment/decrement expression.
*/
SemExpr specificSsaRead(SemSsaVariable v, int delta) { none() }
/**
* Adds additional results to `ssaRead()` that are specific to Java.
*
* This predicate handles propagation of offsets for post-increment and post-decrement expressions
* in exactly the same way as the old Java implementation. Once the new implementation matches the
* old one, we should remove this predicate and propagate deltas for all similar patterns, whether
* or not they come from a post-increment/decrement expression.
*/
SemExpr specificSsaRead(SemSsaVariable v, float delta) { none() }
/**
* Holds if `e >= bound` (if `upper = false`) or `e <= bound` (if `upper = true`).
*/
predicate hasConstantBound(SemExpr e, int bound, boolean upper) { none() }
/**
* Holds if `e >= bound` (if `upper = false`) or `e <= bound` (if `upper = true`).
*/
predicate hasConstantBound(SemExpr e, float bound, boolean upper) { none() }
/**
* Holds if `e >= bound + delta` (if `upper = false`) or `e <= bound + delta` (if `upper = true`).
*/
predicate hasBound(SemExpr e, SemExpr bound, int delta, boolean upper) { none() }
/**
* Holds if `e >= bound + delta` (if `upper = false`) or `e <= bound + delta` (if `upper = true`).
*/
predicate hasBound(SemExpr e, SemExpr bound, float delta, boolean upper) { none() }
/**
* Holds if the value of `dest` is known to be `src + delta`.
*/
predicate additionalValueFlowStep(SemExpr dest, SemExpr src, int delta) { none() }
/**
* Holds if the value of `dest` is known to be `src + delta`.
*/
predicate additionalValueFlowStep(SemExpr dest, SemExpr src, float delta) { none() }
/**
* Gets the type that range analysis should use to track the result of the specified expression,
* if a type other than the original type of the expression is to be used.
*
* This predicate is commonly used in languages that support immutable "boxed" types that are
* actually references but whose values can be tracked as the type contained in the box.
*/
SemType getAlternateType(SemExpr e) { none() }
/**
* Gets the type that range analysis should use to track the result of the specified expression,
* if a type other than the original type of the expression is to be used.
*
* This predicate is commonly used in languages that support immutable "boxed" types that are
* actually references but whose values can be tracked as the type contained in the box.
*/
SemType getAlternateType(SemExpr e) { none() }
/**
* Gets the type that range analysis should use to track the result of the specified source
* variable, if a type other than the original type of the expression is to be used.
*
* This predicate is commonly used in languages that support immutable "boxed" types that are
* actually references but whose values can be tracked as the type contained in the box.
*/
SemType getAlternateTypeForSsaVariable(SemSsaVariable var) { none() }
/**
* Gets the type that range analysis should use to track the result of the specified source
* variable, if a type other than the original type of the expression is to be used.
*
* This predicate is commonly used in languages that support immutable "boxed" types that are
* actually references but whose values can be tracked as the type contained in the box.
*/
SemType getAlternateTypeForSsaVariable(SemSsaVariable var) { none() }
}

File diff suppressed because it is too large Load Diff

View File

@@ -3,133 +3,138 @@
*/
private import experimental.semmle.code.cpp.semantic.Semantic
private import RangeAnalysisSpecific as Specific
private import RangeAnalysisSpecific
private import RangeAnalysisStage as Range
private import ConstantAnalysis
/**
* Gets an expression that equals `v - d`.
*/
SemExpr semSsaRead(SemSsaVariable v, int delta) {
// There are various language-specific extension points that can be removed once we no longer
// expect to match the original Java implementation's results exactly.
result = v.getAUse() and delta = 0
or
exists(int d1, SemConstantIntegerExpr c |
result.(SemAddExpr).hasOperands(semSsaRead(v, d1), c) and
delta = d1 - c.getIntValue() and
not Specific::ignoreSsaReadArithmeticExpr(result)
)
or
exists(SemSubExpr sub, int d1, SemConstantIntegerExpr c |
result = sub and
sub.getLeftOperand() = semSsaRead(v, d1) and
sub.getRightOperand() = c and
delta = d1 + c.getIntValue() and
not Specific::ignoreSsaReadArithmeticExpr(result)
)
or
result = v.(SemSsaExplicitUpdate).getSourceExpr() and
delta = 0 and
not Specific::ignoreSsaReadAssignment(v)
or
result = Specific::specificSsaRead(v, delta)
or
result.(SemCopyValueExpr).getOperand() = semSsaRead(v, delta) and
not Specific::ignoreSsaReadCopy(result)
or
result.(SemStoreExpr).getOperand() = semSsaRead(v, delta)
}
/**
* Gets a condition that tests whether `v` equals `e + delta`.
*
* If the condition evaluates to `testIsTrue`:
* - `isEq = true` : `v == e + delta`
* - `isEq = false` : `v != e + delta`
*/
SemGuard semEqFlowCond(SemSsaVariable v, SemExpr e, int delta, boolean isEq, boolean testIsTrue) {
exists(boolean eqpolarity |
result.isEquality(semSsaRead(v, delta), e, eqpolarity) and
(testIsTrue = true or testIsTrue = false) and
eqpolarity.booleanXor(testIsTrue).booleanNot() = isEq
)
or
exists(boolean testIsTrue0 |
semImplies_v2(result, testIsTrue, semEqFlowCond(v, e, delta, isEq, testIsTrue0), testIsTrue0)
)
}
/**
* Holds if `v` is an `SsaExplicitUpdate` that equals `e + delta`.
*/
predicate semSsaUpdateStep(SemSsaExplicitUpdate v, SemExpr e, int delta) {
exists(SemExpr defExpr | defExpr = v.getSourceExpr() |
defExpr.(SemCopyValueExpr).getOperand() = e and delta = 0
module RangeUtil<Range::DeltaSig D, Range::LangSig<D> Lang> implements Range::UtilSig<D> {
/**
* Gets an expression that equals `v - d`.
*/
SemExpr semSsaRead(SemSsaVariable v, D::Delta delta) {
// There are various language-specific extension points that can be removed once we no longer
// expect to match the original Java implementation's results exactly.
result = v.getAUse() and delta = D::fromInt(0)
or
defExpr.(SemStoreExpr).getOperand() = e and delta = 0
exists(D::Delta d1, SemConstantIntegerExpr c |
result.(SemAddExpr).hasOperands(semSsaRead(v, d1), c) and
delta = D::fromFloat(D::toFloat(d1) - c.getIntValue()) and
not Lang::ignoreSsaReadArithmeticExpr(result)
)
or
defExpr.(SemAddOneExpr).getOperand() = e and delta = 1
exists(SemSubExpr sub, D::Delta d1, SemConstantIntegerExpr c |
result = sub and
sub.getLeftOperand() = semSsaRead(v, d1) and
sub.getRightOperand() = c and
delta = D::fromFloat(D::toFloat(d1) + c.getIntValue()) and
not Lang::ignoreSsaReadArithmeticExpr(result)
)
or
defExpr.(SemSubOneExpr).getOperand() = e and delta = -1
result = v.(SemSsaExplicitUpdate).getSourceExpr() and
delta = D::fromFloat(0) and
not Lang::ignoreSsaReadAssignment(v)
or
e = defExpr and
not (
defExpr instanceof SemCopyValueExpr or
defExpr instanceof SemStoreExpr or
defExpr instanceof SemAddOneExpr or
defExpr instanceof SemSubOneExpr
) and
delta = 0
)
}
result = Lang::specificSsaRead(v, delta)
or
result.(SemCopyValueExpr).getOperand() = semSsaRead(v, delta) and
not Lang::ignoreSsaReadCopy(result)
or
result.(SemStoreExpr).getOperand() = semSsaRead(v, delta)
}
/**
* Holds if `e1 + delta` equals `e2`.
*/
predicate semValueFlowStep(SemExpr e2, SemExpr e1, int delta) {
e2.(SemCopyValueExpr).getOperand() = e1 and delta = 0
or
e2.(SemStoreExpr).getOperand() = e1 and delta = 0
or
e2.(SemAddOneExpr).getOperand() = e1 and delta = 1
or
e2.(SemSubOneExpr).getOperand() = e1 and delta = -1
or
Specific::additionalValueFlowStep(e2, e1, delta)
or
exists(SemExpr x | e2.(SemAddExpr).hasOperands(e1, x) |
x.(SemConstantIntegerExpr).getIntValue() = delta
)
or
exists(SemExpr x, SemSubExpr sub |
e2 = sub and
sub.getLeftOperand() = e1 and
sub.getRightOperand() = x
|
x.(SemConstantIntegerExpr).getIntValue() = -delta
)
}
/**
* Gets a condition that tests whether `v` equals `e + delta`.
*
* If the condition evaluates to `testIsTrue`:
* - `isEq = true` : `v == e + delta`
* - `isEq = false` : `v != e + delta`
*/
SemGuard semEqFlowCond(
SemSsaVariable v, SemExpr e, D::Delta delta, boolean isEq, boolean testIsTrue
) {
exists(boolean eqpolarity |
result.isEquality(semSsaRead(v, delta), e, eqpolarity) and
(testIsTrue = true or testIsTrue = false) and
eqpolarity.booleanXor(testIsTrue).booleanNot() = isEq
)
or
exists(boolean testIsTrue0 |
semImplies_v2(result, testIsTrue, semEqFlowCond(v, e, delta, isEq, testIsTrue0), testIsTrue0)
)
}
/**
* Gets the type used to track the specified expression's range information.
*
* Usually, this just `e.getSemType()`, but the language can override this to track immutable boxed
* primitive types as the underlying primitive type.
*/
SemType getTrackedType(SemExpr e) {
result = Specific::getAlternateType(e)
or
not exists(Specific::getAlternateType(e)) and result = e.getSemType()
}
/**
* Holds if `v` is an `SsaExplicitUpdate` that equals `e + delta`.
*/
predicate semSsaUpdateStep(SemSsaExplicitUpdate v, SemExpr e, D::Delta delta) {
exists(SemExpr defExpr | defExpr = v.getSourceExpr() |
defExpr.(SemCopyValueExpr).getOperand() = e and delta = D::fromFloat(0)
or
defExpr.(SemStoreExpr).getOperand() = e and delta = D::fromFloat(0)
or
defExpr.(SemAddOneExpr).getOperand() = e and delta = D::fromFloat(1)
or
defExpr.(SemSubOneExpr).getOperand() = e and delta = D::fromFloat(-1)
or
e = defExpr and
not (
defExpr instanceof SemCopyValueExpr or
defExpr instanceof SemStoreExpr or
defExpr instanceof SemAddOneExpr or
defExpr instanceof SemSubOneExpr
) and
delta = D::fromFloat(0)
)
}
/**
* Gets the type used to track the specified source variable's range information.
*
* Usually, this just `e.getType()`, but the language can override this to track immutable boxed
* primitive types as the underlying primitive type.
*/
SemType getTrackedTypeForSsaVariable(SemSsaVariable var) {
result = Specific::getAlternateTypeForSsaVariable(var)
or
not exists(Specific::getAlternateTypeForSsaVariable(var)) and result = var.getType()
/**
* Holds if `e1 + delta` equals `e2`.
*/
predicate semValueFlowStep(SemExpr e2, SemExpr e1, D::Delta delta) {
e2.(SemCopyValueExpr).getOperand() = e1 and delta = D::fromFloat(0)
or
e2.(SemStoreExpr).getOperand() = e1 and delta = D::fromFloat(0)
or
e2.(SemAddOneExpr).getOperand() = e1 and delta = D::fromFloat(1)
or
e2.(SemSubOneExpr).getOperand() = e1 and delta = D::fromFloat(-1)
or
Lang::additionalValueFlowStep(e2, e1, delta)
or
exists(SemExpr x | e2.(SemAddExpr).hasOperands(e1, x) |
D::fromInt(x.(SemConstantIntegerExpr).getIntValue()) = delta
)
or
exists(SemExpr x, SemSubExpr sub |
e2 = sub and
sub.getLeftOperand() = e1 and
sub.getRightOperand() = x
|
D::fromInt(-x.(SemConstantIntegerExpr).getIntValue()) = delta
)
}
/**
* Gets the type used to track the specified expression's range information.
*
* Usually, this just `e.getSemType()`, but the language can override this to track immutable boxed
* primitive types as the underlying primitive type.
*/
SemType getTrackedType(SemExpr e) {
result = Lang::getAlternateType(e)
or
not exists(Lang::getAlternateType(e)) and result = e.getSemType()
}
/**
* Gets the type used to track the specified source variable's range information.
*
* Usually, this just `e.getType()`, but the language can override this to track immutable boxed
* primitive types as the underlying primitive type.
*/
SemType getTrackedTypeForSsaVariable(SemSsaVariable var) {
result = Lang::getAlternateTypeForSsaVariable(var)
or
not exists(Lang::getAlternateTypeForSsaVariable(var)) and result = var.getType()
}
}

View File

@@ -6,488 +6,494 @@
* three-valued domain `{negative, zero, positive}`.
*/
private import RangeAnalysisStage
private import SignAnalysisSpecific as Specific
private import experimental.semmle.code.cpp.semantic.Semantic
private import ConstantAnalysis
private import RangeUtils
private import Sign
/**
* An SSA definition for which the analysis can compute the sign.
*
* The actual computation of the sign is done in an override of the `getSign()` predicate. The
* charpred of any subclass must _not_ invoke `getSign()`, directly or indirectly. This ensures
* that the charpred does not introduce negative recursion. The `getSign()` predicate may be
* recursive.
*/
abstract private class SignDef instanceof SemSsaVariable {
final string toString() { result = super.toString() }
module SignAnalysis<DeltaSig D, UtilSig<D> Utils> {
/**
* An SSA definition for which the analysis can compute the sign.
*
* The actual computation of the sign is done in an override of the `getSign()` predicate. The
* charpred of any subclass must _not_ invoke `getSign()`, directly or indirectly. This ensures
* that the charpred does not introduce negative recursion. The `getSign()` predicate may be
* recursive.
*/
abstract private class SignDef instanceof SemSsaVariable {
final string toString() { result = super.toString() }
/** Gets the possible signs of this SSA definition. */
abstract Sign getSign();
}
/** An SSA definition whose sign is computed based on standard flow. */
abstract private class FlowSignDef extends SignDef {
abstract override Sign getSign();
}
/** An SSA definition whose sign is determined by the sign of that definitions source expression. */
private class ExplicitSignDef extends FlowSignDef instanceof SemSsaExplicitUpdate {
final override Sign getSign() { result = semExprSign(super.getSourceExpr()) }
}
/** An SSA Phi definition, whose sign is the union of the signs of its inputs. */
private class PhiSignDef extends FlowSignDef instanceof SemSsaPhiNode {
final override Sign getSign() {
exists(SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge |
edge.phiInput(this, inp) and
result = semSsaSign(inp, edge)
)
}
}
/** An SSA definition whose sign is computed by a language-specific implementation. */
abstract class CustomSignDef extends SignDef {
abstract override Sign getSign();
}
/**
* An expression for which the analysis can compute the sign.
*
* The actual computation of the sign is done in an override of the `getSign()` predicate. The
* charpred of any subclass must _not_ invoke `getSign()`, directly or indirectly. This ensures
* that the charpred does not introduce negative recursion. The `getSign()` predicate may be
* recursive.
*
* Concrete implementations extend one of the following subclasses:
* - `ConstantSignExpr`, for expressions with a compile-time constant value.
* - `FlowSignExpr`, for expressions whose sign can be computed from the signs of their operands.
* - `CustomsignExpr`, for expressions whose sign can be computed by a language-specific
* implementation.
*
* If the same expression matches more than one of the above subclasses, the sign is computed as
* follows:
* - The sign of a `ConstantSignExpr` is computed solely from `ConstantSignExpr.getSign()`,
* regardless of any other subclasses.
* - If a non-`ConstantSignExpr` expression matches exactly one of `FlowSignExpr` or
* `CustomSignExpr`, the sign is computed by that class' `getSign()` predicate.
* - If a non-`ConstantSignExpr` expression matches both `FlowSignExpr` and `CustomSignExpr`, the
* sign is the _intersection_ of the signs of those two classes' `getSign()` predicates. Thus,
* both classes have the opportunity to _restrict_ the set of possible signs, not to generate new
* possible signs.
* - If an expression does not match any of the three subclasses, then it can have any sign.
*
* Note that the `getSign()` predicate is introduced only in subclasses of `SignExpr`.
*/
abstract class SignExpr instanceof SemExpr {
SignExpr() { not Specific::ignoreExprSign(this) }
final string toString() { result = super.toString() }
abstract Sign getSign();
}
/** An expression whose sign is determined by its constant numeric value. */
private class ConstantSignExpr extends SignExpr {
ConstantSignExpr() {
this instanceof SemConstantIntegerExpr or
exists(this.(SemNumericLiteralExpr).getApproximateFloatValue())
/** Gets the possible signs of this SSA definition. */
abstract Sign getSign();
}
final override Sign getSign() {
exists(int i | this.(SemConstantIntegerExpr).getIntValue() = i |
i < 0 and result = TNeg()
/** An SSA definition whose sign is computed based on standard flow. */
abstract private class FlowSignDef extends SignDef {
abstract override Sign getSign();
}
/** An SSA definition whose sign is determined by the sign of that definitions source expression. */
private class ExplicitSignDef extends FlowSignDef instanceof SemSsaExplicitUpdate {
final override Sign getSign() { result = semExprSign(super.getSourceExpr()) }
}
/** An SSA Phi definition, whose sign is the union of the signs of its inputs. */
private class PhiSignDef extends FlowSignDef instanceof SemSsaPhiNode {
final override Sign getSign() {
exists(SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge |
edge.phiInput(this, inp) and
result = semSsaSign(inp, edge)
)
}
}
/** An SSA definition whose sign is computed by a language-specific implementation. */
abstract class CustomSignDef extends SignDef {
abstract override Sign getSign();
}
/**
* An expression for which the analysis can compute the sign.
*
* The actual computation of the sign is done in an override of the `getSign()` predicate. The
* charpred of any subclass must _not_ invoke `getSign()`, directly or indirectly. This ensures
* that the charpred does not introduce negative recursion. The `getSign()` predicate may be
* recursive.
*
* Concrete implementations extend one of the following subclasses:
* - `ConstantSignExpr`, for expressions with a compile-time constant value.
* - `FlowSignExpr`, for expressions whose sign can be computed from the signs of their operands.
* - `CustomsignExpr`, for expressions whose sign can be computed by a language-specific
* implementation.
*
* If the same expression matches more than one of the above subclasses, the sign is computed as
* follows:
* - The sign of a `ConstantSignExpr` is computed solely from `ConstantSignExpr.getSign()`,
* regardless of any other subclasses.
* - If a non-`ConstantSignExpr` expression matches exactly one of `FlowSignExpr` or
* `CustomSignExpr`, the sign is computed by that class' `getSign()` predicate.
* - If a non-`ConstantSignExpr` expression matches both `FlowSignExpr` and `CustomSignExpr`, the
* sign is the _intersection_ of the signs of those two classes' `getSign()` predicates. Thus,
* both classes have the opportunity to _restrict_ the set of possible signs, not to generate new
* possible signs.
* - If an expression does not match any of the three subclasses, then it can have any sign.
*
* Note that the `getSign()` predicate is introduced only in subclasses of `SignExpr`.
*/
abstract class SignExpr instanceof SemExpr {
SignExpr() { not Specific::ignoreExprSign(this) }
final string toString() { result = super.toString() }
abstract Sign getSign();
}
/** An expression whose sign is determined by its constant numeric value. */
private class ConstantSignExpr extends SignExpr {
ConstantSignExpr() {
this instanceof SemConstantIntegerExpr or
exists(this.(SemNumericLiteralExpr).getApproximateFloatValue())
}
final override Sign getSign() {
exists(int i | this.(SemConstantIntegerExpr).getIntValue() = i |
i < 0 and result = TNeg()
or
i = 0 and result = TZero()
or
i > 0 and result = TPos()
)
or
i = 0 and result = TZero()
or
i > 0 and result = TPos()
)
or
not exists(this.(SemConstantIntegerExpr).getIntValue()) and
exists(float f | f = this.(SemNumericLiteralExpr).getApproximateFloatValue() |
f < 0 and result = TNeg()
or
f = 0 and result = TZero()
or
f > 0 and result = TPos()
)
}
}
abstract private class NonConstantSignExpr extends SignExpr {
NonConstantSignExpr() { not this instanceof ConstantSignExpr }
final override Sign getSign() {
// The result is the _intersection_ of the signs computed from flow and by the language.
(result = this.(FlowSignExpr).getSignRestriction() or not this instanceof FlowSignExpr) and
(result = this.(CustomSignExpr).getSignRestriction() or not this instanceof CustomSignExpr)
}
}
/** An expression whose sign is computed from the signs of its operands. */
abstract private class FlowSignExpr extends NonConstantSignExpr {
abstract Sign getSignRestriction();
}
/** An expression whose sign is computed by a language-specific implementation. */
abstract class CustomSignExpr extends NonConstantSignExpr {
abstract Sign getSignRestriction();
}
/** An expression whose sign is unknown. */
private class UnknownSignExpr extends SignExpr {
UnknownSignExpr() {
not this instanceof FlowSignExpr and
not this instanceof CustomSignExpr and
not this instanceof ConstantSignExpr and
(
// Only track numeric types.
getTrackedType(this) instanceof SemNumericType
or
// Unless the language says to track this expression anyway.
Specific::trackUnknownNonNumericExpr(this)
)
not exists(this.(SemConstantIntegerExpr).getIntValue()) and
exists(float f | f = this.(SemNumericLiteralExpr).getApproximateFloatValue() |
f < 0 and result = TNeg()
or
f = 0 and result = TZero()
or
f > 0 and result = TPos()
)
}
}
final override Sign getSign() { semAnySign(result) }
}
abstract private class NonConstantSignExpr extends SignExpr {
NonConstantSignExpr() { not this instanceof ConstantSignExpr }
/**
* A `Load` expression whose sign is computed from the sign of its SSA definition, restricted by
* inference from any intervening guards.
*/
class UseSignExpr extends FlowSignExpr {
SemSsaVariable v;
UseSignExpr() { v.getAUse() = this }
override Sign getSignRestriction() {
// Propagate via SSA
// Propagate the sign from the def of `v`, incorporating any inference from guards.
result = semSsaSign(v, any(SemSsaReadPositionBlock bb | bb.getAnExpr() = this))
or
// No block for this read. Just use the sign of the def.
// REVIEW: How can this happen?
not exists(SemSsaReadPositionBlock bb | bb.getAnExpr() = this) and
result = semSsaDefSign(v)
final override Sign getSign() {
// The result is the _intersection_ of the signs computed from flow and by the language.
(result = this.(FlowSignExpr).getSignRestriction() or not this instanceof FlowSignExpr) and
(result = this.(CustomSignExpr).getSignRestriction() or not this instanceof CustomSignExpr)
}
}
}
/** A binary expression whose sign is computed from the signs of its operands. */
private class BinarySignExpr extends FlowSignExpr {
SemBinaryExpr binary;
/** An expression whose sign is computed from the signs of its operands. */
abstract private class FlowSignExpr extends NonConstantSignExpr {
abstract Sign getSignRestriction();
}
BinarySignExpr() { binary = this }
/** An expression whose sign is computed by a language-specific implementation. */
abstract class CustomSignExpr extends NonConstantSignExpr {
abstract Sign getSignRestriction();
}
override Sign getSignRestriction() {
exists(SemExpr left, SemExpr right |
binaryExprOperands(binary, left, right) and
/** An expression whose sign is unknown. */
private class UnknownSignExpr extends SignExpr {
UnknownSignExpr() {
not this instanceof FlowSignExpr and
not this instanceof CustomSignExpr and
not this instanceof ConstantSignExpr and
(
// Only track numeric types.
Utils::getTrackedType(this) instanceof SemNumericType
or
// Unless the language says to track this expression anyway.
Specific::trackUnknownNonNumericExpr(this)
)
}
final override Sign getSign() { semAnySign(result) }
}
/**
* A `Load` expression whose sign is computed from the sign of its SSA definition, restricted by
* inference from any intervening guards.
*/
class UseSignExpr extends FlowSignExpr {
SemSsaVariable v;
UseSignExpr() { v.getAUse() = this }
override Sign getSignRestriction() {
// Propagate via SSA
// Propagate the sign from the def of `v`, incorporating any inference from guards.
result = semSsaSign(v, any(SemSsaReadPositionBlock bb | bb.getAnExpr() = this))
or
// No block for this read. Just use the sign of the def.
// REVIEW: How can this happen?
not exists(SemSsaReadPositionBlock bb | bb.getAnExpr() = this) and
result = semSsaDefSign(v)
}
}
/** A binary expression whose sign is computed from the signs of its operands. */
private class BinarySignExpr extends FlowSignExpr {
SemBinaryExpr binary;
BinarySignExpr() { binary = this }
override Sign getSignRestriction() {
exists(SemExpr left, SemExpr right |
binaryExprOperands(binary, left, right) and
result =
semExprSign(pragma[only_bind_out](left))
.applyBinaryOp(semExprSign(pragma[only_bind_out](right)), binary.getOpcode())
)
or
exists(SemDivExpr div | div = binary |
result = semExprSign(div.getLeftOperand()) and
result != TZero() and
div.getRightOperand().(SemFloatingPointLiteralExpr).getFloatValue() = 0
)
}
}
pragma[nomagic]
private predicate binaryExprOperands(SemBinaryExpr binary, SemExpr left, SemExpr right) {
binary.getLeftOperand() = left and binary.getRightOperand() = right
}
/**
* A `Convert`, `Box`, or `Unbox` expression.
*/
private class SemCastExpr instanceof SemUnaryExpr {
string toString() { result = super.toString() }
SemCastExpr() {
this instanceof SemConvertExpr
or
this instanceof SemBoxExpr
or
this instanceof SemUnboxExpr
}
}
/** A unary expression whose sign is computed from the sign of its operand. */
private class UnarySignExpr extends FlowSignExpr {
SemUnaryExpr unary;
UnarySignExpr() { unary = this and not this instanceof SemCastExpr }
override Sign getSignRestriction() {
result =
semExprSign(pragma[only_bind_out](left))
.applyBinaryOp(semExprSign(pragma[only_bind_out](right)), binary.getOpcode())
)
or
exists(SemDivExpr div | div = binary |
result = semExprSign(div.getLeftOperand()) and
result != TZero() and
div.getRightOperand().(SemFloatingPointLiteralExpr).getFloatValue() = 0
semExprSign(pragma[only_bind_out](unary.getOperand())).applyUnaryOp(unary.getOpcode())
}
}
/**
* A `Convert`, `Box`, or `Unbox` expression, whose sign is computed based on
* the sign of its operand and the source and destination types.
*/
abstract private class CastSignExpr extends FlowSignExpr {
SemUnaryExpr cast;
CastSignExpr() { cast = this and cast instanceof SemCastExpr }
override Sign getSignRestriction() { result = semExprSign(cast.getOperand()) }
}
/**
* A `Convert` expression.
*/
private class ConvertSignExpr extends CastSignExpr {
override SemConvertExpr cast;
}
/**
* A `Box` expression.
*/
private class BoxSignExpr extends CastSignExpr {
override SemBoxExpr cast;
}
/**
* An `Unbox` expression.
*/
private class UnboxSignExpr extends CastSignExpr {
override SemUnboxExpr cast;
UnboxSignExpr() {
exists(SemType fromType | fromType = Utils::getTrackedType(cast.getOperand()) |
// Only numeric source types are handled here.
fromType instanceof SemNumericType
)
}
}
private predicate unknownSign(SemExpr e) { e instanceof UnknownSignExpr }
/**
* Holds if `lowerbound` is a lower bound for `v` at `pos`. This is restricted
* to only include bounds for which we might determine a sign.
*/
private predicate lowerBound(
SemExpr lowerbound, SemSsaVariable v, SemSsaReadPosition pos, boolean isStrict
) {
exists(boolean testIsTrue, SemRelationalExpr comp |
pos.hasReadOfVar(v) and
semGuardControlsSsaRead(semGetComparisonGuard(comp), pos, testIsTrue) and
not unknownSign(lowerbound)
|
testIsTrue = true and
comp.getLesserOperand() = lowerbound and
comp.getGreaterOperand() = Utils::semSsaRead(v, D::fromInt(0)) and
(if comp.isStrict() then isStrict = true else isStrict = false)
or
testIsTrue = false and
comp.getGreaterOperand() = lowerbound and
comp.getLesserOperand() = Utils::semSsaRead(v, D::fromInt(0)) and
(if comp.isStrict() then isStrict = false else isStrict = true)
)
}
}
pragma[nomagic]
private predicate binaryExprOperands(SemBinaryExpr binary, SemExpr left, SemExpr right) {
binary.getLeftOperand() = left and binary.getRightOperand() = right
}
/**
* A `Convert`, `Box`, or `Unbox` expression.
*/
private class SemCastExpr extends SemUnaryExpr {
SemCastExpr() {
this instanceof SemConvertExpr
or
this instanceof SemBoxExpr
or
this instanceof SemUnboxExpr
}
}
/** A unary expression whose sign is computed from the sign of its operand. */
private class UnarySignExpr extends FlowSignExpr {
SemUnaryExpr unary;
UnarySignExpr() { unary = this and not this instanceof SemCastExpr }
override Sign getSignRestriction() {
result = semExprSign(pragma[only_bind_out](unary.getOperand())).applyUnaryOp(unary.getOpcode())
}
}
/**
* A `Convert`, `Box`, or `Unbox` expression, whose sign is computed based on
* the sign of its operand and the source and destination types.
*/
abstract private class CastSignExpr extends FlowSignExpr {
SemUnaryExpr cast;
CastSignExpr() { cast = this and cast instanceof SemCastExpr }
override Sign getSignRestriction() { result = semExprSign(cast.getOperand()) }
}
/**
* A `Convert` expression.
*/
private class ConvertSignExpr extends CastSignExpr {
override SemConvertExpr cast;
}
/**
* A `Box` expression.
*/
private class BoxSignExpr extends CastSignExpr {
override SemBoxExpr cast;
}
/**
* An `Unbox` expression.
*/
private class UnboxSignExpr extends CastSignExpr {
override SemUnboxExpr cast;
UnboxSignExpr() {
exists(SemType fromType | fromType = getTrackedType(cast.getOperand()) |
// Only numeric source types are handled here.
fromType instanceof SemNumericType
/**
* Holds if `upperbound` is an upper bound for `v` at `pos`. This is restricted
* to only include bounds for which we might determine a sign.
*/
private predicate upperBound(
SemExpr upperbound, SemSsaVariable v, SemSsaReadPosition pos, boolean isStrict
) {
exists(boolean testIsTrue, SemRelationalExpr comp |
pos.hasReadOfVar(v) and
semGuardControlsSsaRead(semGetComparisonGuard(comp), pos, testIsTrue) and
not unknownSign(upperbound)
|
testIsTrue = true and
comp.getGreaterOperand() = upperbound and
comp.getLesserOperand() = Utils::semSsaRead(v, D::fromInt(0)) and
(if comp.isStrict() then isStrict = true else isStrict = false)
or
testIsTrue = false and
comp.getLesserOperand() = upperbound and
comp.getGreaterOperand() = Utils::semSsaRead(v, D::fromInt(0)) and
(if comp.isStrict() then isStrict = false else isStrict = true)
)
}
}
private predicate unknownSign(SemExpr e) { e instanceof UnknownSignExpr }
/**
* Holds if `eqbound` is an equality/inequality for `v` at `pos`. This is
* restricted to only include bounds for which we might determine a sign. The
* boolean `isEq` gives the polarity:
* - `isEq = true` : `v = eqbound`
* - `isEq = false` : `v != eqbound`
*/
private predicate eqBound(SemExpr eqbound, SemSsaVariable v, SemSsaReadPosition pos, boolean isEq) {
exists(SemGuard guard, boolean testIsTrue, boolean polarity |
pos.hasReadOfVar(v) and
semGuardControlsSsaRead(guard, pos, testIsTrue) and
guard.isEquality(eqbound, Utils::semSsaRead(v, D::fromInt(0)), polarity) and
isEq = polarity.booleanXor(testIsTrue).booleanNot() and
not unknownSign(eqbound)
)
}
/**
* Holds if `lowerbound` is a lower bound for `v` at `pos`. This is restricted
* to only include bounds for which we might determine a sign.
*/
private predicate lowerBound(
SemExpr lowerbound, SemSsaVariable v, SemSsaReadPosition pos, boolean isStrict
) {
exists(boolean testIsTrue, SemRelationalExpr comp |
pos.hasReadOfVar(v) and
semGuardControlsSsaRead(semGetComparisonGuard(comp), pos, testIsTrue) and
not unknownSign(lowerbound)
|
testIsTrue = true and
comp.getLesserOperand() = lowerbound and
comp.getGreaterOperand() = semSsaRead(v, 0) and
(if comp.isStrict() then isStrict = true else isStrict = false)
/**
* Holds if `bound` is a bound for `v` at `pos` that needs to be positive in
* order for `v` to be positive.
*/
private predicate posBound(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) {
upperBound(bound, v, pos, _) or
eqBound(bound, v, pos, true)
}
/**
* Holds if `bound` is a bound for `v` at `pos` that needs to be negative in
* order for `v` to be negative.
*/
private predicate negBound(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) {
lowerBound(bound, v, pos, _) or
eqBound(bound, v, pos, true)
}
/**
* Holds if `bound` is a bound for `v` at `pos` that can restrict whether `v`
* can be zero.
*/
private predicate zeroBound(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) {
lowerBound(bound, v, pos, _) or
upperBound(bound, v, pos, _) or
eqBound(bound, v, pos, _)
}
/** Holds if `bound` allows `v` to be positive at `pos`. */
private predicate posBoundOk(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) {
posBound(bound, v, pos) and TPos() = semExprSign(bound)
}
/** Holds if `bound` allows `v` to be negative at `pos`. */
private predicate negBoundOk(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) {
negBound(bound, v, pos) and TNeg() = semExprSign(bound)
}
/** Holds if `bound` allows `v` to be zero at `pos`. */
private predicate zeroBoundOk(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) {
lowerBound(bound, v, pos, _) and TNeg() = semExprSign(bound)
or
testIsTrue = false and
comp.getGreaterOperand() = lowerbound and
comp.getLesserOperand() = semSsaRead(v, 0) and
(if comp.isStrict() then isStrict = false else isStrict = true)
)
}
/**
* Holds if `upperbound` is an upper bound for `v` at `pos`. This is restricted
* to only include bounds for which we might determine a sign.
*/
private predicate upperBound(
SemExpr upperbound, SemSsaVariable v, SemSsaReadPosition pos, boolean isStrict
) {
exists(boolean testIsTrue, SemRelationalExpr comp |
pos.hasReadOfVar(v) and
semGuardControlsSsaRead(semGetComparisonGuard(comp), pos, testIsTrue) and
not unknownSign(upperbound)
|
testIsTrue = true and
comp.getGreaterOperand() = upperbound and
comp.getLesserOperand() = semSsaRead(v, 0) and
(if comp.isStrict() then isStrict = true else isStrict = false)
lowerBound(bound, v, pos, false) and TZero() = semExprSign(bound)
or
testIsTrue = false and
comp.getLesserOperand() = upperbound and
comp.getGreaterOperand() = semSsaRead(v, 0) and
(if comp.isStrict() then isStrict = false else isStrict = true)
)
}
upperBound(bound, v, pos, _) and TPos() = semExprSign(bound)
or
upperBound(bound, v, pos, false) and TZero() = semExprSign(bound)
or
eqBound(bound, v, pos, true) and TZero() = semExprSign(bound)
or
eqBound(bound, v, pos, false) and TZero() != semExprSign(bound)
}
/**
* Holds if `eqbound` is an equality/inequality for `v` at `pos`. This is
* restricted to only include bounds for which we might determine a sign. The
* boolean `isEq` gives the polarity:
* - `isEq = true` : `v = eqbound`
* - `isEq = false` : `v != eqbound`
*/
private predicate eqBound(SemExpr eqbound, SemSsaVariable v, SemSsaReadPosition pos, boolean isEq) {
exists(SemGuard guard, boolean testIsTrue, boolean polarity |
/**
* Holds if there is a bound that might restrict whether `v` has the sign `s`
* at `pos`.
*/
private predicate hasGuard(SemSsaVariable v, SemSsaReadPosition pos, Sign s) {
s = TPos() and posBound(_, v, pos)
or
s = TNeg() and negBound(_, v, pos)
or
s = TZero() and zeroBound(_, v, pos)
}
/**
* Gets a possible sign of `v` at `pos` based on its definition, where the sign
* might be ruled out by a guard.
*/
pragma[noinline]
private Sign guardedSsaSign(SemSsaVariable v, SemSsaReadPosition pos) {
result = semSsaDefSign(v) and
pos.hasReadOfVar(v) and
semGuardControlsSsaRead(guard, pos, testIsTrue) and
guard.isEquality(eqbound, semSsaRead(v, 0), polarity) and
isEq = polarity.booleanXor(testIsTrue).booleanNot() and
not unknownSign(eqbound)
)
}
/**
* Holds if `bound` is a bound for `v` at `pos` that needs to be positive in
* order for `v` to be positive.
*/
private predicate posBound(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) {
upperBound(bound, v, pos, _) or
eqBound(bound, v, pos, true)
}
/**
* Holds if `bound` is a bound for `v` at `pos` that needs to be negative in
* order for `v` to be negative.
*/
private predicate negBound(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) {
lowerBound(bound, v, pos, _) or
eqBound(bound, v, pos, true)
}
/**
* Holds if `bound` is a bound for `v` at `pos` that can restrict whether `v`
* can be zero.
*/
private predicate zeroBound(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) {
lowerBound(bound, v, pos, _) or
upperBound(bound, v, pos, _) or
eqBound(bound, v, pos, _)
}
/** Holds if `bound` allows `v` to be positive at `pos`. */
private predicate posBoundOk(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) {
posBound(bound, v, pos) and TPos() = semExprSign(bound)
}
/** Holds if `bound` allows `v` to be negative at `pos`. */
private predicate negBoundOk(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) {
negBound(bound, v, pos) and TNeg() = semExprSign(bound)
}
/** Holds if `bound` allows `v` to be zero at `pos`. */
private predicate zeroBoundOk(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) {
lowerBound(bound, v, pos, _) and TNeg() = semExprSign(bound)
or
lowerBound(bound, v, pos, false) and TZero() = semExprSign(bound)
or
upperBound(bound, v, pos, _) and TPos() = semExprSign(bound)
or
upperBound(bound, v, pos, false) and TZero() = semExprSign(bound)
or
eqBound(bound, v, pos, true) and TZero() = semExprSign(bound)
or
eqBound(bound, v, pos, false) and TZero() != semExprSign(bound)
}
/**
* Holds if there is a bound that might restrict whether `v` has the sign `s`
* at `pos`.
*/
private predicate hasGuard(SemSsaVariable v, SemSsaReadPosition pos, Sign s) {
s = TPos() and posBound(_, v, pos)
or
s = TNeg() and negBound(_, v, pos)
or
s = TZero() and zeroBound(_, v, pos)
}
/**
* Gets a possible sign of `v` at `pos` based on its definition, where the sign
* might be ruled out by a guard.
*/
pragma[noinline]
private Sign guardedSsaSign(SemSsaVariable v, SemSsaReadPosition pos) {
result = semSsaDefSign(v) and
pos.hasReadOfVar(v) and
hasGuard(v, pos, result)
}
/**
* Gets a possible sign of `v` at `pos` based on its definition, where no guard
* can rule it out.
*/
pragma[noinline]
private Sign unguardedSsaSign(SemSsaVariable v, SemSsaReadPosition pos) {
result = semSsaDefSign(v) and
pos.hasReadOfVar(v) and
not hasGuard(v, pos, result)
}
/**
* Gets a possible sign of `v` at read position `pos`, where a guard could have
* ruled out the sign but does not.
* This does not check that the definition of `v` also allows the sign.
*/
private Sign guardedSsaSignOk(SemSsaVariable v, SemSsaReadPosition pos) {
result = TPos() and
forex(SemExpr bound | posBound(bound, v, pos) | posBoundOk(bound, v, pos))
or
result = TNeg() and
forex(SemExpr bound | negBound(bound, v, pos) | negBoundOk(bound, v, pos))
or
result = TZero() and
forex(SemExpr bound | zeroBound(bound, v, pos) | zeroBoundOk(bound, v, pos))
}
/** Gets a possible sign for `v` at `pos`. */
private Sign semSsaSign(SemSsaVariable v, SemSsaReadPosition pos) {
result = unguardedSsaSign(v, pos)
or
result = guardedSsaSign(v, pos) and
result = guardedSsaSignOk(v, pos)
}
/** Gets a possible sign for `v`. */
pragma[nomagic]
Sign semSsaDefSign(SemSsaVariable v) { result = v.(SignDef).getSign() }
/** Gets a possible sign for `e`. */
cached
Sign semExprSign(SemExpr e) {
exists(Sign s | s = e.(SignExpr).getSign() |
if
getTrackedType(e) instanceof SemUnsignedIntegerType and
s = TNeg() and
not Specific::ignoreTypeRestrictions(e)
then result = TPos()
else result = s
)
}
/**
* Dummy predicate that holds for any sign. This is added to improve readability
* of cases where the sign is unrestricted.
*/
predicate semAnySign(Sign s) { any() }
/** Holds if `e` can be positive and cannot be negative. */
predicate semPositive(SemExpr e) {
semExprSign(e) = TPos() and
not semExprSign(e) = TNeg()
}
/** Holds if `e` can be negative and cannot be positive. */
predicate semNegative(SemExpr e) {
semExprSign(e) = TNeg() and
not semExprSign(e) = TPos()
}
/** Holds if `e` is strictly positive. */
predicate semStrictlyPositive(SemExpr e) {
semExprSign(e) = TPos() and
not semExprSign(e) = TNeg() and
not semExprSign(e) = TZero()
}
/** Holds if `e` is strictly negative. */
predicate semStrictlyNegative(SemExpr e) {
semExprSign(e) = TNeg() and
not semExprSign(e) = TPos() and
not semExprSign(e) = TZero()
hasGuard(v, pos, result)
}
/**
* Gets a possible sign of `v` at `pos` based on its definition, where no guard
* can rule it out.
*/
pragma[noinline]
private Sign unguardedSsaSign(SemSsaVariable v, SemSsaReadPosition pos) {
result = semSsaDefSign(v) and
pos.hasReadOfVar(v) and
not hasGuard(v, pos, result)
}
/**
* Gets a possible sign of `v` at read position `pos`, where a guard could have
* ruled out the sign but does not.
* This does not check that the definition of `v` also allows the sign.
*/
private Sign guardedSsaSignOk(SemSsaVariable v, SemSsaReadPosition pos) {
result = TPos() and
forex(SemExpr bound | posBound(bound, v, pos) | posBoundOk(bound, v, pos))
or
result = TNeg() and
forex(SemExpr bound | negBound(bound, v, pos) | negBoundOk(bound, v, pos))
or
result = TZero() and
forex(SemExpr bound | zeroBound(bound, v, pos) | zeroBoundOk(bound, v, pos))
}
/** Gets a possible sign for `v` at `pos`. */
private Sign semSsaSign(SemSsaVariable v, SemSsaReadPosition pos) {
result = unguardedSsaSign(v, pos)
or
result = guardedSsaSign(v, pos) and
result = guardedSsaSignOk(v, pos)
}
/** Gets a possible sign for `v`. */
pragma[nomagic]
Sign semSsaDefSign(SemSsaVariable v) { result = v.(SignDef).getSign() }
/** Gets a possible sign for `e`. */
cached
Sign semExprSign(SemExpr e) {
exists(Sign s | s = e.(SignExpr).getSign() |
if
Utils::getTrackedType(e) instanceof SemUnsignedIntegerType and
s = TNeg() and
not Specific::ignoreTypeRestrictions(e)
then result = TPos()
else result = s
)
}
/**
* Dummy predicate that holds for any sign. This is added to improve readability
* of cases where the sign is unrestricted.
*/
predicate semAnySign(Sign s) { any() }
/** Holds if `e` can be positive and cannot be negative. */
predicate semPositive(SemExpr e) {
semExprSign(e) = TPos() and
not semExprSign(e) = TNeg()
}
/** Holds if `e` can be negative and cannot be positive. */
predicate semNegative(SemExpr e) {
semExprSign(e) = TNeg() and
not semExprSign(e) = TPos()
}
/** Holds if `e` is strictly positive. */
predicate semStrictlyPositive(SemExpr e) {
semExprSign(e) = TPos() and
not semExprSign(e) = TNeg() and
not semExprSign(e) = TZero()
}
/** Holds if `e` is strictly negative. */
predicate semStrictlyNegative(SemExpr e) {
semExprSign(e) = TNeg() and
not semExprSign(e) = TPos() and
not semExprSign(e) = TZero()
}
}

View File

@@ -1,5 +1,5 @@
name: codeql/cpp-all
version: 0.4.6-dev
version: 0.5.1
groups: cpp
dbscheme: semmlecode.cpp.dbscheme
extractor: cpp
@@ -7,3 +7,4 @@ library: true
upgrades: upgrades
dependencies:
codeql/ssa: ${workspace}
codeql/tutorial: ${workspace}

View File

@@ -318,7 +318,7 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
MetricFunction getMetrics() { result = this }
/** Holds if this function calls the function `f`. */
predicate calls(Function f) { exists(Locatable l | this.calls(f, l)) }
predicate calls(Function f) { this.calls(f, _) }
/**
* Holds if this function calls the function `f` in the `FunctionCall`
@@ -335,7 +335,7 @@ class Function extends Declaration, ControlFlowNode, AccessHolder, @function {
}
/** Holds if this function accesses a function or variable or enumerator `a`. */
predicate accesses(Declaration a) { exists(Locatable l | this.accesses(a, l)) }
predicate accesses(Declaration a) { this.accesses(a, _) }
/**
* Holds if this function accesses a function or variable or enumerator `a`

View File

@@ -10,12 +10,14 @@ import semmle.code.cpp.File
*/
class Location extends @location {
/** Gets the container corresponding to this location. */
pragma[nomagic]
Container getContainer() { this.fullLocationInfo(result, _, _, _, _) }
/** Gets the file corresponding to this location, if any. */
File getFile() { result = this.getContainer() }
/** Gets the 1-based line number (inclusive) where this location starts. */
pragma[nomagic]
int getStartLine() { this.fullLocationInfo(_, result, _, _, _) }
/** Gets the 1-based column number (inclusive) where this location starts. */

View File

@@ -816,6 +816,12 @@ private predicate floatingPointTypeMapping(
or
// _Float128x
kind = 50 and base = 2 and domain = TRealDomain() and realKind = 50 and extended = true
or
// _Float16
kind = 52 and base = 2 and domain = TRealDomain() and realKind = 52 and extended = false
or
// _Complex _Float16
kind = 53 and base = 2 and domain = TComplexDomain() and realKind = 52 and extended = false
}
/**

View File

@@ -33,7 +33,7 @@ DependencyOptions getDependencyOptions() { any() }
class DependsSource extends Element {
DependsSource() {
// not inside a template instantiation
not exists(Element other | this.isFromTemplateInstantiation(other)) or
not this.isFromTemplateInstantiation(_) or
// allow DeclarationEntrys of template specializations
this.(DeclarationEntry).getDeclaration().(Function).isConstructedFrom(_) or
this.(DeclarationEntry).getDeclaration().(Class).isConstructedFrom(_)

View File

@@ -69,12 +69,9 @@ predicate functionContainsDisabledCode(Function f) {
*/
predicate functionContainsPreprocCode(Function f) {
// `f` contains a preprocessor branch
exists(
PreprocessorBranchDirective pbd, string file, int pbdStartLine, int fBlockStartLine,
int fBlockEndLine
|
exists(string file, int pbdStartLine, int fBlockStartLine, int fBlockEndLine |
functionLocation(f, file, fBlockStartLine, fBlockEndLine) and
pbdLocation(pbd, file, pbdStartLine) and
pbdLocation(_, file, pbdStartLine) and
pbdStartLine <= fBlockEndLine and
pbdStartLine >= fBlockStartLine
)

View File

@@ -244,9 +244,7 @@ class ScanfFormatLiteral extends Expr {
/**
* Gets the maximum width option of the nth input (empty string if none is given).
*/
string getMaxWidthOpt(int n) {
exists(string spec, string len, string conv | this.parseConvSpec(n, spec, result, len, conv))
}
string getMaxWidthOpt(int n) { this.parseConvSpec(n, _, result, _, _) }
/**
* Gets the maximum width of the nth input.
@@ -256,18 +254,12 @@ class ScanfFormatLiteral extends Expr {
/**
* Gets the length flag of the nth conversion specifier.
*/
string getLength(int n) {
exists(string spec, string width, string conv |
this.parseConvSpec(n, spec, width, result, conv)
)
}
string getLength(int n) { this.parseConvSpec(n, _, _, result, _) }
/**
* Gets the conversion character of the nth conversion specifier.
*/
string getConversionChar(int n) {
exists(string spec, string width, string len | this.parseConvSpec(n, spec, width, len, result))
}
string getConversionChar(int n) { this.parseConvSpec(n, _, _, _, result) }
/**
* Gets the maximum length of the string that can be produced by the nth

View File

@@ -54,7 +54,7 @@ class SubBasicBlock extends ControlFlowNodeBase {
* only condition under which a `SubBasicBlock` may have multiple
* predecessors.
*/
predicate firstInBB() { exists(BasicBlock bb | this.getRankInBasicBlock(bb) = 1) }
predicate firstInBB() { this.getRankInBasicBlock(_) = 1 }
/**
* Holds if this `SubBasicBlock` comes last in its basic block. This is the

View File

@@ -441,8 +441,8 @@ library class ExprEvaluator extends int {
req = mid.(AssignExpr).getRValue()
)
or
exists(VariableAccess va, Variable v, boolean sub1 |
this.interestingVariableAccess(e, va, v, sub1) and
exists(Variable v, boolean sub1 |
this.interestingVariableAccess(e, _, v, sub1) and
req = v.getAnAssignedValue() and
(sub1 = true implies not this.ignoreVariableAssignment(e, v, req)) and
sub = false
@@ -876,7 +876,7 @@ private predicate nonAnalyzableVariableDefinition(Variable v, StmtParent def) {
* empirically to have effect only on a few rare and pathological examples.
*/
private predicate tractableVariable(Variable v) {
not exists(StmtParent def | nonAnalyzableVariableDefinition(v, def)) or
not nonAnalyzableVariableDefinition(v, _) or
strictcount(StmtParent def | nonAnalyzableVariableDefinition(v, def)) < 1000
}

View File

@@ -622,7 +622,11 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
}
private module Stage1 implements StageSig {
class Ap = Unit;
class Ap extends int {
// workaround for bad functionality-induced joins (happens when using `Unit`)
pragma[nomagic]
Ap() { this in [0 .. 1] and this < 1 }
}
private class Cc = boolean;
@@ -872,9 +876,9 @@ private module Stage1 implements StageSig {
pragma[nomagic]
private predicate revFlowOut(ReturnPosition pos, Configuration config) {
exists(DataFlowCall call, NodeEx out |
exists(NodeEx out |
revFlow(out, _, config) and
viableReturnPosOutNodeCandFwd1(call, pos, out, config)
viableReturnPosOutNodeCandFwd1(_, pos, out, config)
)
}
@@ -1327,8 +1331,8 @@ private module MkStage<StageSig PrevStage> {
*/
pragma[nomagic]
additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, ApApprox apa, Configuration config
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
ApApprox apa, Configuration config
) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
PrevStage::revFlow(node, state, apa, config) and
@@ -1337,21 +1341,21 @@ private module MkStage<StageSig PrevStage> {
pragma[inline]
additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
Configuration config
) {
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
}
pragma[nomagic]
private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, ApApprox apa, Configuration config
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
ApApprox apa, Configuration config
) {
sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and
summaryCtx = TParameterPositionNone() and
summaryCtx = TParamNodeNone() and
ap = getApNil(node) and
apa = getApprox(ap)
or
@@ -1372,7 +1376,7 @@ private module MkStage<StageSig PrevStage> {
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
summaryCtx = TParamNodeNone() and
argAp = apNone()
)
or
@@ -1380,7 +1384,7 @@ private module MkStage<StageSig PrevStage> {
fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
summaryCtx = TParamNodeNone() and
argAp = apNone() and
ap = getApNil(node) and
apa = getApprox(ap)
@@ -1390,7 +1394,7 @@ private module MkStage<StageSig PrevStage> {
fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStateStep(mid, state0, node, state, config) and
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
summaryCtx = TParamNodeNone() and
argAp = apNone() and
ap = getApNil(node) and
apa = getApprox(ap)
@@ -1414,10 +1418,10 @@ private module MkStage<StageSig PrevStage> {
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
if PrevStage::parameterMayFlowThrough(node, apa, config)
then (
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
summaryCtx = TParamNodeSome(node.asNode()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
summaryCtx = TParamNodeNone() and argAp = apNone()
)
or
// flow out of a callable
@@ -1433,16 +1437,19 @@ private module MkStage<StageSig PrevStage> {
)
or
// flow through a callable
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
exists(
DataFlowCall call, CcCall ccc, RetNodeEx ret, boolean allowsFieldFlow, ApApprox innerArgApa
|
fwdFlowThrough(call, cc, state, ccc, summaryCtx, argAp, ap, apa, ret, innerArgApa, config) and
flowThroughOutOfCall(call, ccc, ret, node, allowsFieldFlow, innerArgApa, apa, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
pragma[nomagic]
private predicate fwdFlowStore(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType, ApApprox apa1 |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
@@ -1473,8 +1480,8 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate fwdFlowRead0(
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ApNonNil ap, Configuration config
NodeEx node1, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, ApNonNil ap,
Configuration config
) {
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, _, _, config)
@@ -1483,7 +1490,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
) {
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and
@@ -1493,7 +1500,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
ParamNodeOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
) {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
@@ -1505,64 +1512,38 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate fwdFlowRetFromArg(
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
RetNodeEx ret, FlowState state, CcCall ccc, ParamNodeEx summaryCtx, Ap argAp, ApApprox argApa,
Ap ap, ApApprox apa, Configuration config
) {
exists(DataFlowCallable c, ReturnKindExt kind |
exists(ReturnKindExt kind |
fwdFlow(pragma[only_bind_into](ret), state, ccc,
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
getApprox(argAp) = argApa and
c = ret.getEnclosingCallable() and
TParamNodeSome(pragma[only_bind_into](summaryCtx.asNode())),
pragma[only_bind_into](apSome(argAp)), ap, pragma[only_bind_into](apa),
pragma[only_bind_into](config)) and
kind = ret.getKind() and
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
parameterFlowThroughAllowed(p, kind)
parameterFlowThroughAllowed(summaryCtx, kind) and
argApa = getApprox(argAp) and
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config))
)
}
pragma[inline]
private predicate fwdFlowInMayFlowThrough(
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
private predicate fwdFlowThrough0(
DataFlowCall call, Cc cc, FlowState state, CcCall ccc, ParamNodeOption summaryCtx,
ApOption argAp, Ap ap, ApApprox apa, RetNodeEx ret, ParamNodeEx innerSummaryCtx,
Ap innerArgAp, ApApprox innerArgApa, Configuration config
) {
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(param, apa, config)
}
// dedup before joining with `flowThroughOutOfCall`
pragma[nomagic]
private predicate fwdFlowInMayFlowThroughProj(
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
}
/**
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
* in the flow covered by `fwdFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate fwdFlowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
ApApprox argApa, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
fwdFlowRetFromArg(ret, state, ccc, innerSummaryCtx, innerArgAp, innerArgApa, ap, apa, config) and
fwdFlowIsEntered(call, cc, ccc, summaryCtx, argAp, innerSummaryCtx, innerArgAp, config)
}
pragma[nomagic]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
ApApprox apa, Configuration config
private predicate fwdFlowThrough(
DataFlowCall call, Cc cc, FlowState state, CcCall ccc, ParamNodeOption summaryCtx,
ApOption argAp, Ap ap, ApApprox apa, RetNodeEx ret, ApApprox innerArgApa, Configuration config
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
config) and
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
)
fwdFlowThrough0(call, cc, state, ccc, summaryCtx, argAp, ap, apa, ret, _, _, innerArgApa,
config)
}
/**
@@ -1571,12 +1552,14 @@ private module MkStage<StageSig PrevStage> {
*/
pragma[nomagic]
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ParameterPosition pos, Ap ap, Configuration config
DataFlowCall call, Cc cc, CcCall innerCc, ParamNodeOption summaryCtx, ApOption argAp,
ParamNodeEx p, Ap ap, Configuration config
) {
exists(ParamNodeEx param |
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
pos = param.getPosition()
exists(ApApprox apa |
fwdFlowIn(call, pragma[only_bind_into](p), _, cc, innerCc, summaryCtx, argAp, ap,
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(p, apa, config) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config))
)
}
@@ -1596,23 +1579,31 @@ private module MkStage<StageSig PrevStage> {
fwdFlowConsCand(ap1, c, ap2, config)
}
pragma[nomagic]
private predicate returnFlowsThrough0(
DataFlowCall call, FlowState state, CcCall ccc, Ap ap, ApApprox apa, RetNodeEx ret,
ParamNodeEx innerSummaryCtx, Ap innerArgAp, ApApprox innerArgApa, Configuration config
) {
fwdFlowThrough0(call, _, state, ccc, _, _, ap, apa, ret, innerSummaryCtx, innerArgAp,
innerArgApa, config)
}
pragma[nomagic]
private predicate returnFlowsThrough(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
RetNodeEx ret, ReturnPosition pos, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
Ap ap, Configuration config
) {
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
kind = ret.getKind() and
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
exists(DataFlowCall call, ApApprox apa, boolean allowsFieldFlow, ApApprox innerArgApa |
returnFlowsThrough0(call, state, ccc, ap, apa, ret, p, argAp, innerArgApa, config) and
flowThroughOutOfCall(call, ccc, ret, _, allowsFieldFlow, innerArgApa, apa, config) and
pos = ret.getReturnPosition() and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
pragma[nomagic]
private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp, Ap ap,
Configuration config
) {
exists(ApApprox argApa |
@@ -1620,7 +1611,7 @@ private module MkStage<StageSig PrevStage> {
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
pragma[only_bind_into](config)) and
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), ap,
pragma[only_bind_into](config)) and
if allowsFieldFlow = false then argAp instanceof ApNil else any()
)
@@ -1639,12 +1630,13 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate flowOutOfCallAp(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, NodeEx out, boolean allowsFieldFlow,
Ap ap, Configuration config
) {
exists(ApApprox apa |
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
fwdFlow(ret, _, _, _, _, ap, apa, config)
flowOutOfCallApa(call, ret, _, out, allowsFieldFlow, apa, config) and
fwdFlow(ret, _, _, _, _, ap, apa, config) and
pos = ret.getReturnPosition()
)
}
@@ -1739,17 +1731,17 @@ private module MkStage<StageSig PrevStage> {
)
or
// flow through a callable
exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
exists(DataFlowCall call, ParamNodeEx p, Ap innerReturnAp |
revFlowThrough(call, returnCtx, p, state, _, returnAp, ap, innerReturnAp, config) and
flowThroughIntoCall(call, node, p, _, ap, innerReturnAp, config)
)
or
// flow out of a callable
exists(ReturnKindExt kind |
revFlowOut(_, node, kind, state, _, _, ap, config) and
if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
exists(ReturnPosition pos |
revFlowOut(_, node, pos, state, _, _, ap, config) and
if returnFlowsThrough(node, pos, state, _, _, _, ap, config)
then (
returnCtx = TReturnCtxMaybeFlowThrough(kind) and
returnCtx = TReturnCtxMaybeFlowThrough(pos) and
returnAp = apSome(ap)
) else (
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
@@ -1782,47 +1774,33 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate revFlowOut(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, FlowState state, ReturnCtx returnCtx,
ApOption returnAp, Ap ap, Configuration config
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
flowOutOfCallAp(call, ret, pos, out, allowsFieldFlow, ap, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
/**
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
* in the flow covered by `revFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate revFlowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
Configuration config
) {
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
revFlowIsReturned(call, _, _, _, _, config)
}
pragma[nomagic]
private predicate revFlowParamToReturn(
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
ParamNodeEx p, FlowState state, ReturnPosition pos, Ap returnAp, Ap ap, Configuration config
) {
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind)
revFlow(pragma[only_bind_into](p), state, TReturnCtxMaybeFlowThrough(pos), apSome(returnAp),
pragma[only_bind_into](ap), pragma[only_bind_into](config)) and
parameterFlowThroughAllowed(p, pos.getKind()) and
PrevStage::parameterMayFlowThrough(p, getApprox(ap), config)
}
pragma[nomagic]
private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
Configuration config
private predicate revFlowThrough(
DataFlowCall call, ReturnCtx returnCtx, ParamNodeEx p, FlowState state, ReturnPosition pos,
ApOption returnAp, Ap ap, Ap innerReturnAp, Configuration config
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
)
revFlowParamToReturn(p, state, pos, innerReturnAp, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, pos, innerReturnAp, config)
}
/**
@@ -1832,12 +1810,12 @@ private module MkStage<StageSig PrevStage> {
*/
pragma[nomagic]
private predicate revFlowIsReturned(
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnPosition pos, Ap ap,
Configuration config
) {
exists(RetNodeEx ret, FlowState state, CcCall ccc |
revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
revFlowOut(call, ret, pos, state, returnCtx, returnAp, ap, config) and
returnFlowsThrough(ret, pos, state, ccc, _, _, ap, config) and
matchesCall(ccc, call)
)
}
@@ -1915,17 +1893,17 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
ParamNodeEx p, Ap ap, ReturnPosition pos, Ap returnAp, Configuration config
) {
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind)
revFlow(p, _, TReturnCtxMaybeFlowThrough(pos), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, pos.getKind())
}
pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(RetNodeEx ret, ReturnKindExt kind |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, _, config)
exists(ReturnPosition pos |
returnFlowsThrough(_, pos, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, pos, _, config)
)
}
@@ -1933,20 +1911,21 @@ private module MkStage<StageSig PrevStage> {
predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
) {
exists(ParamNodeEx p |
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
parameterFlowsThroughRev(p, argAp, kind, ap, config)
exists(ParamNodeEx p, ReturnPosition pos |
returnFlowsThrough(ret, pos, _, _, p, argAp, ap, config) and
parameterFlowsThroughRev(p, argAp, pos, ap, config) and
kind = pos.getKind()
)
}
pragma[nomagic]
predicate revFlowInToReturnIsReturned(
private predicate revFlowThroughArg(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
Ap ap, Configuration config
) {
exists(ReturnKindExt returnKind0, Ap returnAp0 |
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
exists(ParamNodeEx p, Ap innerReturnAp |
revFlowThrough(call, returnCtx, p, state, _, returnAp, ap, innerReturnAp, config) and
flowThroughIntoCall(call, arg, p, _, ap, innerReturnAp, config)
)
}
@@ -1954,7 +1933,7 @@ private module MkStage<StageSig PrevStage> {
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
revFlowThroughArg(call, arg, state, returnCtx, returnAp, ap, config)
)
}
@@ -1967,8 +1946,9 @@ private module MkStage<StageSig PrevStage> {
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
tuples =
count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
count(NodeEx n, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap |
fwdFlow(n, state, cc, summaryCtx, argAp, ap, config)
)
or
fwd = false and
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
@@ -2823,13 +2803,12 @@ private Configuration unbindConf(Configuration conf) {
pragma[nomagic]
private predicate nodeMayUseSummary0(
NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
Configuration config
NodeEx n, ParamNodeEx p, FlowState state, AccessPathApprox apa, Configuration config
) {
exists(AccessPathApprox apa0 |
c = n.getEnclosingCallable() and
Stage5::parameterMayFlowThrough(p, _, _) and
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParamNodeSome(p.asNode()),
TAccessPathApproxSome(apa), apa0, config)
)
}
@@ -2838,10 +2817,9 @@ pragma[nomagic]
private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) {
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
exists(ParamNodeEx p |
Stage5::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos)
nodeMayUseSummary0(n, p, state, apa, config)
)
}
@@ -3771,8 +3749,8 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap,
AccessPathApprox apa, Configuration config
) {
exists(PathNodeMid mid, RetNodeEx ret |
pathNode(mid, ret, state, cc, sc, ap, config, _) and
exists(RetNodeEx ret |
pathNode(_, ret, state, cc, sc, ap, config, _) and
kind = ret.getKind() and
apa = ap.getApprox() and
parameterFlowThroughAllowed(sc.getParamNode(), kind)
@@ -4234,17 +4212,15 @@ private module FlowExploration {
ap = TRevPartialNil() and
exists(config.explorationLimit())
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
not clearsContentEx(node, ap.getHead()) and
(
notExpectsContent(node) or
expectsContentEx(node, ap.getHead())
) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
)
revPartialPathStep(_, node, state, sc1, sc2, sc3, ap, config) and
not clearsContentEx(node, ap.getHead()) and
(
notExpectsContent(node) or
expectsContentEx(node, ap.getHead())
) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
}
pragma[nomagic]
@@ -4252,19 +4228,17 @@ private module FlowExploration {
NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
TSummaryCtx3 sc3, PartialAccessPath ap, Configuration config
) {
exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
not clearsContentEx(node, ap.getHead().getContent()) and
(
notExpectsContent(node) or
expectsContentEx(node, ap.getHead().getContent())
) and
if node.asNode() instanceof CastingNode
then compatibleTypes(node.getDataFlowType(), ap.getType())
else any()
)
partialPathStep(_, node, state, cc, sc1, sc2, sc3, ap, config) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
not clearsContentEx(node, ap.getHead().getContent()) and
(
notExpectsContent(node) or
expectsContentEx(node, ap.getHead().getContent())
) and
if node.asNode() instanceof CastingNode
then compatibleTypes(node.getDataFlowType(), ap.getType())
else any()
}
/**

View File

@@ -622,7 +622,11 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
}
private module Stage1 implements StageSig {
class Ap = Unit;
class Ap extends int {
// workaround for bad functionality-induced joins (happens when using `Unit`)
pragma[nomagic]
Ap() { this in [0 .. 1] and this < 1 }
}
private class Cc = boolean;
@@ -872,9 +876,9 @@ private module Stage1 implements StageSig {
pragma[nomagic]
private predicate revFlowOut(ReturnPosition pos, Configuration config) {
exists(DataFlowCall call, NodeEx out |
exists(NodeEx out |
revFlow(out, _, config) and
viableReturnPosOutNodeCandFwd1(call, pos, out, config)
viableReturnPosOutNodeCandFwd1(_, pos, out, config)
)
}
@@ -1327,8 +1331,8 @@ private module MkStage<StageSig PrevStage> {
*/
pragma[nomagic]
additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, ApApprox apa, Configuration config
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
ApApprox apa, Configuration config
) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
PrevStage::revFlow(node, state, apa, config) and
@@ -1337,21 +1341,21 @@ private module MkStage<StageSig PrevStage> {
pragma[inline]
additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
Configuration config
) {
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
}
pragma[nomagic]
private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, ApApprox apa, Configuration config
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
ApApprox apa, Configuration config
) {
sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and
summaryCtx = TParameterPositionNone() and
summaryCtx = TParamNodeNone() and
ap = getApNil(node) and
apa = getApprox(ap)
or
@@ -1372,7 +1376,7 @@ private module MkStage<StageSig PrevStage> {
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
summaryCtx = TParamNodeNone() and
argAp = apNone()
)
or
@@ -1380,7 +1384,7 @@ private module MkStage<StageSig PrevStage> {
fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
summaryCtx = TParamNodeNone() and
argAp = apNone() and
ap = getApNil(node) and
apa = getApprox(ap)
@@ -1390,7 +1394,7 @@ private module MkStage<StageSig PrevStage> {
fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStateStep(mid, state0, node, state, config) and
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
summaryCtx = TParamNodeNone() and
argAp = apNone() and
ap = getApNil(node) and
apa = getApprox(ap)
@@ -1414,10 +1418,10 @@ private module MkStage<StageSig PrevStage> {
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
if PrevStage::parameterMayFlowThrough(node, apa, config)
then (
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
summaryCtx = TParamNodeSome(node.asNode()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
summaryCtx = TParamNodeNone() and argAp = apNone()
)
or
// flow out of a callable
@@ -1433,16 +1437,19 @@ private module MkStage<StageSig PrevStage> {
)
or
// flow through a callable
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
exists(
DataFlowCall call, CcCall ccc, RetNodeEx ret, boolean allowsFieldFlow, ApApprox innerArgApa
|
fwdFlowThrough(call, cc, state, ccc, summaryCtx, argAp, ap, apa, ret, innerArgApa, config) and
flowThroughOutOfCall(call, ccc, ret, node, allowsFieldFlow, innerArgApa, apa, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
pragma[nomagic]
private predicate fwdFlowStore(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType, ApApprox apa1 |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
@@ -1473,8 +1480,8 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate fwdFlowRead0(
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ApNonNil ap, Configuration config
NodeEx node1, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, ApNonNil ap,
Configuration config
) {
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, _, _, config)
@@ -1483,7 +1490,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
) {
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and
@@ -1493,7 +1500,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
ParamNodeOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
) {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
@@ -1505,64 +1512,38 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate fwdFlowRetFromArg(
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
RetNodeEx ret, FlowState state, CcCall ccc, ParamNodeEx summaryCtx, Ap argAp, ApApprox argApa,
Ap ap, ApApprox apa, Configuration config
) {
exists(DataFlowCallable c, ReturnKindExt kind |
exists(ReturnKindExt kind |
fwdFlow(pragma[only_bind_into](ret), state, ccc,
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
getApprox(argAp) = argApa and
c = ret.getEnclosingCallable() and
TParamNodeSome(pragma[only_bind_into](summaryCtx.asNode())),
pragma[only_bind_into](apSome(argAp)), ap, pragma[only_bind_into](apa),
pragma[only_bind_into](config)) and
kind = ret.getKind() and
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
parameterFlowThroughAllowed(p, kind)
parameterFlowThroughAllowed(summaryCtx, kind) and
argApa = getApprox(argAp) and
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config))
)
}
pragma[inline]
private predicate fwdFlowInMayFlowThrough(
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
private predicate fwdFlowThrough0(
DataFlowCall call, Cc cc, FlowState state, CcCall ccc, ParamNodeOption summaryCtx,
ApOption argAp, Ap ap, ApApprox apa, RetNodeEx ret, ParamNodeEx innerSummaryCtx,
Ap innerArgAp, ApApprox innerArgApa, Configuration config
) {
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(param, apa, config)
}
// dedup before joining with `flowThroughOutOfCall`
pragma[nomagic]
private predicate fwdFlowInMayFlowThroughProj(
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
}
/**
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
* in the flow covered by `fwdFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate fwdFlowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
ApApprox argApa, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
fwdFlowRetFromArg(ret, state, ccc, innerSummaryCtx, innerArgAp, innerArgApa, ap, apa, config) and
fwdFlowIsEntered(call, cc, ccc, summaryCtx, argAp, innerSummaryCtx, innerArgAp, config)
}
pragma[nomagic]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
ApApprox apa, Configuration config
private predicate fwdFlowThrough(
DataFlowCall call, Cc cc, FlowState state, CcCall ccc, ParamNodeOption summaryCtx,
ApOption argAp, Ap ap, ApApprox apa, RetNodeEx ret, ApApprox innerArgApa, Configuration config
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
config) and
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
)
fwdFlowThrough0(call, cc, state, ccc, summaryCtx, argAp, ap, apa, ret, _, _, innerArgApa,
config)
}
/**
@@ -1571,12 +1552,14 @@ private module MkStage<StageSig PrevStage> {
*/
pragma[nomagic]
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ParameterPosition pos, Ap ap, Configuration config
DataFlowCall call, Cc cc, CcCall innerCc, ParamNodeOption summaryCtx, ApOption argAp,
ParamNodeEx p, Ap ap, Configuration config
) {
exists(ParamNodeEx param |
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
pos = param.getPosition()
exists(ApApprox apa |
fwdFlowIn(call, pragma[only_bind_into](p), _, cc, innerCc, summaryCtx, argAp, ap,
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(p, apa, config) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config))
)
}
@@ -1596,23 +1579,31 @@ private module MkStage<StageSig PrevStage> {
fwdFlowConsCand(ap1, c, ap2, config)
}
pragma[nomagic]
private predicate returnFlowsThrough0(
DataFlowCall call, FlowState state, CcCall ccc, Ap ap, ApApprox apa, RetNodeEx ret,
ParamNodeEx innerSummaryCtx, Ap innerArgAp, ApApprox innerArgApa, Configuration config
) {
fwdFlowThrough0(call, _, state, ccc, _, _, ap, apa, ret, innerSummaryCtx, innerArgAp,
innerArgApa, config)
}
pragma[nomagic]
private predicate returnFlowsThrough(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
RetNodeEx ret, ReturnPosition pos, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
Ap ap, Configuration config
) {
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
kind = ret.getKind() and
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
exists(DataFlowCall call, ApApprox apa, boolean allowsFieldFlow, ApApprox innerArgApa |
returnFlowsThrough0(call, state, ccc, ap, apa, ret, p, argAp, innerArgApa, config) and
flowThroughOutOfCall(call, ccc, ret, _, allowsFieldFlow, innerArgApa, apa, config) and
pos = ret.getReturnPosition() and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
pragma[nomagic]
private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp, Ap ap,
Configuration config
) {
exists(ApApprox argApa |
@@ -1620,7 +1611,7 @@ private module MkStage<StageSig PrevStage> {
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
pragma[only_bind_into](config)) and
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), ap,
pragma[only_bind_into](config)) and
if allowsFieldFlow = false then argAp instanceof ApNil else any()
)
@@ -1639,12 +1630,13 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate flowOutOfCallAp(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, NodeEx out, boolean allowsFieldFlow,
Ap ap, Configuration config
) {
exists(ApApprox apa |
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
fwdFlow(ret, _, _, _, _, ap, apa, config)
flowOutOfCallApa(call, ret, _, out, allowsFieldFlow, apa, config) and
fwdFlow(ret, _, _, _, _, ap, apa, config) and
pos = ret.getReturnPosition()
)
}
@@ -1739,17 +1731,17 @@ private module MkStage<StageSig PrevStage> {
)
or
// flow through a callable
exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
exists(DataFlowCall call, ParamNodeEx p, Ap innerReturnAp |
revFlowThrough(call, returnCtx, p, state, _, returnAp, ap, innerReturnAp, config) and
flowThroughIntoCall(call, node, p, _, ap, innerReturnAp, config)
)
or
// flow out of a callable
exists(ReturnKindExt kind |
revFlowOut(_, node, kind, state, _, _, ap, config) and
if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
exists(ReturnPosition pos |
revFlowOut(_, node, pos, state, _, _, ap, config) and
if returnFlowsThrough(node, pos, state, _, _, _, ap, config)
then (
returnCtx = TReturnCtxMaybeFlowThrough(kind) and
returnCtx = TReturnCtxMaybeFlowThrough(pos) and
returnAp = apSome(ap)
) else (
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
@@ -1782,47 +1774,33 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate revFlowOut(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, FlowState state, ReturnCtx returnCtx,
ApOption returnAp, Ap ap, Configuration config
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
flowOutOfCallAp(call, ret, pos, out, allowsFieldFlow, ap, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
/**
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
* in the flow covered by `revFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate revFlowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
Configuration config
) {
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
revFlowIsReturned(call, _, _, _, _, config)
}
pragma[nomagic]
private predicate revFlowParamToReturn(
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
ParamNodeEx p, FlowState state, ReturnPosition pos, Ap returnAp, Ap ap, Configuration config
) {
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind)
revFlow(pragma[only_bind_into](p), state, TReturnCtxMaybeFlowThrough(pos), apSome(returnAp),
pragma[only_bind_into](ap), pragma[only_bind_into](config)) and
parameterFlowThroughAllowed(p, pos.getKind()) and
PrevStage::parameterMayFlowThrough(p, getApprox(ap), config)
}
pragma[nomagic]
private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
Configuration config
private predicate revFlowThrough(
DataFlowCall call, ReturnCtx returnCtx, ParamNodeEx p, FlowState state, ReturnPosition pos,
ApOption returnAp, Ap ap, Ap innerReturnAp, Configuration config
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
)
revFlowParamToReturn(p, state, pos, innerReturnAp, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, pos, innerReturnAp, config)
}
/**
@@ -1832,12 +1810,12 @@ private module MkStage<StageSig PrevStage> {
*/
pragma[nomagic]
private predicate revFlowIsReturned(
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnPosition pos, Ap ap,
Configuration config
) {
exists(RetNodeEx ret, FlowState state, CcCall ccc |
revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
revFlowOut(call, ret, pos, state, returnCtx, returnAp, ap, config) and
returnFlowsThrough(ret, pos, state, ccc, _, _, ap, config) and
matchesCall(ccc, call)
)
}
@@ -1915,17 +1893,17 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
ParamNodeEx p, Ap ap, ReturnPosition pos, Ap returnAp, Configuration config
) {
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind)
revFlow(p, _, TReturnCtxMaybeFlowThrough(pos), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, pos.getKind())
}
pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(RetNodeEx ret, ReturnKindExt kind |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, _, config)
exists(ReturnPosition pos |
returnFlowsThrough(_, pos, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, pos, _, config)
)
}
@@ -1933,20 +1911,21 @@ private module MkStage<StageSig PrevStage> {
predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
) {
exists(ParamNodeEx p |
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
parameterFlowsThroughRev(p, argAp, kind, ap, config)
exists(ParamNodeEx p, ReturnPosition pos |
returnFlowsThrough(ret, pos, _, _, p, argAp, ap, config) and
parameterFlowsThroughRev(p, argAp, pos, ap, config) and
kind = pos.getKind()
)
}
pragma[nomagic]
predicate revFlowInToReturnIsReturned(
private predicate revFlowThroughArg(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
Ap ap, Configuration config
) {
exists(ReturnKindExt returnKind0, Ap returnAp0 |
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
exists(ParamNodeEx p, Ap innerReturnAp |
revFlowThrough(call, returnCtx, p, state, _, returnAp, ap, innerReturnAp, config) and
flowThroughIntoCall(call, arg, p, _, ap, innerReturnAp, config)
)
}
@@ -1954,7 +1933,7 @@ private module MkStage<StageSig PrevStage> {
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
revFlowThroughArg(call, arg, state, returnCtx, returnAp, ap, config)
)
}
@@ -1967,8 +1946,9 @@ private module MkStage<StageSig PrevStage> {
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
tuples =
count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
count(NodeEx n, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap |
fwdFlow(n, state, cc, summaryCtx, argAp, ap, config)
)
or
fwd = false and
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
@@ -2823,13 +2803,12 @@ private Configuration unbindConf(Configuration conf) {
pragma[nomagic]
private predicate nodeMayUseSummary0(
NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
Configuration config
NodeEx n, ParamNodeEx p, FlowState state, AccessPathApprox apa, Configuration config
) {
exists(AccessPathApprox apa0 |
c = n.getEnclosingCallable() and
Stage5::parameterMayFlowThrough(p, _, _) and
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParamNodeSome(p.asNode()),
TAccessPathApproxSome(apa), apa0, config)
)
}
@@ -2838,10 +2817,9 @@ pragma[nomagic]
private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) {
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
exists(ParamNodeEx p |
Stage5::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos)
nodeMayUseSummary0(n, p, state, apa, config)
)
}
@@ -3771,8 +3749,8 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap,
AccessPathApprox apa, Configuration config
) {
exists(PathNodeMid mid, RetNodeEx ret |
pathNode(mid, ret, state, cc, sc, ap, config, _) and
exists(RetNodeEx ret |
pathNode(_, ret, state, cc, sc, ap, config, _) and
kind = ret.getKind() and
apa = ap.getApprox() and
parameterFlowThroughAllowed(sc.getParamNode(), kind)
@@ -4234,17 +4212,15 @@ private module FlowExploration {
ap = TRevPartialNil() and
exists(config.explorationLimit())
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
not clearsContentEx(node, ap.getHead()) and
(
notExpectsContent(node) or
expectsContentEx(node, ap.getHead())
) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
)
revPartialPathStep(_, node, state, sc1, sc2, sc3, ap, config) and
not clearsContentEx(node, ap.getHead()) and
(
notExpectsContent(node) or
expectsContentEx(node, ap.getHead())
) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
}
pragma[nomagic]
@@ -4252,19 +4228,17 @@ private module FlowExploration {
NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
TSummaryCtx3 sc3, PartialAccessPath ap, Configuration config
) {
exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
not clearsContentEx(node, ap.getHead().getContent()) and
(
notExpectsContent(node) or
expectsContentEx(node, ap.getHead().getContent())
) and
if node.asNode() instanceof CastingNode
then compatibleTypes(node.getDataFlowType(), ap.getType())
else any()
)
partialPathStep(_, node, state, cc, sc1, sc2, sc3, ap, config) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
not clearsContentEx(node, ap.getHead().getContent()) and
(
notExpectsContent(node) or
expectsContentEx(node, ap.getHead().getContent())
) and
if node.asNode() instanceof CastingNode
then compatibleTypes(node.getDataFlowType(), ap.getType())
else any()
}
/**

View File

@@ -622,7 +622,11 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
}
private module Stage1 implements StageSig {
class Ap = Unit;
class Ap extends int {
// workaround for bad functionality-induced joins (happens when using `Unit`)
pragma[nomagic]
Ap() { this in [0 .. 1] and this < 1 }
}
private class Cc = boolean;
@@ -872,9 +876,9 @@ private module Stage1 implements StageSig {
pragma[nomagic]
private predicate revFlowOut(ReturnPosition pos, Configuration config) {
exists(DataFlowCall call, NodeEx out |
exists(NodeEx out |
revFlow(out, _, config) and
viableReturnPosOutNodeCandFwd1(call, pos, out, config)
viableReturnPosOutNodeCandFwd1(_, pos, out, config)
)
}
@@ -1327,8 +1331,8 @@ private module MkStage<StageSig PrevStage> {
*/
pragma[nomagic]
additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, ApApprox apa, Configuration config
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
ApApprox apa, Configuration config
) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
PrevStage::revFlow(node, state, apa, config) and
@@ -1337,21 +1341,21 @@ private module MkStage<StageSig PrevStage> {
pragma[inline]
additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
Configuration config
) {
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
}
pragma[nomagic]
private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, ApApprox apa, Configuration config
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
ApApprox apa, Configuration config
) {
sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and
summaryCtx = TParameterPositionNone() and
summaryCtx = TParamNodeNone() and
ap = getApNil(node) and
apa = getApprox(ap)
or
@@ -1372,7 +1376,7 @@ private module MkStage<StageSig PrevStage> {
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
summaryCtx = TParamNodeNone() and
argAp = apNone()
)
or
@@ -1380,7 +1384,7 @@ private module MkStage<StageSig PrevStage> {
fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
summaryCtx = TParamNodeNone() and
argAp = apNone() and
ap = getApNil(node) and
apa = getApprox(ap)
@@ -1390,7 +1394,7 @@ private module MkStage<StageSig PrevStage> {
fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStateStep(mid, state0, node, state, config) and
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
summaryCtx = TParamNodeNone() and
argAp = apNone() and
ap = getApNil(node) and
apa = getApprox(ap)
@@ -1414,10 +1418,10 @@ private module MkStage<StageSig PrevStage> {
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
if PrevStage::parameterMayFlowThrough(node, apa, config)
then (
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
summaryCtx = TParamNodeSome(node.asNode()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
summaryCtx = TParamNodeNone() and argAp = apNone()
)
or
// flow out of a callable
@@ -1433,16 +1437,19 @@ private module MkStage<StageSig PrevStage> {
)
or
// flow through a callable
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
exists(
DataFlowCall call, CcCall ccc, RetNodeEx ret, boolean allowsFieldFlow, ApApprox innerArgApa
|
fwdFlowThrough(call, cc, state, ccc, summaryCtx, argAp, ap, apa, ret, innerArgApa, config) and
flowThroughOutOfCall(call, ccc, ret, node, allowsFieldFlow, innerArgApa, apa, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
pragma[nomagic]
private predicate fwdFlowStore(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType, ApApprox apa1 |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
@@ -1473,8 +1480,8 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate fwdFlowRead0(
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ApNonNil ap, Configuration config
NodeEx node1, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, ApNonNil ap,
Configuration config
) {
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, _, _, config)
@@ -1483,7 +1490,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
) {
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and
@@ -1493,7 +1500,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
ParamNodeOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
) {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
@@ -1505,64 +1512,38 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate fwdFlowRetFromArg(
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
RetNodeEx ret, FlowState state, CcCall ccc, ParamNodeEx summaryCtx, Ap argAp, ApApprox argApa,
Ap ap, ApApprox apa, Configuration config
) {
exists(DataFlowCallable c, ReturnKindExt kind |
exists(ReturnKindExt kind |
fwdFlow(pragma[only_bind_into](ret), state, ccc,
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
getApprox(argAp) = argApa and
c = ret.getEnclosingCallable() and
TParamNodeSome(pragma[only_bind_into](summaryCtx.asNode())),
pragma[only_bind_into](apSome(argAp)), ap, pragma[only_bind_into](apa),
pragma[only_bind_into](config)) and
kind = ret.getKind() and
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
parameterFlowThroughAllowed(p, kind)
parameterFlowThroughAllowed(summaryCtx, kind) and
argApa = getApprox(argAp) and
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config))
)
}
pragma[inline]
private predicate fwdFlowInMayFlowThrough(
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
private predicate fwdFlowThrough0(
DataFlowCall call, Cc cc, FlowState state, CcCall ccc, ParamNodeOption summaryCtx,
ApOption argAp, Ap ap, ApApprox apa, RetNodeEx ret, ParamNodeEx innerSummaryCtx,
Ap innerArgAp, ApApprox innerArgApa, Configuration config
) {
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(param, apa, config)
}
// dedup before joining with `flowThroughOutOfCall`
pragma[nomagic]
private predicate fwdFlowInMayFlowThroughProj(
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
}
/**
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
* in the flow covered by `fwdFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate fwdFlowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
ApApprox argApa, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
fwdFlowRetFromArg(ret, state, ccc, innerSummaryCtx, innerArgAp, innerArgApa, ap, apa, config) and
fwdFlowIsEntered(call, cc, ccc, summaryCtx, argAp, innerSummaryCtx, innerArgAp, config)
}
pragma[nomagic]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
ApApprox apa, Configuration config
private predicate fwdFlowThrough(
DataFlowCall call, Cc cc, FlowState state, CcCall ccc, ParamNodeOption summaryCtx,
ApOption argAp, Ap ap, ApApprox apa, RetNodeEx ret, ApApprox innerArgApa, Configuration config
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
config) and
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
)
fwdFlowThrough0(call, cc, state, ccc, summaryCtx, argAp, ap, apa, ret, _, _, innerArgApa,
config)
}
/**
@@ -1571,12 +1552,14 @@ private module MkStage<StageSig PrevStage> {
*/
pragma[nomagic]
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ParameterPosition pos, Ap ap, Configuration config
DataFlowCall call, Cc cc, CcCall innerCc, ParamNodeOption summaryCtx, ApOption argAp,
ParamNodeEx p, Ap ap, Configuration config
) {
exists(ParamNodeEx param |
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
pos = param.getPosition()
exists(ApApprox apa |
fwdFlowIn(call, pragma[only_bind_into](p), _, cc, innerCc, summaryCtx, argAp, ap,
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(p, apa, config) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config))
)
}
@@ -1596,23 +1579,31 @@ private module MkStage<StageSig PrevStage> {
fwdFlowConsCand(ap1, c, ap2, config)
}
pragma[nomagic]
private predicate returnFlowsThrough0(
DataFlowCall call, FlowState state, CcCall ccc, Ap ap, ApApprox apa, RetNodeEx ret,
ParamNodeEx innerSummaryCtx, Ap innerArgAp, ApApprox innerArgApa, Configuration config
) {
fwdFlowThrough0(call, _, state, ccc, _, _, ap, apa, ret, innerSummaryCtx, innerArgAp,
innerArgApa, config)
}
pragma[nomagic]
private predicate returnFlowsThrough(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
RetNodeEx ret, ReturnPosition pos, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
Ap ap, Configuration config
) {
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
kind = ret.getKind() and
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
exists(DataFlowCall call, ApApprox apa, boolean allowsFieldFlow, ApApprox innerArgApa |
returnFlowsThrough0(call, state, ccc, ap, apa, ret, p, argAp, innerArgApa, config) and
flowThroughOutOfCall(call, ccc, ret, _, allowsFieldFlow, innerArgApa, apa, config) and
pos = ret.getReturnPosition() and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
pragma[nomagic]
private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp, Ap ap,
Configuration config
) {
exists(ApApprox argApa |
@@ -1620,7 +1611,7 @@ private module MkStage<StageSig PrevStage> {
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
pragma[only_bind_into](config)) and
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), ap,
pragma[only_bind_into](config)) and
if allowsFieldFlow = false then argAp instanceof ApNil else any()
)
@@ -1639,12 +1630,13 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate flowOutOfCallAp(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, NodeEx out, boolean allowsFieldFlow,
Ap ap, Configuration config
) {
exists(ApApprox apa |
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
fwdFlow(ret, _, _, _, _, ap, apa, config)
flowOutOfCallApa(call, ret, _, out, allowsFieldFlow, apa, config) and
fwdFlow(ret, _, _, _, _, ap, apa, config) and
pos = ret.getReturnPosition()
)
}
@@ -1739,17 +1731,17 @@ private module MkStage<StageSig PrevStage> {
)
or
// flow through a callable
exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
exists(DataFlowCall call, ParamNodeEx p, Ap innerReturnAp |
revFlowThrough(call, returnCtx, p, state, _, returnAp, ap, innerReturnAp, config) and
flowThroughIntoCall(call, node, p, _, ap, innerReturnAp, config)
)
or
// flow out of a callable
exists(ReturnKindExt kind |
revFlowOut(_, node, kind, state, _, _, ap, config) and
if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
exists(ReturnPosition pos |
revFlowOut(_, node, pos, state, _, _, ap, config) and
if returnFlowsThrough(node, pos, state, _, _, _, ap, config)
then (
returnCtx = TReturnCtxMaybeFlowThrough(kind) and
returnCtx = TReturnCtxMaybeFlowThrough(pos) and
returnAp = apSome(ap)
) else (
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
@@ -1782,47 +1774,33 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate revFlowOut(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, FlowState state, ReturnCtx returnCtx,
ApOption returnAp, Ap ap, Configuration config
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
flowOutOfCallAp(call, ret, pos, out, allowsFieldFlow, ap, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
/**
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
* in the flow covered by `revFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate revFlowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
Configuration config
) {
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
revFlowIsReturned(call, _, _, _, _, config)
}
pragma[nomagic]
private predicate revFlowParamToReturn(
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
ParamNodeEx p, FlowState state, ReturnPosition pos, Ap returnAp, Ap ap, Configuration config
) {
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind)
revFlow(pragma[only_bind_into](p), state, TReturnCtxMaybeFlowThrough(pos), apSome(returnAp),
pragma[only_bind_into](ap), pragma[only_bind_into](config)) and
parameterFlowThroughAllowed(p, pos.getKind()) and
PrevStage::parameterMayFlowThrough(p, getApprox(ap), config)
}
pragma[nomagic]
private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
Configuration config
private predicate revFlowThrough(
DataFlowCall call, ReturnCtx returnCtx, ParamNodeEx p, FlowState state, ReturnPosition pos,
ApOption returnAp, Ap ap, Ap innerReturnAp, Configuration config
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
)
revFlowParamToReturn(p, state, pos, innerReturnAp, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, pos, innerReturnAp, config)
}
/**
@@ -1832,12 +1810,12 @@ private module MkStage<StageSig PrevStage> {
*/
pragma[nomagic]
private predicate revFlowIsReturned(
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnPosition pos, Ap ap,
Configuration config
) {
exists(RetNodeEx ret, FlowState state, CcCall ccc |
revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
revFlowOut(call, ret, pos, state, returnCtx, returnAp, ap, config) and
returnFlowsThrough(ret, pos, state, ccc, _, _, ap, config) and
matchesCall(ccc, call)
)
}
@@ -1915,17 +1893,17 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
ParamNodeEx p, Ap ap, ReturnPosition pos, Ap returnAp, Configuration config
) {
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind)
revFlow(p, _, TReturnCtxMaybeFlowThrough(pos), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, pos.getKind())
}
pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(RetNodeEx ret, ReturnKindExt kind |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, _, config)
exists(ReturnPosition pos |
returnFlowsThrough(_, pos, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, pos, _, config)
)
}
@@ -1933,20 +1911,21 @@ private module MkStage<StageSig PrevStage> {
predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
) {
exists(ParamNodeEx p |
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
parameterFlowsThroughRev(p, argAp, kind, ap, config)
exists(ParamNodeEx p, ReturnPosition pos |
returnFlowsThrough(ret, pos, _, _, p, argAp, ap, config) and
parameterFlowsThroughRev(p, argAp, pos, ap, config) and
kind = pos.getKind()
)
}
pragma[nomagic]
predicate revFlowInToReturnIsReturned(
private predicate revFlowThroughArg(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
Ap ap, Configuration config
) {
exists(ReturnKindExt returnKind0, Ap returnAp0 |
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
exists(ParamNodeEx p, Ap innerReturnAp |
revFlowThrough(call, returnCtx, p, state, _, returnAp, ap, innerReturnAp, config) and
flowThroughIntoCall(call, arg, p, _, ap, innerReturnAp, config)
)
}
@@ -1954,7 +1933,7 @@ private module MkStage<StageSig PrevStage> {
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
revFlowThroughArg(call, arg, state, returnCtx, returnAp, ap, config)
)
}
@@ -1967,8 +1946,9 @@ private module MkStage<StageSig PrevStage> {
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
tuples =
count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
count(NodeEx n, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap |
fwdFlow(n, state, cc, summaryCtx, argAp, ap, config)
)
or
fwd = false and
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
@@ -2823,13 +2803,12 @@ private Configuration unbindConf(Configuration conf) {
pragma[nomagic]
private predicate nodeMayUseSummary0(
NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
Configuration config
NodeEx n, ParamNodeEx p, FlowState state, AccessPathApprox apa, Configuration config
) {
exists(AccessPathApprox apa0 |
c = n.getEnclosingCallable() and
Stage5::parameterMayFlowThrough(p, _, _) and
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParamNodeSome(p.asNode()),
TAccessPathApproxSome(apa), apa0, config)
)
}
@@ -2838,10 +2817,9 @@ pragma[nomagic]
private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) {
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
exists(ParamNodeEx p |
Stage5::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos)
nodeMayUseSummary0(n, p, state, apa, config)
)
}
@@ -3771,8 +3749,8 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap,
AccessPathApprox apa, Configuration config
) {
exists(PathNodeMid mid, RetNodeEx ret |
pathNode(mid, ret, state, cc, sc, ap, config, _) and
exists(RetNodeEx ret |
pathNode(_, ret, state, cc, sc, ap, config, _) and
kind = ret.getKind() and
apa = ap.getApprox() and
parameterFlowThroughAllowed(sc.getParamNode(), kind)
@@ -4234,17 +4212,15 @@ private module FlowExploration {
ap = TRevPartialNil() and
exists(config.explorationLimit())
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
not clearsContentEx(node, ap.getHead()) and
(
notExpectsContent(node) or
expectsContentEx(node, ap.getHead())
) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
)
revPartialPathStep(_, node, state, sc1, sc2, sc3, ap, config) and
not clearsContentEx(node, ap.getHead()) and
(
notExpectsContent(node) or
expectsContentEx(node, ap.getHead())
) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
}
pragma[nomagic]
@@ -4252,19 +4228,17 @@ private module FlowExploration {
NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
TSummaryCtx3 sc3, PartialAccessPath ap, Configuration config
) {
exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
not clearsContentEx(node, ap.getHead().getContent()) and
(
notExpectsContent(node) or
expectsContentEx(node, ap.getHead().getContent())
) and
if node.asNode() instanceof CastingNode
then compatibleTypes(node.getDataFlowType(), ap.getType())
else any()
)
partialPathStep(_, node, state, cc, sc1, sc2, sc3, ap, config) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
not clearsContentEx(node, ap.getHead().getContent()) and
(
notExpectsContent(node) or
expectsContentEx(node, ap.getHead().getContent())
) and
if node.asNode() instanceof CastingNode
then compatibleTypes(node.getDataFlowType(), ap.getType())
else any()
}
/**

View File

@@ -622,7 +622,11 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
}
private module Stage1 implements StageSig {
class Ap = Unit;
class Ap extends int {
// workaround for bad functionality-induced joins (happens when using `Unit`)
pragma[nomagic]
Ap() { this in [0 .. 1] and this < 1 }
}
private class Cc = boolean;
@@ -872,9 +876,9 @@ private module Stage1 implements StageSig {
pragma[nomagic]
private predicate revFlowOut(ReturnPosition pos, Configuration config) {
exists(DataFlowCall call, NodeEx out |
exists(NodeEx out |
revFlow(out, _, config) and
viableReturnPosOutNodeCandFwd1(call, pos, out, config)
viableReturnPosOutNodeCandFwd1(_, pos, out, config)
)
}
@@ -1327,8 +1331,8 @@ private module MkStage<StageSig PrevStage> {
*/
pragma[nomagic]
additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, ApApprox apa, Configuration config
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
ApApprox apa, Configuration config
) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
PrevStage::revFlow(node, state, apa, config) and
@@ -1337,21 +1341,21 @@ private module MkStage<StageSig PrevStage> {
pragma[inline]
additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
Configuration config
) {
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
}
pragma[nomagic]
private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, ApApprox apa, Configuration config
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
ApApprox apa, Configuration config
) {
sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and
summaryCtx = TParameterPositionNone() and
summaryCtx = TParamNodeNone() and
ap = getApNil(node) and
apa = getApprox(ap)
or
@@ -1372,7 +1376,7 @@ private module MkStage<StageSig PrevStage> {
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
summaryCtx = TParamNodeNone() and
argAp = apNone()
)
or
@@ -1380,7 +1384,7 @@ private module MkStage<StageSig PrevStage> {
fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
summaryCtx = TParamNodeNone() and
argAp = apNone() and
ap = getApNil(node) and
apa = getApprox(ap)
@@ -1390,7 +1394,7 @@ private module MkStage<StageSig PrevStage> {
fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStateStep(mid, state0, node, state, config) and
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
summaryCtx = TParamNodeNone() and
argAp = apNone() and
ap = getApNil(node) and
apa = getApprox(ap)
@@ -1414,10 +1418,10 @@ private module MkStage<StageSig PrevStage> {
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
if PrevStage::parameterMayFlowThrough(node, apa, config)
then (
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
summaryCtx = TParamNodeSome(node.asNode()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
summaryCtx = TParamNodeNone() and argAp = apNone()
)
or
// flow out of a callable
@@ -1433,16 +1437,19 @@ private module MkStage<StageSig PrevStage> {
)
or
// flow through a callable
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
exists(
DataFlowCall call, CcCall ccc, RetNodeEx ret, boolean allowsFieldFlow, ApApprox innerArgApa
|
fwdFlowThrough(call, cc, state, ccc, summaryCtx, argAp, ap, apa, ret, innerArgApa, config) and
flowThroughOutOfCall(call, ccc, ret, node, allowsFieldFlow, innerArgApa, apa, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
pragma[nomagic]
private predicate fwdFlowStore(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType, ApApprox apa1 |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
@@ -1473,8 +1480,8 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate fwdFlowRead0(
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ApNonNil ap, Configuration config
NodeEx node1, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, ApNonNil ap,
Configuration config
) {
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, _, _, config)
@@ -1483,7 +1490,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
) {
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and
@@ -1493,7 +1500,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
ParamNodeOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
) {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
@@ -1505,64 +1512,38 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate fwdFlowRetFromArg(
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
RetNodeEx ret, FlowState state, CcCall ccc, ParamNodeEx summaryCtx, Ap argAp, ApApprox argApa,
Ap ap, ApApprox apa, Configuration config
) {
exists(DataFlowCallable c, ReturnKindExt kind |
exists(ReturnKindExt kind |
fwdFlow(pragma[only_bind_into](ret), state, ccc,
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
getApprox(argAp) = argApa and
c = ret.getEnclosingCallable() and
TParamNodeSome(pragma[only_bind_into](summaryCtx.asNode())),
pragma[only_bind_into](apSome(argAp)), ap, pragma[only_bind_into](apa),
pragma[only_bind_into](config)) and
kind = ret.getKind() and
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
parameterFlowThroughAllowed(p, kind)
parameterFlowThroughAllowed(summaryCtx, kind) and
argApa = getApprox(argAp) and
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config))
)
}
pragma[inline]
private predicate fwdFlowInMayFlowThrough(
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
private predicate fwdFlowThrough0(
DataFlowCall call, Cc cc, FlowState state, CcCall ccc, ParamNodeOption summaryCtx,
ApOption argAp, Ap ap, ApApprox apa, RetNodeEx ret, ParamNodeEx innerSummaryCtx,
Ap innerArgAp, ApApprox innerArgApa, Configuration config
) {
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(param, apa, config)
}
// dedup before joining with `flowThroughOutOfCall`
pragma[nomagic]
private predicate fwdFlowInMayFlowThroughProj(
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
}
/**
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
* in the flow covered by `fwdFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate fwdFlowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
ApApprox argApa, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
fwdFlowRetFromArg(ret, state, ccc, innerSummaryCtx, innerArgAp, innerArgApa, ap, apa, config) and
fwdFlowIsEntered(call, cc, ccc, summaryCtx, argAp, innerSummaryCtx, innerArgAp, config)
}
pragma[nomagic]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
ApApprox apa, Configuration config
private predicate fwdFlowThrough(
DataFlowCall call, Cc cc, FlowState state, CcCall ccc, ParamNodeOption summaryCtx,
ApOption argAp, Ap ap, ApApprox apa, RetNodeEx ret, ApApprox innerArgApa, Configuration config
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
config) and
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
)
fwdFlowThrough0(call, cc, state, ccc, summaryCtx, argAp, ap, apa, ret, _, _, innerArgApa,
config)
}
/**
@@ -1571,12 +1552,14 @@ private module MkStage<StageSig PrevStage> {
*/
pragma[nomagic]
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ParameterPosition pos, Ap ap, Configuration config
DataFlowCall call, Cc cc, CcCall innerCc, ParamNodeOption summaryCtx, ApOption argAp,
ParamNodeEx p, Ap ap, Configuration config
) {
exists(ParamNodeEx param |
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
pos = param.getPosition()
exists(ApApprox apa |
fwdFlowIn(call, pragma[only_bind_into](p), _, cc, innerCc, summaryCtx, argAp, ap,
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(p, apa, config) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config))
)
}
@@ -1596,23 +1579,31 @@ private module MkStage<StageSig PrevStage> {
fwdFlowConsCand(ap1, c, ap2, config)
}
pragma[nomagic]
private predicate returnFlowsThrough0(
DataFlowCall call, FlowState state, CcCall ccc, Ap ap, ApApprox apa, RetNodeEx ret,
ParamNodeEx innerSummaryCtx, Ap innerArgAp, ApApprox innerArgApa, Configuration config
) {
fwdFlowThrough0(call, _, state, ccc, _, _, ap, apa, ret, innerSummaryCtx, innerArgAp,
innerArgApa, config)
}
pragma[nomagic]
private predicate returnFlowsThrough(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
RetNodeEx ret, ReturnPosition pos, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
Ap ap, Configuration config
) {
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
kind = ret.getKind() and
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
exists(DataFlowCall call, ApApprox apa, boolean allowsFieldFlow, ApApprox innerArgApa |
returnFlowsThrough0(call, state, ccc, ap, apa, ret, p, argAp, innerArgApa, config) and
flowThroughOutOfCall(call, ccc, ret, _, allowsFieldFlow, innerArgApa, apa, config) and
pos = ret.getReturnPosition() and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
pragma[nomagic]
private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp, Ap ap,
Configuration config
) {
exists(ApApprox argApa |
@@ -1620,7 +1611,7 @@ private module MkStage<StageSig PrevStage> {
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
pragma[only_bind_into](config)) and
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), ap,
pragma[only_bind_into](config)) and
if allowsFieldFlow = false then argAp instanceof ApNil else any()
)
@@ -1639,12 +1630,13 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate flowOutOfCallAp(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, NodeEx out, boolean allowsFieldFlow,
Ap ap, Configuration config
) {
exists(ApApprox apa |
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
fwdFlow(ret, _, _, _, _, ap, apa, config)
flowOutOfCallApa(call, ret, _, out, allowsFieldFlow, apa, config) and
fwdFlow(ret, _, _, _, _, ap, apa, config) and
pos = ret.getReturnPosition()
)
}
@@ -1739,17 +1731,17 @@ private module MkStage<StageSig PrevStage> {
)
or
// flow through a callable
exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
exists(DataFlowCall call, ParamNodeEx p, Ap innerReturnAp |
revFlowThrough(call, returnCtx, p, state, _, returnAp, ap, innerReturnAp, config) and
flowThroughIntoCall(call, node, p, _, ap, innerReturnAp, config)
)
or
// flow out of a callable
exists(ReturnKindExt kind |
revFlowOut(_, node, kind, state, _, _, ap, config) and
if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
exists(ReturnPosition pos |
revFlowOut(_, node, pos, state, _, _, ap, config) and
if returnFlowsThrough(node, pos, state, _, _, _, ap, config)
then (
returnCtx = TReturnCtxMaybeFlowThrough(kind) and
returnCtx = TReturnCtxMaybeFlowThrough(pos) and
returnAp = apSome(ap)
) else (
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
@@ -1782,47 +1774,33 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate revFlowOut(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, FlowState state, ReturnCtx returnCtx,
ApOption returnAp, Ap ap, Configuration config
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
flowOutOfCallAp(call, ret, pos, out, allowsFieldFlow, ap, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
/**
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
* in the flow covered by `revFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate revFlowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
Configuration config
) {
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
revFlowIsReturned(call, _, _, _, _, config)
}
pragma[nomagic]
private predicate revFlowParamToReturn(
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
ParamNodeEx p, FlowState state, ReturnPosition pos, Ap returnAp, Ap ap, Configuration config
) {
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind)
revFlow(pragma[only_bind_into](p), state, TReturnCtxMaybeFlowThrough(pos), apSome(returnAp),
pragma[only_bind_into](ap), pragma[only_bind_into](config)) and
parameterFlowThroughAllowed(p, pos.getKind()) and
PrevStage::parameterMayFlowThrough(p, getApprox(ap), config)
}
pragma[nomagic]
private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
Configuration config
private predicate revFlowThrough(
DataFlowCall call, ReturnCtx returnCtx, ParamNodeEx p, FlowState state, ReturnPosition pos,
ApOption returnAp, Ap ap, Ap innerReturnAp, Configuration config
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
)
revFlowParamToReturn(p, state, pos, innerReturnAp, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, pos, innerReturnAp, config)
}
/**
@@ -1832,12 +1810,12 @@ private module MkStage<StageSig PrevStage> {
*/
pragma[nomagic]
private predicate revFlowIsReturned(
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnPosition pos, Ap ap,
Configuration config
) {
exists(RetNodeEx ret, FlowState state, CcCall ccc |
revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
revFlowOut(call, ret, pos, state, returnCtx, returnAp, ap, config) and
returnFlowsThrough(ret, pos, state, ccc, _, _, ap, config) and
matchesCall(ccc, call)
)
}
@@ -1915,17 +1893,17 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
ParamNodeEx p, Ap ap, ReturnPosition pos, Ap returnAp, Configuration config
) {
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind)
revFlow(p, _, TReturnCtxMaybeFlowThrough(pos), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, pos.getKind())
}
pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(RetNodeEx ret, ReturnKindExt kind |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, _, config)
exists(ReturnPosition pos |
returnFlowsThrough(_, pos, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, pos, _, config)
)
}
@@ -1933,20 +1911,21 @@ private module MkStage<StageSig PrevStage> {
predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
) {
exists(ParamNodeEx p |
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
parameterFlowsThroughRev(p, argAp, kind, ap, config)
exists(ParamNodeEx p, ReturnPosition pos |
returnFlowsThrough(ret, pos, _, _, p, argAp, ap, config) and
parameterFlowsThroughRev(p, argAp, pos, ap, config) and
kind = pos.getKind()
)
}
pragma[nomagic]
predicate revFlowInToReturnIsReturned(
private predicate revFlowThroughArg(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
Ap ap, Configuration config
) {
exists(ReturnKindExt returnKind0, Ap returnAp0 |
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
exists(ParamNodeEx p, Ap innerReturnAp |
revFlowThrough(call, returnCtx, p, state, _, returnAp, ap, innerReturnAp, config) and
flowThroughIntoCall(call, arg, p, _, ap, innerReturnAp, config)
)
}
@@ -1954,7 +1933,7 @@ private module MkStage<StageSig PrevStage> {
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
revFlowThroughArg(call, arg, state, returnCtx, returnAp, ap, config)
)
}
@@ -1967,8 +1946,9 @@ private module MkStage<StageSig PrevStage> {
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
tuples =
count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
count(NodeEx n, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap |
fwdFlow(n, state, cc, summaryCtx, argAp, ap, config)
)
or
fwd = false and
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
@@ -2823,13 +2803,12 @@ private Configuration unbindConf(Configuration conf) {
pragma[nomagic]
private predicate nodeMayUseSummary0(
NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
Configuration config
NodeEx n, ParamNodeEx p, FlowState state, AccessPathApprox apa, Configuration config
) {
exists(AccessPathApprox apa0 |
c = n.getEnclosingCallable() and
Stage5::parameterMayFlowThrough(p, _, _) and
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParamNodeSome(p.asNode()),
TAccessPathApproxSome(apa), apa0, config)
)
}
@@ -2838,10 +2817,9 @@ pragma[nomagic]
private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) {
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
exists(ParamNodeEx p |
Stage5::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos)
nodeMayUseSummary0(n, p, state, apa, config)
)
}
@@ -3771,8 +3749,8 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap,
AccessPathApprox apa, Configuration config
) {
exists(PathNodeMid mid, RetNodeEx ret |
pathNode(mid, ret, state, cc, sc, ap, config, _) and
exists(RetNodeEx ret |
pathNode(_, ret, state, cc, sc, ap, config, _) and
kind = ret.getKind() and
apa = ap.getApprox() and
parameterFlowThroughAllowed(sc.getParamNode(), kind)
@@ -4234,17 +4212,15 @@ private module FlowExploration {
ap = TRevPartialNil() and
exists(config.explorationLimit())
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
not clearsContentEx(node, ap.getHead()) and
(
notExpectsContent(node) or
expectsContentEx(node, ap.getHead())
) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
)
revPartialPathStep(_, node, state, sc1, sc2, sc3, ap, config) and
not clearsContentEx(node, ap.getHead()) and
(
notExpectsContent(node) or
expectsContentEx(node, ap.getHead())
) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
}
pragma[nomagic]
@@ -4252,19 +4228,17 @@ private module FlowExploration {
NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
TSummaryCtx3 sc3, PartialAccessPath ap, Configuration config
) {
exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
not clearsContentEx(node, ap.getHead().getContent()) and
(
notExpectsContent(node) or
expectsContentEx(node, ap.getHead().getContent())
) and
if node.asNode() instanceof CastingNode
then compatibleTypes(node.getDataFlowType(), ap.getType())
else any()
)
partialPathStep(_, node, state, cc, sc1, sc2, sc3, ap, config) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
not clearsContentEx(node, ap.getHead().getContent()) and
(
notExpectsContent(node) or
expectsContentEx(node, ap.getHead().getContent())
) and
if node.asNode() instanceof CastingNode
then compatibleTypes(node.getDataFlowType(), ap.getType())
else any()
}
/**

View File

@@ -916,15 +916,15 @@ private module Cached {
TDataFlowCallSome(DataFlowCall call)
cached
newtype TParameterPositionOption =
TParameterPositionNone() or
TParameterPositionSome(ParameterPosition pos)
newtype TParamNodeOption =
TParamNodeNone() or
TParamNodeSome(ParamNode p)
cached
newtype TReturnCtx =
TReturnCtxNone() or
TReturnCtxNoFlowThrough() or
TReturnCtxMaybeFlowThrough(ReturnKindExt kind)
TReturnCtxMaybeFlowThrough(ReturnPosition pos)
cached
newtype TTypedContentApprox =
@@ -1343,15 +1343,15 @@ class DataFlowCallOption extends TDataFlowCallOption {
}
}
/** An optional `ParameterPosition`. */
class ParameterPositionOption extends TParameterPositionOption {
/** An optional `ParamNode`. */
class ParamNodeOption extends TParamNodeOption {
string toString() {
this = TParameterPositionNone() and
this = TParamNodeNone() and
result = "(none)"
or
exists(ParameterPosition pos |
this = TParameterPositionSome(pos) and
result = pos.toString()
exists(ParamNode p |
this = TParamNodeSome(p) and
result = p.toString()
)
}
}
@@ -1363,7 +1363,7 @@ class ParameterPositionOption extends TParameterPositionOption {
*
* - `TReturnCtxNone()`: no return flow.
* - `TReturnCtxNoFlowThrough()`: return flow, but flow through is not possible.
* - `TReturnCtxMaybeFlowThrough(ReturnKindExt kind)`: return flow, of kind `kind`, and
* - `TReturnCtxMaybeFlowThrough(ReturnPosition pos)`: return flow, of kind `pos`, and
* flow through may be possible.
*/
class ReturnCtx extends TReturnCtx {
@@ -1374,9 +1374,9 @@ class ReturnCtx extends TReturnCtx {
this = TReturnCtxNoFlowThrough() and
result = "(no flow through)"
or
exists(ReturnKindExt kind |
this = TReturnCtxMaybeFlowThrough(kind) and
result = kind.toString()
exists(ReturnPosition pos |
this = TReturnCtxMaybeFlowThrough(pos) and
result = pos.toString()
)
}
}

View File

@@ -45,6 +45,16 @@ module Consistency {
) {
none()
}
/** Holds if `(c, pos, p)` should be excluded from the consistency test `uniqueParameterNodeAtPosition`. */
predicate uniqueParameterNodeAtPositionExclude(DataFlowCallable c, ParameterPosition pos, Node p) {
none()
}
/** Holds if `(c, pos, p)` should be excluded from the consistency test `uniqueParameterNodePosition`. */
predicate uniqueParameterNodePositionExclude(DataFlowCallable c, ParameterPosition pos, Node p) {
none()
}
}
private class RelevantNode extends Node {
@@ -101,9 +111,7 @@ module Consistency {
exists(int c |
c =
strictcount(Node n |
not exists(string filepath, int startline, int startcolumn, int endline, int endcolumn |
n.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
) and
not n.hasLocationInfo(_, _, _, _, _) and
not any(ConsistencyConfiguration conf).missingLocationExclude(n)
) and
msg = "Nodes without location: " + c
@@ -248,6 +256,7 @@ module Consistency {
query predicate uniqueParameterNodeAtPosition(
DataFlowCallable c, ParameterPosition pos, Node p, string msg
) {
not any(ConsistencyConfiguration conf).uniqueParameterNodeAtPositionExclude(c, pos, p) and
isParameterNode(p, c, pos) and
not exists(unique(Node p0 | isParameterNode(p0, c, pos))) and
msg = "Parameters with overlapping positions."
@@ -256,6 +265,7 @@ module Consistency {
query predicate uniqueParameterNodePosition(
DataFlowCallable c, ParameterPosition pos, Node p, string msg
) {
not any(ConsistencyConfiguration conf).uniqueParameterNodePositionExclude(c, pos, p) and
isParameterNode(p, c, pos) and
not exists(unique(ParameterPosition pos0 | isParameterNode(p, c, pos0))) and
msg = "Parameter node with multiple positions."

View File

@@ -622,7 +622,11 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
}
private module Stage1 implements StageSig {
class Ap = Unit;
class Ap extends int {
// workaround for bad functionality-induced joins (happens when using `Unit`)
pragma[nomagic]
Ap() { this in [0 .. 1] and this < 1 }
}
private class Cc = boolean;
@@ -872,9 +876,9 @@ private module Stage1 implements StageSig {
pragma[nomagic]
private predicate revFlowOut(ReturnPosition pos, Configuration config) {
exists(DataFlowCall call, NodeEx out |
exists(NodeEx out |
revFlow(out, _, config) and
viableReturnPosOutNodeCandFwd1(call, pos, out, config)
viableReturnPosOutNodeCandFwd1(_, pos, out, config)
)
}
@@ -1327,8 +1331,8 @@ private module MkStage<StageSig PrevStage> {
*/
pragma[nomagic]
additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, ApApprox apa, Configuration config
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
ApApprox apa, Configuration config
) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
PrevStage::revFlow(node, state, apa, config) and
@@ -1337,21 +1341,21 @@ private module MkStage<StageSig PrevStage> {
pragma[inline]
additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
Configuration config
) {
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
}
pragma[nomagic]
private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, ApApprox apa, Configuration config
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
ApApprox apa, Configuration config
) {
sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and
summaryCtx = TParameterPositionNone() and
summaryCtx = TParamNodeNone() and
ap = getApNil(node) and
apa = getApprox(ap)
or
@@ -1372,7 +1376,7 @@ private module MkStage<StageSig PrevStage> {
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
summaryCtx = TParamNodeNone() and
argAp = apNone()
)
or
@@ -1380,7 +1384,7 @@ private module MkStage<StageSig PrevStage> {
fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
summaryCtx = TParamNodeNone() and
argAp = apNone() and
ap = getApNil(node) and
apa = getApprox(ap)
@@ -1390,7 +1394,7 @@ private module MkStage<StageSig PrevStage> {
fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStateStep(mid, state0, node, state, config) and
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
summaryCtx = TParamNodeNone() and
argAp = apNone() and
ap = getApNil(node) and
apa = getApprox(ap)
@@ -1414,10 +1418,10 @@ private module MkStage<StageSig PrevStage> {
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
if PrevStage::parameterMayFlowThrough(node, apa, config)
then (
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
summaryCtx = TParamNodeSome(node.asNode()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
summaryCtx = TParamNodeNone() and argAp = apNone()
)
or
// flow out of a callable
@@ -1433,16 +1437,19 @@ private module MkStage<StageSig PrevStage> {
)
or
// flow through a callable
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
exists(
DataFlowCall call, CcCall ccc, RetNodeEx ret, boolean allowsFieldFlow, ApApprox innerArgApa
|
fwdFlowThrough(call, cc, state, ccc, summaryCtx, argAp, ap, apa, ret, innerArgApa, config) and
flowThroughOutOfCall(call, ccc, ret, node, allowsFieldFlow, innerArgApa, apa, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
pragma[nomagic]
private predicate fwdFlowStore(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType, ApApprox apa1 |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
@@ -1473,8 +1480,8 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate fwdFlowRead0(
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ApNonNil ap, Configuration config
NodeEx node1, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, ApNonNil ap,
Configuration config
) {
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, _, _, config)
@@ -1483,7 +1490,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
) {
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and
@@ -1493,7 +1500,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
ParamNodeOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
) {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
@@ -1505,64 +1512,38 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate fwdFlowRetFromArg(
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
RetNodeEx ret, FlowState state, CcCall ccc, ParamNodeEx summaryCtx, Ap argAp, ApApprox argApa,
Ap ap, ApApprox apa, Configuration config
) {
exists(DataFlowCallable c, ReturnKindExt kind |
exists(ReturnKindExt kind |
fwdFlow(pragma[only_bind_into](ret), state, ccc,
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
getApprox(argAp) = argApa and
c = ret.getEnclosingCallable() and
TParamNodeSome(pragma[only_bind_into](summaryCtx.asNode())),
pragma[only_bind_into](apSome(argAp)), ap, pragma[only_bind_into](apa),
pragma[only_bind_into](config)) and
kind = ret.getKind() and
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
parameterFlowThroughAllowed(p, kind)
parameterFlowThroughAllowed(summaryCtx, kind) and
argApa = getApprox(argAp) and
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config))
)
}
pragma[inline]
private predicate fwdFlowInMayFlowThrough(
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
private predicate fwdFlowThrough0(
DataFlowCall call, Cc cc, FlowState state, CcCall ccc, ParamNodeOption summaryCtx,
ApOption argAp, Ap ap, ApApprox apa, RetNodeEx ret, ParamNodeEx innerSummaryCtx,
Ap innerArgAp, ApApprox innerArgApa, Configuration config
) {
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(param, apa, config)
}
// dedup before joining with `flowThroughOutOfCall`
pragma[nomagic]
private predicate fwdFlowInMayFlowThroughProj(
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
}
/**
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
* in the flow covered by `fwdFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate fwdFlowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
ApApprox argApa, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
fwdFlowRetFromArg(ret, state, ccc, innerSummaryCtx, innerArgAp, innerArgApa, ap, apa, config) and
fwdFlowIsEntered(call, cc, ccc, summaryCtx, argAp, innerSummaryCtx, innerArgAp, config)
}
pragma[nomagic]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
ApApprox apa, Configuration config
private predicate fwdFlowThrough(
DataFlowCall call, Cc cc, FlowState state, CcCall ccc, ParamNodeOption summaryCtx,
ApOption argAp, Ap ap, ApApprox apa, RetNodeEx ret, ApApprox innerArgApa, Configuration config
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
config) and
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
)
fwdFlowThrough0(call, cc, state, ccc, summaryCtx, argAp, ap, apa, ret, _, _, innerArgApa,
config)
}
/**
@@ -1571,12 +1552,14 @@ private module MkStage<StageSig PrevStage> {
*/
pragma[nomagic]
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ParameterPosition pos, Ap ap, Configuration config
DataFlowCall call, Cc cc, CcCall innerCc, ParamNodeOption summaryCtx, ApOption argAp,
ParamNodeEx p, Ap ap, Configuration config
) {
exists(ParamNodeEx param |
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
pos = param.getPosition()
exists(ApApprox apa |
fwdFlowIn(call, pragma[only_bind_into](p), _, cc, innerCc, summaryCtx, argAp, ap,
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(p, apa, config) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config))
)
}
@@ -1596,23 +1579,31 @@ private module MkStage<StageSig PrevStage> {
fwdFlowConsCand(ap1, c, ap2, config)
}
pragma[nomagic]
private predicate returnFlowsThrough0(
DataFlowCall call, FlowState state, CcCall ccc, Ap ap, ApApprox apa, RetNodeEx ret,
ParamNodeEx innerSummaryCtx, Ap innerArgAp, ApApprox innerArgApa, Configuration config
) {
fwdFlowThrough0(call, _, state, ccc, _, _, ap, apa, ret, innerSummaryCtx, innerArgAp,
innerArgApa, config)
}
pragma[nomagic]
private predicate returnFlowsThrough(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
RetNodeEx ret, ReturnPosition pos, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
Ap ap, Configuration config
) {
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
kind = ret.getKind() and
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
exists(DataFlowCall call, ApApprox apa, boolean allowsFieldFlow, ApApprox innerArgApa |
returnFlowsThrough0(call, state, ccc, ap, apa, ret, p, argAp, innerArgApa, config) and
flowThroughOutOfCall(call, ccc, ret, _, allowsFieldFlow, innerArgApa, apa, config) and
pos = ret.getReturnPosition() and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
pragma[nomagic]
private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp, Ap ap,
Configuration config
) {
exists(ApApprox argApa |
@@ -1620,7 +1611,7 @@ private module MkStage<StageSig PrevStage> {
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
pragma[only_bind_into](config)) and
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), ap,
pragma[only_bind_into](config)) and
if allowsFieldFlow = false then argAp instanceof ApNil else any()
)
@@ -1639,12 +1630,13 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate flowOutOfCallAp(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, NodeEx out, boolean allowsFieldFlow,
Ap ap, Configuration config
) {
exists(ApApprox apa |
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
fwdFlow(ret, _, _, _, _, ap, apa, config)
flowOutOfCallApa(call, ret, _, out, allowsFieldFlow, apa, config) and
fwdFlow(ret, _, _, _, _, ap, apa, config) and
pos = ret.getReturnPosition()
)
}
@@ -1739,17 +1731,17 @@ private module MkStage<StageSig PrevStage> {
)
or
// flow through a callable
exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
exists(DataFlowCall call, ParamNodeEx p, Ap innerReturnAp |
revFlowThrough(call, returnCtx, p, state, _, returnAp, ap, innerReturnAp, config) and
flowThroughIntoCall(call, node, p, _, ap, innerReturnAp, config)
)
or
// flow out of a callable
exists(ReturnKindExt kind |
revFlowOut(_, node, kind, state, _, _, ap, config) and
if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
exists(ReturnPosition pos |
revFlowOut(_, node, pos, state, _, _, ap, config) and
if returnFlowsThrough(node, pos, state, _, _, _, ap, config)
then (
returnCtx = TReturnCtxMaybeFlowThrough(kind) and
returnCtx = TReturnCtxMaybeFlowThrough(pos) and
returnAp = apSome(ap)
) else (
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
@@ -1782,47 +1774,33 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate revFlowOut(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, FlowState state, ReturnCtx returnCtx,
ApOption returnAp, Ap ap, Configuration config
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
flowOutOfCallAp(call, ret, pos, out, allowsFieldFlow, ap, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
/**
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
* in the flow covered by `revFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate revFlowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
Configuration config
) {
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
revFlowIsReturned(call, _, _, _, _, config)
}
pragma[nomagic]
private predicate revFlowParamToReturn(
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
ParamNodeEx p, FlowState state, ReturnPosition pos, Ap returnAp, Ap ap, Configuration config
) {
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind)
revFlow(pragma[only_bind_into](p), state, TReturnCtxMaybeFlowThrough(pos), apSome(returnAp),
pragma[only_bind_into](ap), pragma[only_bind_into](config)) and
parameterFlowThroughAllowed(p, pos.getKind()) and
PrevStage::parameterMayFlowThrough(p, getApprox(ap), config)
}
pragma[nomagic]
private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
Configuration config
private predicate revFlowThrough(
DataFlowCall call, ReturnCtx returnCtx, ParamNodeEx p, FlowState state, ReturnPosition pos,
ApOption returnAp, Ap ap, Ap innerReturnAp, Configuration config
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
)
revFlowParamToReturn(p, state, pos, innerReturnAp, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, pos, innerReturnAp, config)
}
/**
@@ -1832,12 +1810,12 @@ private module MkStage<StageSig PrevStage> {
*/
pragma[nomagic]
private predicate revFlowIsReturned(
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnPosition pos, Ap ap,
Configuration config
) {
exists(RetNodeEx ret, FlowState state, CcCall ccc |
revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
revFlowOut(call, ret, pos, state, returnCtx, returnAp, ap, config) and
returnFlowsThrough(ret, pos, state, ccc, _, _, ap, config) and
matchesCall(ccc, call)
)
}
@@ -1915,17 +1893,17 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
ParamNodeEx p, Ap ap, ReturnPosition pos, Ap returnAp, Configuration config
) {
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind)
revFlow(p, _, TReturnCtxMaybeFlowThrough(pos), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, pos.getKind())
}
pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(RetNodeEx ret, ReturnKindExt kind |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, _, config)
exists(ReturnPosition pos |
returnFlowsThrough(_, pos, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, pos, _, config)
)
}
@@ -1933,20 +1911,21 @@ private module MkStage<StageSig PrevStage> {
predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
) {
exists(ParamNodeEx p |
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
parameterFlowsThroughRev(p, argAp, kind, ap, config)
exists(ParamNodeEx p, ReturnPosition pos |
returnFlowsThrough(ret, pos, _, _, p, argAp, ap, config) and
parameterFlowsThroughRev(p, argAp, pos, ap, config) and
kind = pos.getKind()
)
}
pragma[nomagic]
predicate revFlowInToReturnIsReturned(
private predicate revFlowThroughArg(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
Ap ap, Configuration config
) {
exists(ReturnKindExt returnKind0, Ap returnAp0 |
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
exists(ParamNodeEx p, Ap innerReturnAp |
revFlowThrough(call, returnCtx, p, state, _, returnAp, ap, innerReturnAp, config) and
flowThroughIntoCall(call, arg, p, _, ap, innerReturnAp, config)
)
}
@@ -1954,7 +1933,7 @@ private module MkStage<StageSig PrevStage> {
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
revFlowThroughArg(call, arg, state, returnCtx, returnAp, ap, config)
)
}
@@ -1967,8 +1946,9 @@ private module MkStage<StageSig PrevStage> {
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
tuples =
count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
count(NodeEx n, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap |
fwdFlow(n, state, cc, summaryCtx, argAp, ap, config)
)
or
fwd = false and
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
@@ -2823,13 +2803,12 @@ private Configuration unbindConf(Configuration conf) {
pragma[nomagic]
private predicate nodeMayUseSummary0(
NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
Configuration config
NodeEx n, ParamNodeEx p, FlowState state, AccessPathApprox apa, Configuration config
) {
exists(AccessPathApprox apa0 |
c = n.getEnclosingCallable() and
Stage5::parameterMayFlowThrough(p, _, _) and
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParamNodeSome(p.asNode()),
TAccessPathApproxSome(apa), apa0, config)
)
}
@@ -2838,10 +2817,9 @@ pragma[nomagic]
private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) {
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
exists(ParamNodeEx p |
Stage5::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos)
nodeMayUseSummary0(n, p, state, apa, config)
)
}
@@ -3771,8 +3749,8 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap,
AccessPathApprox apa, Configuration config
) {
exists(PathNodeMid mid, RetNodeEx ret |
pathNode(mid, ret, state, cc, sc, ap, config, _) and
exists(RetNodeEx ret |
pathNode(_, ret, state, cc, sc, ap, config, _) and
kind = ret.getKind() and
apa = ap.getApprox() and
parameterFlowThroughAllowed(sc.getParamNode(), kind)
@@ -4234,17 +4212,15 @@ private module FlowExploration {
ap = TRevPartialNil() and
exists(config.explorationLimit())
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
not clearsContentEx(node, ap.getHead()) and
(
notExpectsContent(node) or
expectsContentEx(node, ap.getHead())
) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
)
revPartialPathStep(_, node, state, sc1, sc2, sc3, ap, config) and
not clearsContentEx(node, ap.getHead()) and
(
notExpectsContent(node) or
expectsContentEx(node, ap.getHead())
) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
}
pragma[nomagic]
@@ -4252,19 +4228,17 @@ private module FlowExploration {
NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
TSummaryCtx3 sc3, PartialAccessPath ap, Configuration config
) {
exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
not clearsContentEx(node, ap.getHead().getContent()) and
(
notExpectsContent(node) or
expectsContentEx(node, ap.getHead().getContent())
) and
if node.asNode() instanceof CastingNode
then compatibleTypes(node.getDataFlowType(), ap.getType())
else any()
)
partialPathStep(_, node, state, cc, sc1, sc2, sc3, ap, config) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
not clearsContentEx(node, ap.getHead().getContent()) and
(
notExpectsContent(node) or
expectsContentEx(node, ap.getHead().getContent())
) and
if node.asNode() instanceof CastingNode
then compatibleTypes(node.getDataFlowType(), ap.getType())
else any()
}
/**

View File

@@ -450,10 +450,8 @@ module FlowVar_internal {
}
override string toString() {
exists(Expr e |
this.definedByExpr(e, _) and
result = "assignment to " + v
)
this.definedByExpr(_, _) and
result = "assignment to " + v
or
this.definedByInitialValue(_) and
result = "initial value of " + v

View File

@@ -54,7 +54,7 @@ class SubBasicBlock extends ControlFlowNodeBase {
* only condition under which a `SubBasicBlock` may have multiple
* predecessors.
*/
predicate firstInBB() { exists(BasicBlock bb | this.getRankInBasicBlock(bb) = 1) }
predicate firstInBB() { this.getRankInBasicBlock(_) = 1 }
/**
* Holds if this `SubBasicBlock` comes last in its basic block. This is the

View File

@@ -70,8 +70,8 @@ module VirtualDispatch {
* that is, `c` or one of its supertypes overrides `f`.
*/
private predicate cannotInherit(Class c, MemberFunction f) {
exists(Class overridingType, MemberFunction override |
cannotInheritHelper(c, f, overridingType, override) and
exists(MemberFunction override |
cannotInheritHelper(c, f, _, override) and
override.overrides+(f)
)
}

View File

@@ -53,7 +53,7 @@ class Expr extends StmtParent, @expr {
Declaration getEnclosingDeclaration() { result = exprEnclosingElement(this) }
/** Gets a child of this expression. */
Expr getAChild() { exists(int n | result = this.getChild(n)) }
Expr getAChild() { result = this.getChild(_) }
/** Gets the parent of this expression, if any. */
Element getParent() { exprparents(underlyingElement(this), _, unresolveElement(result)) }

View File

@@ -622,7 +622,11 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
}
private module Stage1 implements StageSig {
class Ap = Unit;
class Ap extends int {
// workaround for bad functionality-induced joins (happens when using `Unit`)
pragma[nomagic]
Ap() { this in [0 .. 1] and this < 1 }
}
private class Cc = boolean;
@@ -872,9 +876,9 @@ private module Stage1 implements StageSig {
pragma[nomagic]
private predicate revFlowOut(ReturnPosition pos, Configuration config) {
exists(DataFlowCall call, NodeEx out |
exists(NodeEx out |
revFlow(out, _, config) and
viableReturnPosOutNodeCandFwd1(call, pos, out, config)
viableReturnPosOutNodeCandFwd1(_, pos, out, config)
)
}
@@ -1327,8 +1331,8 @@ private module MkStage<StageSig PrevStage> {
*/
pragma[nomagic]
additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, ApApprox apa, Configuration config
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
ApApprox apa, Configuration config
) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
PrevStage::revFlow(node, state, apa, config) and
@@ -1337,21 +1341,21 @@ private module MkStage<StageSig PrevStage> {
pragma[inline]
additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
Configuration config
) {
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
}
pragma[nomagic]
private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, ApApprox apa, Configuration config
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
ApApprox apa, Configuration config
) {
sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and
summaryCtx = TParameterPositionNone() and
summaryCtx = TParamNodeNone() and
ap = getApNil(node) and
apa = getApprox(ap)
or
@@ -1372,7 +1376,7 @@ private module MkStage<StageSig PrevStage> {
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
summaryCtx = TParamNodeNone() and
argAp = apNone()
)
or
@@ -1380,7 +1384,7 @@ private module MkStage<StageSig PrevStage> {
fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
summaryCtx = TParamNodeNone() and
argAp = apNone() and
ap = getApNil(node) and
apa = getApprox(ap)
@@ -1390,7 +1394,7 @@ private module MkStage<StageSig PrevStage> {
fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStateStep(mid, state0, node, state, config) and
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
summaryCtx = TParamNodeNone() and
argAp = apNone() and
ap = getApNil(node) and
apa = getApprox(ap)
@@ -1414,10 +1418,10 @@ private module MkStage<StageSig PrevStage> {
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
if PrevStage::parameterMayFlowThrough(node, apa, config)
then (
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
summaryCtx = TParamNodeSome(node.asNode()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
summaryCtx = TParamNodeNone() and argAp = apNone()
)
or
// flow out of a callable
@@ -1433,16 +1437,19 @@ private module MkStage<StageSig PrevStage> {
)
or
// flow through a callable
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
exists(
DataFlowCall call, CcCall ccc, RetNodeEx ret, boolean allowsFieldFlow, ApApprox innerArgApa
|
fwdFlowThrough(call, cc, state, ccc, summaryCtx, argAp, ap, apa, ret, innerArgApa, config) and
flowThroughOutOfCall(call, ccc, ret, node, allowsFieldFlow, innerArgApa, apa, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
pragma[nomagic]
private predicate fwdFlowStore(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType, ApApprox apa1 |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
@@ -1473,8 +1480,8 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate fwdFlowRead0(
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ApNonNil ap, Configuration config
NodeEx node1, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, ApNonNil ap,
Configuration config
) {
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, _, _, config)
@@ -1483,7 +1490,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
) {
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and
@@ -1493,7 +1500,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
ParamNodeOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
) {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
@@ -1505,64 +1512,38 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate fwdFlowRetFromArg(
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
RetNodeEx ret, FlowState state, CcCall ccc, ParamNodeEx summaryCtx, Ap argAp, ApApprox argApa,
Ap ap, ApApprox apa, Configuration config
) {
exists(DataFlowCallable c, ReturnKindExt kind |
exists(ReturnKindExt kind |
fwdFlow(pragma[only_bind_into](ret), state, ccc,
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
getApprox(argAp) = argApa and
c = ret.getEnclosingCallable() and
TParamNodeSome(pragma[only_bind_into](summaryCtx.asNode())),
pragma[only_bind_into](apSome(argAp)), ap, pragma[only_bind_into](apa),
pragma[only_bind_into](config)) and
kind = ret.getKind() and
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
parameterFlowThroughAllowed(p, kind)
parameterFlowThroughAllowed(summaryCtx, kind) and
argApa = getApprox(argAp) and
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config))
)
}
pragma[inline]
private predicate fwdFlowInMayFlowThrough(
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
private predicate fwdFlowThrough0(
DataFlowCall call, Cc cc, FlowState state, CcCall ccc, ParamNodeOption summaryCtx,
ApOption argAp, Ap ap, ApApprox apa, RetNodeEx ret, ParamNodeEx innerSummaryCtx,
Ap innerArgAp, ApApprox innerArgApa, Configuration config
) {
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(param, apa, config)
}
// dedup before joining with `flowThroughOutOfCall`
pragma[nomagic]
private predicate fwdFlowInMayFlowThroughProj(
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
}
/**
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
* in the flow covered by `fwdFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate fwdFlowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
ApApprox argApa, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
fwdFlowRetFromArg(ret, state, ccc, innerSummaryCtx, innerArgAp, innerArgApa, ap, apa, config) and
fwdFlowIsEntered(call, cc, ccc, summaryCtx, argAp, innerSummaryCtx, innerArgAp, config)
}
pragma[nomagic]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
ApApprox apa, Configuration config
private predicate fwdFlowThrough(
DataFlowCall call, Cc cc, FlowState state, CcCall ccc, ParamNodeOption summaryCtx,
ApOption argAp, Ap ap, ApApprox apa, RetNodeEx ret, ApApprox innerArgApa, Configuration config
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
config) and
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
)
fwdFlowThrough0(call, cc, state, ccc, summaryCtx, argAp, ap, apa, ret, _, _, innerArgApa,
config)
}
/**
@@ -1571,12 +1552,14 @@ private module MkStage<StageSig PrevStage> {
*/
pragma[nomagic]
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ParameterPosition pos, Ap ap, Configuration config
DataFlowCall call, Cc cc, CcCall innerCc, ParamNodeOption summaryCtx, ApOption argAp,
ParamNodeEx p, Ap ap, Configuration config
) {
exists(ParamNodeEx param |
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
pos = param.getPosition()
exists(ApApprox apa |
fwdFlowIn(call, pragma[only_bind_into](p), _, cc, innerCc, summaryCtx, argAp, ap,
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(p, apa, config) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config))
)
}
@@ -1596,23 +1579,31 @@ private module MkStage<StageSig PrevStage> {
fwdFlowConsCand(ap1, c, ap2, config)
}
pragma[nomagic]
private predicate returnFlowsThrough0(
DataFlowCall call, FlowState state, CcCall ccc, Ap ap, ApApprox apa, RetNodeEx ret,
ParamNodeEx innerSummaryCtx, Ap innerArgAp, ApApprox innerArgApa, Configuration config
) {
fwdFlowThrough0(call, _, state, ccc, _, _, ap, apa, ret, innerSummaryCtx, innerArgAp,
innerArgApa, config)
}
pragma[nomagic]
private predicate returnFlowsThrough(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
RetNodeEx ret, ReturnPosition pos, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
Ap ap, Configuration config
) {
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
kind = ret.getKind() and
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
exists(DataFlowCall call, ApApprox apa, boolean allowsFieldFlow, ApApprox innerArgApa |
returnFlowsThrough0(call, state, ccc, ap, apa, ret, p, argAp, innerArgApa, config) and
flowThroughOutOfCall(call, ccc, ret, _, allowsFieldFlow, innerArgApa, apa, config) and
pos = ret.getReturnPosition() and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
pragma[nomagic]
private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp, Ap ap,
Configuration config
) {
exists(ApApprox argApa |
@@ -1620,7 +1611,7 @@ private module MkStage<StageSig PrevStage> {
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
pragma[only_bind_into](config)) and
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), ap,
pragma[only_bind_into](config)) and
if allowsFieldFlow = false then argAp instanceof ApNil else any()
)
@@ -1639,12 +1630,13 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate flowOutOfCallAp(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, NodeEx out, boolean allowsFieldFlow,
Ap ap, Configuration config
) {
exists(ApApprox apa |
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
fwdFlow(ret, _, _, _, _, ap, apa, config)
flowOutOfCallApa(call, ret, _, out, allowsFieldFlow, apa, config) and
fwdFlow(ret, _, _, _, _, ap, apa, config) and
pos = ret.getReturnPosition()
)
}
@@ -1739,17 +1731,17 @@ private module MkStage<StageSig PrevStage> {
)
or
// flow through a callable
exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
exists(DataFlowCall call, ParamNodeEx p, Ap innerReturnAp |
revFlowThrough(call, returnCtx, p, state, _, returnAp, ap, innerReturnAp, config) and
flowThroughIntoCall(call, node, p, _, ap, innerReturnAp, config)
)
or
// flow out of a callable
exists(ReturnKindExt kind |
revFlowOut(_, node, kind, state, _, _, ap, config) and
if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
exists(ReturnPosition pos |
revFlowOut(_, node, pos, state, _, _, ap, config) and
if returnFlowsThrough(node, pos, state, _, _, _, ap, config)
then (
returnCtx = TReturnCtxMaybeFlowThrough(kind) and
returnCtx = TReturnCtxMaybeFlowThrough(pos) and
returnAp = apSome(ap)
) else (
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
@@ -1782,47 +1774,33 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate revFlowOut(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, FlowState state, ReturnCtx returnCtx,
ApOption returnAp, Ap ap, Configuration config
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
flowOutOfCallAp(call, ret, pos, out, allowsFieldFlow, ap, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
/**
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
* in the flow covered by `revFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate revFlowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
Configuration config
) {
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
revFlowIsReturned(call, _, _, _, _, config)
}
pragma[nomagic]
private predicate revFlowParamToReturn(
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
ParamNodeEx p, FlowState state, ReturnPosition pos, Ap returnAp, Ap ap, Configuration config
) {
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind)
revFlow(pragma[only_bind_into](p), state, TReturnCtxMaybeFlowThrough(pos), apSome(returnAp),
pragma[only_bind_into](ap), pragma[only_bind_into](config)) and
parameterFlowThroughAllowed(p, pos.getKind()) and
PrevStage::parameterMayFlowThrough(p, getApprox(ap), config)
}
pragma[nomagic]
private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
Configuration config
private predicate revFlowThrough(
DataFlowCall call, ReturnCtx returnCtx, ParamNodeEx p, FlowState state, ReturnPosition pos,
ApOption returnAp, Ap ap, Ap innerReturnAp, Configuration config
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
)
revFlowParamToReturn(p, state, pos, innerReturnAp, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, pos, innerReturnAp, config)
}
/**
@@ -1832,12 +1810,12 @@ private module MkStage<StageSig PrevStage> {
*/
pragma[nomagic]
private predicate revFlowIsReturned(
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnPosition pos, Ap ap,
Configuration config
) {
exists(RetNodeEx ret, FlowState state, CcCall ccc |
revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
revFlowOut(call, ret, pos, state, returnCtx, returnAp, ap, config) and
returnFlowsThrough(ret, pos, state, ccc, _, _, ap, config) and
matchesCall(ccc, call)
)
}
@@ -1915,17 +1893,17 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
ParamNodeEx p, Ap ap, ReturnPosition pos, Ap returnAp, Configuration config
) {
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind)
revFlow(p, _, TReturnCtxMaybeFlowThrough(pos), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, pos.getKind())
}
pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(RetNodeEx ret, ReturnKindExt kind |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, _, config)
exists(ReturnPosition pos |
returnFlowsThrough(_, pos, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, pos, _, config)
)
}
@@ -1933,20 +1911,21 @@ private module MkStage<StageSig PrevStage> {
predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
) {
exists(ParamNodeEx p |
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
parameterFlowsThroughRev(p, argAp, kind, ap, config)
exists(ParamNodeEx p, ReturnPosition pos |
returnFlowsThrough(ret, pos, _, _, p, argAp, ap, config) and
parameterFlowsThroughRev(p, argAp, pos, ap, config) and
kind = pos.getKind()
)
}
pragma[nomagic]
predicate revFlowInToReturnIsReturned(
private predicate revFlowThroughArg(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
Ap ap, Configuration config
) {
exists(ReturnKindExt returnKind0, Ap returnAp0 |
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
exists(ParamNodeEx p, Ap innerReturnAp |
revFlowThrough(call, returnCtx, p, state, _, returnAp, ap, innerReturnAp, config) and
flowThroughIntoCall(call, arg, p, _, ap, innerReturnAp, config)
)
}
@@ -1954,7 +1933,7 @@ private module MkStage<StageSig PrevStage> {
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
revFlowThroughArg(call, arg, state, returnCtx, returnAp, ap, config)
)
}
@@ -1967,8 +1946,9 @@ private module MkStage<StageSig PrevStage> {
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
tuples =
count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
count(NodeEx n, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap |
fwdFlow(n, state, cc, summaryCtx, argAp, ap, config)
)
or
fwd = false and
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
@@ -2823,13 +2803,12 @@ private Configuration unbindConf(Configuration conf) {
pragma[nomagic]
private predicate nodeMayUseSummary0(
NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
Configuration config
NodeEx n, ParamNodeEx p, FlowState state, AccessPathApprox apa, Configuration config
) {
exists(AccessPathApprox apa0 |
c = n.getEnclosingCallable() and
Stage5::parameterMayFlowThrough(p, _, _) and
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParamNodeSome(p.asNode()),
TAccessPathApproxSome(apa), apa0, config)
)
}
@@ -2838,10 +2817,9 @@ pragma[nomagic]
private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) {
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
exists(ParamNodeEx p |
Stage5::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos)
nodeMayUseSummary0(n, p, state, apa, config)
)
}
@@ -3771,8 +3749,8 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap,
AccessPathApprox apa, Configuration config
) {
exists(PathNodeMid mid, RetNodeEx ret |
pathNode(mid, ret, state, cc, sc, ap, config, _) and
exists(RetNodeEx ret |
pathNode(_, ret, state, cc, sc, ap, config, _) and
kind = ret.getKind() and
apa = ap.getApprox() and
parameterFlowThroughAllowed(sc.getParamNode(), kind)
@@ -4234,17 +4212,15 @@ private module FlowExploration {
ap = TRevPartialNil() and
exists(config.explorationLimit())
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
not clearsContentEx(node, ap.getHead()) and
(
notExpectsContent(node) or
expectsContentEx(node, ap.getHead())
) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
)
revPartialPathStep(_, node, state, sc1, sc2, sc3, ap, config) and
not clearsContentEx(node, ap.getHead()) and
(
notExpectsContent(node) or
expectsContentEx(node, ap.getHead())
) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
}
pragma[nomagic]
@@ -4252,19 +4228,17 @@ private module FlowExploration {
NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
TSummaryCtx3 sc3, PartialAccessPath ap, Configuration config
) {
exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
not clearsContentEx(node, ap.getHead().getContent()) and
(
notExpectsContent(node) or
expectsContentEx(node, ap.getHead().getContent())
) and
if node.asNode() instanceof CastingNode
then compatibleTypes(node.getDataFlowType(), ap.getType())
else any()
)
partialPathStep(_, node, state, cc, sc1, sc2, sc3, ap, config) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
not clearsContentEx(node, ap.getHead().getContent()) and
(
notExpectsContent(node) or
expectsContentEx(node, ap.getHead().getContent())
) and
if node.asNode() instanceof CastingNode
then compatibleTypes(node.getDataFlowType(), ap.getType())
else any()
}
/**

View File

@@ -622,7 +622,11 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
}
private module Stage1 implements StageSig {
class Ap = Unit;
class Ap extends int {
// workaround for bad functionality-induced joins (happens when using `Unit`)
pragma[nomagic]
Ap() { this in [0 .. 1] and this < 1 }
}
private class Cc = boolean;
@@ -872,9 +876,9 @@ private module Stage1 implements StageSig {
pragma[nomagic]
private predicate revFlowOut(ReturnPosition pos, Configuration config) {
exists(DataFlowCall call, NodeEx out |
exists(NodeEx out |
revFlow(out, _, config) and
viableReturnPosOutNodeCandFwd1(call, pos, out, config)
viableReturnPosOutNodeCandFwd1(_, pos, out, config)
)
}
@@ -1327,8 +1331,8 @@ private module MkStage<StageSig PrevStage> {
*/
pragma[nomagic]
additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, ApApprox apa, Configuration config
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
ApApprox apa, Configuration config
) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
PrevStage::revFlow(node, state, apa, config) and
@@ -1337,21 +1341,21 @@ private module MkStage<StageSig PrevStage> {
pragma[inline]
additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
Configuration config
) {
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
}
pragma[nomagic]
private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, ApApprox apa, Configuration config
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
ApApprox apa, Configuration config
) {
sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and
summaryCtx = TParameterPositionNone() and
summaryCtx = TParamNodeNone() and
ap = getApNil(node) and
apa = getApprox(ap)
or
@@ -1372,7 +1376,7 @@ private module MkStage<StageSig PrevStage> {
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
summaryCtx = TParamNodeNone() and
argAp = apNone()
)
or
@@ -1380,7 +1384,7 @@ private module MkStage<StageSig PrevStage> {
fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
summaryCtx = TParamNodeNone() and
argAp = apNone() and
ap = getApNil(node) and
apa = getApprox(ap)
@@ -1390,7 +1394,7 @@ private module MkStage<StageSig PrevStage> {
fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStateStep(mid, state0, node, state, config) and
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
summaryCtx = TParamNodeNone() and
argAp = apNone() and
ap = getApNil(node) and
apa = getApprox(ap)
@@ -1414,10 +1418,10 @@ private module MkStage<StageSig PrevStage> {
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
if PrevStage::parameterMayFlowThrough(node, apa, config)
then (
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
summaryCtx = TParamNodeSome(node.asNode()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
summaryCtx = TParamNodeNone() and argAp = apNone()
)
or
// flow out of a callable
@@ -1433,16 +1437,19 @@ private module MkStage<StageSig PrevStage> {
)
or
// flow through a callable
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
exists(
DataFlowCall call, CcCall ccc, RetNodeEx ret, boolean allowsFieldFlow, ApApprox innerArgApa
|
fwdFlowThrough(call, cc, state, ccc, summaryCtx, argAp, ap, apa, ret, innerArgApa, config) and
flowThroughOutOfCall(call, ccc, ret, node, allowsFieldFlow, innerArgApa, apa, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
pragma[nomagic]
private predicate fwdFlowStore(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType, ApApprox apa1 |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
@@ -1473,8 +1480,8 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate fwdFlowRead0(
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ApNonNil ap, Configuration config
NodeEx node1, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, ApNonNil ap,
Configuration config
) {
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, _, _, config)
@@ -1483,7 +1490,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
) {
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and
@@ -1493,7 +1500,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
ParamNodeOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
) {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
@@ -1505,64 +1512,38 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate fwdFlowRetFromArg(
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
RetNodeEx ret, FlowState state, CcCall ccc, ParamNodeEx summaryCtx, Ap argAp, ApApprox argApa,
Ap ap, ApApprox apa, Configuration config
) {
exists(DataFlowCallable c, ReturnKindExt kind |
exists(ReturnKindExt kind |
fwdFlow(pragma[only_bind_into](ret), state, ccc,
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
getApprox(argAp) = argApa and
c = ret.getEnclosingCallable() and
TParamNodeSome(pragma[only_bind_into](summaryCtx.asNode())),
pragma[only_bind_into](apSome(argAp)), ap, pragma[only_bind_into](apa),
pragma[only_bind_into](config)) and
kind = ret.getKind() and
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
parameterFlowThroughAllowed(p, kind)
parameterFlowThroughAllowed(summaryCtx, kind) and
argApa = getApprox(argAp) and
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config))
)
}
pragma[inline]
private predicate fwdFlowInMayFlowThrough(
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
private predicate fwdFlowThrough0(
DataFlowCall call, Cc cc, FlowState state, CcCall ccc, ParamNodeOption summaryCtx,
ApOption argAp, Ap ap, ApApprox apa, RetNodeEx ret, ParamNodeEx innerSummaryCtx,
Ap innerArgAp, ApApprox innerArgApa, Configuration config
) {
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(param, apa, config)
}
// dedup before joining with `flowThroughOutOfCall`
pragma[nomagic]
private predicate fwdFlowInMayFlowThroughProj(
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
}
/**
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
* in the flow covered by `fwdFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate fwdFlowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
ApApprox argApa, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
fwdFlowRetFromArg(ret, state, ccc, innerSummaryCtx, innerArgAp, innerArgApa, ap, apa, config) and
fwdFlowIsEntered(call, cc, ccc, summaryCtx, argAp, innerSummaryCtx, innerArgAp, config)
}
pragma[nomagic]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
ApApprox apa, Configuration config
private predicate fwdFlowThrough(
DataFlowCall call, Cc cc, FlowState state, CcCall ccc, ParamNodeOption summaryCtx,
ApOption argAp, Ap ap, ApApprox apa, RetNodeEx ret, ApApprox innerArgApa, Configuration config
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
config) and
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
)
fwdFlowThrough0(call, cc, state, ccc, summaryCtx, argAp, ap, apa, ret, _, _, innerArgApa,
config)
}
/**
@@ -1571,12 +1552,14 @@ private module MkStage<StageSig PrevStage> {
*/
pragma[nomagic]
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ParameterPosition pos, Ap ap, Configuration config
DataFlowCall call, Cc cc, CcCall innerCc, ParamNodeOption summaryCtx, ApOption argAp,
ParamNodeEx p, Ap ap, Configuration config
) {
exists(ParamNodeEx param |
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
pos = param.getPosition()
exists(ApApprox apa |
fwdFlowIn(call, pragma[only_bind_into](p), _, cc, innerCc, summaryCtx, argAp, ap,
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(p, apa, config) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config))
)
}
@@ -1596,23 +1579,31 @@ private module MkStage<StageSig PrevStage> {
fwdFlowConsCand(ap1, c, ap2, config)
}
pragma[nomagic]
private predicate returnFlowsThrough0(
DataFlowCall call, FlowState state, CcCall ccc, Ap ap, ApApprox apa, RetNodeEx ret,
ParamNodeEx innerSummaryCtx, Ap innerArgAp, ApApprox innerArgApa, Configuration config
) {
fwdFlowThrough0(call, _, state, ccc, _, _, ap, apa, ret, innerSummaryCtx, innerArgAp,
innerArgApa, config)
}
pragma[nomagic]
private predicate returnFlowsThrough(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
RetNodeEx ret, ReturnPosition pos, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
Ap ap, Configuration config
) {
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
kind = ret.getKind() and
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
exists(DataFlowCall call, ApApprox apa, boolean allowsFieldFlow, ApApprox innerArgApa |
returnFlowsThrough0(call, state, ccc, ap, apa, ret, p, argAp, innerArgApa, config) and
flowThroughOutOfCall(call, ccc, ret, _, allowsFieldFlow, innerArgApa, apa, config) and
pos = ret.getReturnPosition() and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
pragma[nomagic]
private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp, Ap ap,
Configuration config
) {
exists(ApApprox argApa |
@@ -1620,7 +1611,7 @@ private module MkStage<StageSig PrevStage> {
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
pragma[only_bind_into](config)) and
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), ap,
pragma[only_bind_into](config)) and
if allowsFieldFlow = false then argAp instanceof ApNil else any()
)
@@ -1639,12 +1630,13 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate flowOutOfCallAp(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, NodeEx out, boolean allowsFieldFlow,
Ap ap, Configuration config
) {
exists(ApApprox apa |
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
fwdFlow(ret, _, _, _, _, ap, apa, config)
flowOutOfCallApa(call, ret, _, out, allowsFieldFlow, apa, config) and
fwdFlow(ret, _, _, _, _, ap, apa, config) and
pos = ret.getReturnPosition()
)
}
@@ -1739,17 +1731,17 @@ private module MkStage<StageSig PrevStage> {
)
or
// flow through a callable
exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
exists(DataFlowCall call, ParamNodeEx p, Ap innerReturnAp |
revFlowThrough(call, returnCtx, p, state, _, returnAp, ap, innerReturnAp, config) and
flowThroughIntoCall(call, node, p, _, ap, innerReturnAp, config)
)
or
// flow out of a callable
exists(ReturnKindExt kind |
revFlowOut(_, node, kind, state, _, _, ap, config) and
if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
exists(ReturnPosition pos |
revFlowOut(_, node, pos, state, _, _, ap, config) and
if returnFlowsThrough(node, pos, state, _, _, _, ap, config)
then (
returnCtx = TReturnCtxMaybeFlowThrough(kind) and
returnCtx = TReturnCtxMaybeFlowThrough(pos) and
returnAp = apSome(ap)
) else (
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
@@ -1782,47 +1774,33 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate revFlowOut(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, FlowState state, ReturnCtx returnCtx,
ApOption returnAp, Ap ap, Configuration config
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
flowOutOfCallAp(call, ret, pos, out, allowsFieldFlow, ap, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
/**
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
* in the flow covered by `revFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate revFlowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
Configuration config
) {
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
revFlowIsReturned(call, _, _, _, _, config)
}
pragma[nomagic]
private predicate revFlowParamToReturn(
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
ParamNodeEx p, FlowState state, ReturnPosition pos, Ap returnAp, Ap ap, Configuration config
) {
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind)
revFlow(pragma[only_bind_into](p), state, TReturnCtxMaybeFlowThrough(pos), apSome(returnAp),
pragma[only_bind_into](ap), pragma[only_bind_into](config)) and
parameterFlowThroughAllowed(p, pos.getKind()) and
PrevStage::parameterMayFlowThrough(p, getApprox(ap), config)
}
pragma[nomagic]
private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
Configuration config
private predicate revFlowThrough(
DataFlowCall call, ReturnCtx returnCtx, ParamNodeEx p, FlowState state, ReturnPosition pos,
ApOption returnAp, Ap ap, Ap innerReturnAp, Configuration config
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
)
revFlowParamToReturn(p, state, pos, innerReturnAp, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, pos, innerReturnAp, config)
}
/**
@@ -1832,12 +1810,12 @@ private module MkStage<StageSig PrevStage> {
*/
pragma[nomagic]
private predicate revFlowIsReturned(
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnPosition pos, Ap ap,
Configuration config
) {
exists(RetNodeEx ret, FlowState state, CcCall ccc |
revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
revFlowOut(call, ret, pos, state, returnCtx, returnAp, ap, config) and
returnFlowsThrough(ret, pos, state, ccc, _, _, ap, config) and
matchesCall(ccc, call)
)
}
@@ -1915,17 +1893,17 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
ParamNodeEx p, Ap ap, ReturnPosition pos, Ap returnAp, Configuration config
) {
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind)
revFlow(p, _, TReturnCtxMaybeFlowThrough(pos), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, pos.getKind())
}
pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(RetNodeEx ret, ReturnKindExt kind |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, _, config)
exists(ReturnPosition pos |
returnFlowsThrough(_, pos, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, pos, _, config)
)
}
@@ -1933,20 +1911,21 @@ private module MkStage<StageSig PrevStage> {
predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
) {
exists(ParamNodeEx p |
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
parameterFlowsThroughRev(p, argAp, kind, ap, config)
exists(ParamNodeEx p, ReturnPosition pos |
returnFlowsThrough(ret, pos, _, _, p, argAp, ap, config) and
parameterFlowsThroughRev(p, argAp, pos, ap, config) and
kind = pos.getKind()
)
}
pragma[nomagic]
predicate revFlowInToReturnIsReturned(
private predicate revFlowThroughArg(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
Ap ap, Configuration config
) {
exists(ReturnKindExt returnKind0, Ap returnAp0 |
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
exists(ParamNodeEx p, Ap innerReturnAp |
revFlowThrough(call, returnCtx, p, state, _, returnAp, ap, innerReturnAp, config) and
flowThroughIntoCall(call, arg, p, _, ap, innerReturnAp, config)
)
}
@@ -1954,7 +1933,7 @@ private module MkStage<StageSig PrevStage> {
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
revFlowThroughArg(call, arg, state, returnCtx, returnAp, ap, config)
)
}
@@ -1967,8 +1946,9 @@ private module MkStage<StageSig PrevStage> {
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
tuples =
count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
count(NodeEx n, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap |
fwdFlow(n, state, cc, summaryCtx, argAp, ap, config)
)
or
fwd = false and
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
@@ -2823,13 +2803,12 @@ private Configuration unbindConf(Configuration conf) {
pragma[nomagic]
private predicate nodeMayUseSummary0(
NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
Configuration config
NodeEx n, ParamNodeEx p, FlowState state, AccessPathApprox apa, Configuration config
) {
exists(AccessPathApprox apa0 |
c = n.getEnclosingCallable() and
Stage5::parameterMayFlowThrough(p, _, _) and
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParamNodeSome(p.asNode()),
TAccessPathApproxSome(apa), apa0, config)
)
}
@@ -2838,10 +2817,9 @@ pragma[nomagic]
private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) {
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
exists(ParamNodeEx p |
Stage5::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos)
nodeMayUseSummary0(n, p, state, apa, config)
)
}
@@ -3771,8 +3749,8 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap,
AccessPathApprox apa, Configuration config
) {
exists(PathNodeMid mid, RetNodeEx ret |
pathNode(mid, ret, state, cc, sc, ap, config, _) and
exists(RetNodeEx ret |
pathNode(_, ret, state, cc, sc, ap, config, _) and
kind = ret.getKind() and
apa = ap.getApprox() and
parameterFlowThroughAllowed(sc.getParamNode(), kind)
@@ -4234,17 +4212,15 @@ private module FlowExploration {
ap = TRevPartialNil() and
exists(config.explorationLimit())
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
not clearsContentEx(node, ap.getHead()) and
(
notExpectsContent(node) or
expectsContentEx(node, ap.getHead())
) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
)
revPartialPathStep(_, node, state, sc1, sc2, sc3, ap, config) and
not clearsContentEx(node, ap.getHead()) and
(
notExpectsContent(node) or
expectsContentEx(node, ap.getHead())
) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
}
pragma[nomagic]
@@ -4252,19 +4228,17 @@ private module FlowExploration {
NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
TSummaryCtx3 sc3, PartialAccessPath ap, Configuration config
) {
exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
not clearsContentEx(node, ap.getHead().getContent()) and
(
notExpectsContent(node) or
expectsContentEx(node, ap.getHead().getContent())
) and
if node.asNode() instanceof CastingNode
then compatibleTypes(node.getDataFlowType(), ap.getType())
else any()
)
partialPathStep(_, node, state, cc, sc1, sc2, sc3, ap, config) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
not clearsContentEx(node, ap.getHead().getContent()) and
(
notExpectsContent(node) or
expectsContentEx(node, ap.getHead().getContent())
) and
if node.asNode() instanceof CastingNode
then compatibleTypes(node.getDataFlowType(), ap.getType())
else any()
}
/**

View File

@@ -622,7 +622,11 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
}
private module Stage1 implements StageSig {
class Ap = Unit;
class Ap extends int {
// workaround for bad functionality-induced joins (happens when using `Unit`)
pragma[nomagic]
Ap() { this in [0 .. 1] and this < 1 }
}
private class Cc = boolean;
@@ -872,9 +876,9 @@ private module Stage1 implements StageSig {
pragma[nomagic]
private predicate revFlowOut(ReturnPosition pos, Configuration config) {
exists(DataFlowCall call, NodeEx out |
exists(NodeEx out |
revFlow(out, _, config) and
viableReturnPosOutNodeCandFwd1(call, pos, out, config)
viableReturnPosOutNodeCandFwd1(_, pos, out, config)
)
}
@@ -1327,8 +1331,8 @@ private module MkStage<StageSig PrevStage> {
*/
pragma[nomagic]
additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, ApApprox apa, Configuration config
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
ApApprox apa, Configuration config
) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
PrevStage::revFlow(node, state, apa, config) and
@@ -1337,21 +1341,21 @@ private module MkStage<StageSig PrevStage> {
pragma[inline]
additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
Configuration config
) {
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
}
pragma[nomagic]
private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, ApApprox apa, Configuration config
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
ApApprox apa, Configuration config
) {
sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and
summaryCtx = TParameterPositionNone() and
summaryCtx = TParamNodeNone() and
ap = getApNil(node) and
apa = getApprox(ap)
or
@@ -1372,7 +1376,7 @@ private module MkStage<StageSig PrevStage> {
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
summaryCtx = TParamNodeNone() and
argAp = apNone()
)
or
@@ -1380,7 +1384,7 @@ private module MkStage<StageSig PrevStage> {
fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
summaryCtx = TParamNodeNone() and
argAp = apNone() and
ap = getApNil(node) and
apa = getApprox(ap)
@@ -1390,7 +1394,7 @@ private module MkStage<StageSig PrevStage> {
fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStateStep(mid, state0, node, state, config) and
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
summaryCtx = TParamNodeNone() and
argAp = apNone() and
ap = getApNil(node) and
apa = getApprox(ap)
@@ -1414,10 +1418,10 @@ private module MkStage<StageSig PrevStage> {
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
if PrevStage::parameterMayFlowThrough(node, apa, config)
then (
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
summaryCtx = TParamNodeSome(node.asNode()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
summaryCtx = TParamNodeNone() and argAp = apNone()
)
or
// flow out of a callable
@@ -1433,16 +1437,19 @@ private module MkStage<StageSig PrevStage> {
)
or
// flow through a callable
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
exists(
DataFlowCall call, CcCall ccc, RetNodeEx ret, boolean allowsFieldFlow, ApApprox innerArgApa
|
fwdFlowThrough(call, cc, state, ccc, summaryCtx, argAp, ap, apa, ret, innerArgApa, config) and
flowThroughOutOfCall(call, ccc, ret, node, allowsFieldFlow, innerArgApa, apa, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
pragma[nomagic]
private predicate fwdFlowStore(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType, ApApprox apa1 |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
@@ -1473,8 +1480,8 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate fwdFlowRead0(
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ApNonNil ap, Configuration config
NodeEx node1, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, ApNonNil ap,
Configuration config
) {
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, _, _, config)
@@ -1483,7 +1490,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
) {
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and
@@ -1493,7 +1500,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
ParamNodeOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
) {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
@@ -1505,64 +1512,38 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate fwdFlowRetFromArg(
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
RetNodeEx ret, FlowState state, CcCall ccc, ParamNodeEx summaryCtx, Ap argAp, ApApprox argApa,
Ap ap, ApApprox apa, Configuration config
) {
exists(DataFlowCallable c, ReturnKindExt kind |
exists(ReturnKindExt kind |
fwdFlow(pragma[only_bind_into](ret), state, ccc,
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
getApprox(argAp) = argApa and
c = ret.getEnclosingCallable() and
TParamNodeSome(pragma[only_bind_into](summaryCtx.asNode())),
pragma[only_bind_into](apSome(argAp)), ap, pragma[only_bind_into](apa),
pragma[only_bind_into](config)) and
kind = ret.getKind() and
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
parameterFlowThroughAllowed(p, kind)
parameterFlowThroughAllowed(summaryCtx, kind) and
argApa = getApprox(argAp) and
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config))
)
}
pragma[inline]
private predicate fwdFlowInMayFlowThrough(
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
private predicate fwdFlowThrough0(
DataFlowCall call, Cc cc, FlowState state, CcCall ccc, ParamNodeOption summaryCtx,
ApOption argAp, Ap ap, ApApprox apa, RetNodeEx ret, ParamNodeEx innerSummaryCtx,
Ap innerArgAp, ApApprox innerArgApa, Configuration config
) {
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(param, apa, config)
}
// dedup before joining with `flowThroughOutOfCall`
pragma[nomagic]
private predicate fwdFlowInMayFlowThroughProj(
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
}
/**
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
* in the flow covered by `fwdFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate fwdFlowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
ApApprox argApa, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
fwdFlowRetFromArg(ret, state, ccc, innerSummaryCtx, innerArgAp, innerArgApa, ap, apa, config) and
fwdFlowIsEntered(call, cc, ccc, summaryCtx, argAp, innerSummaryCtx, innerArgAp, config)
}
pragma[nomagic]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
ApApprox apa, Configuration config
private predicate fwdFlowThrough(
DataFlowCall call, Cc cc, FlowState state, CcCall ccc, ParamNodeOption summaryCtx,
ApOption argAp, Ap ap, ApApprox apa, RetNodeEx ret, ApApprox innerArgApa, Configuration config
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
config) and
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
)
fwdFlowThrough0(call, cc, state, ccc, summaryCtx, argAp, ap, apa, ret, _, _, innerArgApa,
config)
}
/**
@@ -1571,12 +1552,14 @@ private module MkStage<StageSig PrevStage> {
*/
pragma[nomagic]
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ParameterPosition pos, Ap ap, Configuration config
DataFlowCall call, Cc cc, CcCall innerCc, ParamNodeOption summaryCtx, ApOption argAp,
ParamNodeEx p, Ap ap, Configuration config
) {
exists(ParamNodeEx param |
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
pos = param.getPosition()
exists(ApApprox apa |
fwdFlowIn(call, pragma[only_bind_into](p), _, cc, innerCc, summaryCtx, argAp, ap,
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(p, apa, config) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config))
)
}
@@ -1596,23 +1579,31 @@ private module MkStage<StageSig PrevStage> {
fwdFlowConsCand(ap1, c, ap2, config)
}
pragma[nomagic]
private predicate returnFlowsThrough0(
DataFlowCall call, FlowState state, CcCall ccc, Ap ap, ApApprox apa, RetNodeEx ret,
ParamNodeEx innerSummaryCtx, Ap innerArgAp, ApApprox innerArgApa, Configuration config
) {
fwdFlowThrough0(call, _, state, ccc, _, _, ap, apa, ret, innerSummaryCtx, innerArgAp,
innerArgApa, config)
}
pragma[nomagic]
private predicate returnFlowsThrough(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
RetNodeEx ret, ReturnPosition pos, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
Ap ap, Configuration config
) {
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
kind = ret.getKind() and
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
exists(DataFlowCall call, ApApprox apa, boolean allowsFieldFlow, ApApprox innerArgApa |
returnFlowsThrough0(call, state, ccc, ap, apa, ret, p, argAp, innerArgApa, config) and
flowThroughOutOfCall(call, ccc, ret, _, allowsFieldFlow, innerArgApa, apa, config) and
pos = ret.getReturnPosition() and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
pragma[nomagic]
private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp, Ap ap,
Configuration config
) {
exists(ApApprox argApa |
@@ -1620,7 +1611,7 @@ private module MkStage<StageSig PrevStage> {
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
pragma[only_bind_into](config)) and
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), ap,
pragma[only_bind_into](config)) and
if allowsFieldFlow = false then argAp instanceof ApNil else any()
)
@@ -1639,12 +1630,13 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate flowOutOfCallAp(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, NodeEx out, boolean allowsFieldFlow,
Ap ap, Configuration config
) {
exists(ApApprox apa |
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
fwdFlow(ret, _, _, _, _, ap, apa, config)
flowOutOfCallApa(call, ret, _, out, allowsFieldFlow, apa, config) and
fwdFlow(ret, _, _, _, _, ap, apa, config) and
pos = ret.getReturnPosition()
)
}
@@ -1739,17 +1731,17 @@ private module MkStage<StageSig PrevStage> {
)
or
// flow through a callable
exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
exists(DataFlowCall call, ParamNodeEx p, Ap innerReturnAp |
revFlowThrough(call, returnCtx, p, state, _, returnAp, ap, innerReturnAp, config) and
flowThroughIntoCall(call, node, p, _, ap, innerReturnAp, config)
)
or
// flow out of a callable
exists(ReturnKindExt kind |
revFlowOut(_, node, kind, state, _, _, ap, config) and
if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
exists(ReturnPosition pos |
revFlowOut(_, node, pos, state, _, _, ap, config) and
if returnFlowsThrough(node, pos, state, _, _, _, ap, config)
then (
returnCtx = TReturnCtxMaybeFlowThrough(kind) and
returnCtx = TReturnCtxMaybeFlowThrough(pos) and
returnAp = apSome(ap)
) else (
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
@@ -1782,47 +1774,33 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate revFlowOut(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, FlowState state, ReturnCtx returnCtx,
ApOption returnAp, Ap ap, Configuration config
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
flowOutOfCallAp(call, ret, pos, out, allowsFieldFlow, ap, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
/**
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
* in the flow covered by `revFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate revFlowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
Configuration config
) {
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
revFlowIsReturned(call, _, _, _, _, config)
}
pragma[nomagic]
private predicate revFlowParamToReturn(
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
ParamNodeEx p, FlowState state, ReturnPosition pos, Ap returnAp, Ap ap, Configuration config
) {
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind)
revFlow(pragma[only_bind_into](p), state, TReturnCtxMaybeFlowThrough(pos), apSome(returnAp),
pragma[only_bind_into](ap), pragma[only_bind_into](config)) and
parameterFlowThroughAllowed(p, pos.getKind()) and
PrevStage::parameterMayFlowThrough(p, getApprox(ap), config)
}
pragma[nomagic]
private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
Configuration config
private predicate revFlowThrough(
DataFlowCall call, ReturnCtx returnCtx, ParamNodeEx p, FlowState state, ReturnPosition pos,
ApOption returnAp, Ap ap, Ap innerReturnAp, Configuration config
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
)
revFlowParamToReturn(p, state, pos, innerReturnAp, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, pos, innerReturnAp, config)
}
/**
@@ -1832,12 +1810,12 @@ private module MkStage<StageSig PrevStage> {
*/
pragma[nomagic]
private predicate revFlowIsReturned(
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnPosition pos, Ap ap,
Configuration config
) {
exists(RetNodeEx ret, FlowState state, CcCall ccc |
revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
revFlowOut(call, ret, pos, state, returnCtx, returnAp, ap, config) and
returnFlowsThrough(ret, pos, state, ccc, _, _, ap, config) and
matchesCall(ccc, call)
)
}
@@ -1915,17 +1893,17 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
ParamNodeEx p, Ap ap, ReturnPosition pos, Ap returnAp, Configuration config
) {
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind)
revFlow(p, _, TReturnCtxMaybeFlowThrough(pos), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, pos.getKind())
}
pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(RetNodeEx ret, ReturnKindExt kind |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, _, config)
exists(ReturnPosition pos |
returnFlowsThrough(_, pos, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, pos, _, config)
)
}
@@ -1933,20 +1911,21 @@ private module MkStage<StageSig PrevStage> {
predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
) {
exists(ParamNodeEx p |
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
parameterFlowsThroughRev(p, argAp, kind, ap, config)
exists(ParamNodeEx p, ReturnPosition pos |
returnFlowsThrough(ret, pos, _, _, p, argAp, ap, config) and
parameterFlowsThroughRev(p, argAp, pos, ap, config) and
kind = pos.getKind()
)
}
pragma[nomagic]
predicate revFlowInToReturnIsReturned(
private predicate revFlowThroughArg(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
Ap ap, Configuration config
) {
exists(ReturnKindExt returnKind0, Ap returnAp0 |
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
exists(ParamNodeEx p, Ap innerReturnAp |
revFlowThrough(call, returnCtx, p, state, _, returnAp, ap, innerReturnAp, config) and
flowThroughIntoCall(call, arg, p, _, ap, innerReturnAp, config)
)
}
@@ -1954,7 +1933,7 @@ private module MkStage<StageSig PrevStage> {
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
revFlowThroughArg(call, arg, state, returnCtx, returnAp, ap, config)
)
}
@@ -1967,8 +1946,9 @@ private module MkStage<StageSig PrevStage> {
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
tuples =
count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
count(NodeEx n, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap |
fwdFlow(n, state, cc, summaryCtx, argAp, ap, config)
)
or
fwd = false and
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
@@ -2823,13 +2803,12 @@ private Configuration unbindConf(Configuration conf) {
pragma[nomagic]
private predicate nodeMayUseSummary0(
NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
Configuration config
NodeEx n, ParamNodeEx p, FlowState state, AccessPathApprox apa, Configuration config
) {
exists(AccessPathApprox apa0 |
c = n.getEnclosingCallable() and
Stage5::parameterMayFlowThrough(p, _, _) and
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParamNodeSome(p.asNode()),
TAccessPathApproxSome(apa), apa0, config)
)
}
@@ -2838,10 +2817,9 @@ pragma[nomagic]
private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) {
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
exists(ParamNodeEx p |
Stage5::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos)
nodeMayUseSummary0(n, p, state, apa, config)
)
}
@@ -3771,8 +3749,8 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap,
AccessPathApprox apa, Configuration config
) {
exists(PathNodeMid mid, RetNodeEx ret |
pathNode(mid, ret, state, cc, sc, ap, config, _) and
exists(RetNodeEx ret |
pathNode(_, ret, state, cc, sc, ap, config, _) and
kind = ret.getKind() and
apa = ap.getApprox() and
parameterFlowThroughAllowed(sc.getParamNode(), kind)
@@ -4234,17 +4212,15 @@ private module FlowExploration {
ap = TRevPartialNil() and
exists(config.explorationLimit())
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
not clearsContentEx(node, ap.getHead()) and
(
notExpectsContent(node) or
expectsContentEx(node, ap.getHead())
) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
)
revPartialPathStep(_, node, state, sc1, sc2, sc3, ap, config) and
not clearsContentEx(node, ap.getHead()) and
(
notExpectsContent(node) or
expectsContentEx(node, ap.getHead())
) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
}
pragma[nomagic]
@@ -4252,19 +4228,17 @@ private module FlowExploration {
NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
TSummaryCtx3 sc3, PartialAccessPath ap, Configuration config
) {
exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
not clearsContentEx(node, ap.getHead().getContent()) and
(
notExpectsContent(node) or
expectsContentEx(node, ap.getHead().getContent())
) and
if node.asNode() instanceof CastingNode
then compatibleTypes(node.getDataFlowType(), ap.getType())
else any()
)
partialPathStep(_, node, state, cc, sc1, sc2, sc3, ap, config) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
not clearsContentEx(node, ap.getHead().getContent()) and
(
notExpectsContent(node) or
expectsContentEx(node, ap.getHead().getContent())
) and
if node.asNode() instanceof CastingNode
then compatibleTypes(node.getDataFlowType(), ap.getType())
else any()
}
/**

View File

@@ -622,7 +622,11 @@ private predicate parameterFlowThroughAllowed(ParamNodeEx p, ReturnKindExt kind)
}
private module Stage1 implements StageSig {
class Ap = Unit;
class Ap extends int {
// workaround for bad functionality-induced joins (happens when using `Unit`)
pragma[nomagic]
Ap() { this in [0 .. 1] and this < 1 }
}
private class Cc = boolean;
@@ -872,9 +876,9 @@ private module Stage1 implements StageSig {
pragma[nomagic]
private predicate revFlowOut(ReturnPosition pos, Configuration config) {
exists(DataFlowCall call, NodeEx out |
exists(NodeEx out |
revFlow(out, _, config) and
viableReturnPosOutNodeCandFwd1(call, pos, out, config)
viableReturnPosOutNodeCandFwd1(_, pos, out, config)
)
}
@@ -1327,8 +1331,8 @@ private module MkStage<StageSig PrevStage> {
*/
pragma[nomagic]
additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, ApApprox apa, Configuration config
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
ApApprox apa, Configuration config
) {
fwdFlow0(node, state, cc, summaryCtx, argAp, ap, apa, config) and
PrevStage::revFlow(node, state, apa, config) and
@@ -1337,21 +1341,21 @@ private module MkStage<StageSig PrevStage> {
pragma[inline]
additional predicate fwdFlow(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, Configuration config
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
Configuration config
) {
fwdFlow(node, state, cc, summaryCtx, argAp, ap, _, config)
}
pragma[nomagic]
private predicate fwdFlow0(
NodeEx node, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap, ApApprox apa, Configuration config
NodeEx node, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap,
ApApprox apa, Configuration config
) {
sourceNode(node, state, config) and
(if hasSourceCallCtx(config) then cc = ccSomeCall() else cc = ccNone()) and
argAp = apNone() and
summaryCtx = TParameterPositionNone() and
summaryCtx = TParamNodeNone() and
ap = getApNil(node) and
apa = getApprox(ap)
or
@@ -1372,7 +1376,7 @@ private module MkStage<StageSig PrevStage> {
fwdFlow(mid, pragma[only_bind_into](state), _, _, _, ap, apa, pragma[only_bind_into](config)) and
jumpStep(mid, node, config) and
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
summaryCtx = TParamNodeNone() and
argAp = apNone()
)
or
@@ -1380,7 +1384,7 @@ private module MkStage<StageSig PrevStage> {
fwdFlow(mid, state, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStep(mid, node, config) and
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
summaryCtx = TParamNodeNone() and
argAp = apNone() and
ap = getApNil(node) and
apa = getApprox(ap)
@@ -1390,7 +1394,7 @@ private module MkStage<StageSig PrevStage> {
fwdFlow(mid, state0, _, _, _, nil, pragma[only_bind_into](config)) and
additionalJumpStateStep(mid, state0, node, state, config) and
cc = ccNone() and
summaryCtx = TParameterPositionNone() and
summaryCtx = TParamNodeNone() and
argAp = apNone() and
ap = getApNil(node) and
apa = getApprox(ap)
@@ -1414,10 +1418,10 @@ private module MkStage<StageSig PrevStage> {
fwdFlowIn(_, node, state, _, cc, _, _, ap, apa, config) and
if PrevStage::parameterMayFlowThrough(node, apa, config)
then (
summaryCtx = TParameterPositionSome(node.(ParamNodeEx).getPosition()) and
summaryCtx = TParamNodeSome(node.asNode()) and
argAp = apSome(ap)
) else (
summaryCtx = TParameterPositionNone() and argAp = apNone()
summaryCtx = TParamNodeNone() and argAp = apNone()
)
or
// flow out of a callable
@@ -1433,16 +1437,19 @@ private module MkStage<StageSig PrevStage> {
)
or
// flow through a callable
exists(DataFlowCall call, ParameterPosition summaryCtx0, Ap argAp0 |
fwdFlowOutFromArg(call, node, state, summaryCtx0, argAp0, ap, apa, config) and
fwdFlowIsEntered(call, cc, summaryCtx, argAp, summaryCtx0, argAp0, config)
exists(
DataFlowCall call, CcCall ccc, RetNodeEx ret, boolean allowsFieldFlow, ApApprox innerArgApa
|
fwdFlowThrough(call, cc, state, ccc, summaryCtx, argAp, ap, apa, ret, innerArgApa, config) and
flowThroughOutOfCall(call, ccc, ret, node, allowsFieldFlow, innerArgApa, apa, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
pragma[nomagic]
private predicate fwdFlowStore(
NodeEx node1, Ap ap1, TypedContent tc, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
) {
exists(DataFlowType contentType, ApApprox apa1 |
fwdFlow(node1, state, cc, summaryCtx, argAp, ap1, apa1, config) and
@@ -1473,8 +1480,8 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate fwdFlowRead0(
NodeEx node1, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ApNonNil ap, Configuration config
NodeEx node1, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, ApNonNil ap,
Configuration config
) {
fwdFlow(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, _, _, config)
@@ -1483,7 +1490,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate fwdFlowRead(
Ap ap, Content c, NodeEx node1, NodeEx node2, FlowState state, Cc cc,
ParameterPositionOption summaryCtx, ApOption argAp, Configuration config
ParamNodeOption summaryCtx, ApOption argAp, Configuration config
) {
fwdFlowRead0(node1, state, cc, summaryCtx, argAp, ap, config) and
PrevStage::readStepCand(node1, c, node2, config) and
@@ -1493,7 +1500,7 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate fwdFlowIn(
DataFlowCall call, ParamNodeEx p, FlowState state, Cc outercc, CcCall innercc,
ParameterPositionOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
ParamNodeOption summaryCtx, ApOption argAp, Ap ap, ApApprox apa, Configuration config
) {
exists(ArgNodeEx arg, boolean allowsFieldFlow |
fwdFlow(arg, state, outercc, summaryCtx, argAp, ap, apa, config) and
@@ -1505,64 +1512,38 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate fwdFlowRetFromArg(
RetNodeEx ret, FlowState state, CcCall ccc, ParameterPosition summaryCtx, ParamNodeEx p,
Ap argAp, ApApprox argApa, Ap ap, ApApprox apa, Configuration config
RetNodeEx ret, FlowState state, CcCall ccc, ParamNodeEx summaryCtx, Ap argAp, ApApprox argApa,
Ap ap, ApApprox apa, Configuration config
) {
exists(DataFlowCallable c, ReturnKindExt kind |
exists(ReturnKindExt kind |
fwdFlow(pragma[only_bind_into](ret), state, ccc,
TParameterPositionSome(pragma[only_bind_into](summaryCtx)), apSome(argAp), ap, apa, config) and
getApprox(argAp) = argApa and
c = ret.getEnclosingCallable() and
TParamNodeSome(pragma[only_bind_into](summaryCtx.asNode())),
pragma[only_bind_into](apSome(argAp)), ap, pragma[only_bind_into](apa),
pragma[only_bind_into](config)) and
kind = ret.getKind() and
p.isParameterOf(c, pragma[only_bind_into](summaryCtx)) and
parameterFlowThroughAllowed(p, kind)
parameterFlowThroughAllowed(summaryCtx, kind) and
argApa = getApprox(argAp) and
PrevStage::returnMayFlowThrough(ret, argApa, apa, kind, pragma[only_bind_into](config))
)
}
pragma[inline]
private predicate fwdFlowInMayFlowThrough(
DataFlowCall call, Cc cc, CcCall innerCc, ParameterPositionOption summaryCtx, ApOption argAp,
ParamNodeEx param, Ap ap, ApApprox apa, Configuration config
private predicate fwdFlowThrough0(
DataFlowCall call, Cc cc, FlowState state, CcCall ccc, ParamNodeOption summaryCtx,
ApOption argAp, Ap ap, ApApprox apa, RetNodeEx ret, ParamNodeEx innerSummaryCtx,
Ap innerArgAp, ApApprox innerArgApa, Configuration config
) {
fwdFlowIn(call, pragma[only_bind_into](param), _, cc, innerCc, summaryCtx, argAp, ap,
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(param, apa, config)
}
// dedup before joining with `flowThroughOutOfCall`
pragma[nomagic]
private predicate fwdFlowInMayFlowThroughProj(
DataFlowCall call, CcCall innerCc, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThrough(call, _, innerCc, _, _, _, _, apa, config)
}
/**
* Same as `flowThroughOutOfCall`, but restricted to calls that are reached
* in the flow covered by `fwdFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate fwdFlowThroughOutOfCall(
DataFlowCall call, CcCall ccc, RetNodeEx ret, NodeEx out, boolean allowsFieldFlow,
ApApprox argApa, ApApprox apa, Configuration config
) {
fwdFlowInMayFlowThroughProj(call, ccc, argApa, config) and
flowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config)
fwdFlowRetFromArg(ret, state, ccc, innerSummaryCtx, innerArgAp, innerArgApa, ap, apa, config) and
fwdFlowIsEntered(call, cc, ccc, summaryCtx, argAp, innerSummaryCtx, innerArgAp, config)
}
pragma[nomagic]
private predicate fwdFlowOutFromArg(
DataFlowCall call, NodeEx out, FlowState state, ParameterPosition summaryCtx, Ap argAp, Ap ap,
ApApprox apa, Configuration config
private predicate fwdFlowThrough(
DataFlowCall call, Cc cc, FlowState state, CcCall ccc, ParamNodeOption summaryCtx,
ApOption argAp, Ap ap, ApApprox apa, RetNodeEx ret, ApApprox innerArgApa, Configuration config
) {
exists(RetNodeEx ret, boolean allowsFieldFlow, CcCall ccc, ApApprox argApa |
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc),
summaryCtx, _, argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa),
config) and
fwdFlowThroughOutOfCall(call, ccc, ret, out, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
)
fwdFlowThrough0(call, cc, state, ccc, summaryCtx, argAp, ap, apa, ret, _, _, innerArgApa,
config)
}
/**
@@ -1571,12 +1552,14 @@ private module MkStage<StageSig PrevStage> {
*/
pragma[nomagic]
private predicate fwdFlowIsEntered(
DataFlowCall call, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
ParameterPosition pos, Ap ap, Configuration config
DataFlowCall call, Cc cc, CcCall innerCc, ParamNodeOption summaryCtx, ApOption argAp,
ParamNodeEx p, Ap ap, Configuration config
) {
exists(ParamNodeEx param |
fwdFlowInMayFlowThrough(call, cc, _, summaryCtx, argAp, param, ap, _, config) and
pos = param.getPosition()
exists(ApApprox apa |
fwdFlowIn(call, pragma[only_bind_into](p), _, cc, innerCc, summaryCtx, argAp, ap,
pragma[only_bind_into](apa), pragma[only_bind_into](config)) and
PrevStage::parameterMayFlowThrough(p, apa, config) and
PrevStage::callMayFlowThroughRev(call, pragma[only_bind_into](config))
)
}
@@ -1596,23 +1579,31 @@ private module MkStage<StageSig PrevStage> {
fwdFlowConsCand(ap1, c, ap2, config)
}
pragma[nomagic]
private predicate returnFlowsThrough0(
DataFlowCall call, FlowState state, CcCall ccc, Ap ap, ApApprox apa, RetNodeEx ret,
ParamNodeEx innerSummaryCtx, Ap innerArgAp, ApApprox innerArgApa, Configuration config
) {
fwdFlowThrough0(call, _, state, ccc, _, _, ap, apa, ret, innerSummaryCtx, innerArgAp,
innerArgApa, config)
}
pragma[nomagic]
private predicate returnFlowsThrough(
RetNodeEx ret, ReturnKindExt kind, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
RetNodeEx ret, ReturnPosition pos, FlowState state, CcCall ccc, ParamNodeEx p, Ap argAp,
Ap ap, Configuration config
) {
exists(boolean allowsFieldFlow, ApApprox argApa, ApApprox apa |
fwdFlowRetFromArg(pragma[only_bind_into](ret), state, pragma[only_bind_into](ccc), _, p,
argAp, pragma[only_bind_into](argApa), ap, pragma[only_bind_into](apa), config) and
kind = ret.getKind() and
fwdFlowThroughOutOfCall(_, ccc, ret, _, allowsFieldFlow, argApa, apa, config) and
(if allowsFieldFlow = false then ap instanceof ApNil else any())
exists(DataFlowCall call, ApApprox apa, boolean allowsFieldFlow, ApApprox innerArgApa |
returnFlowsThrough0(call, state, ccc, ap, apa, ret, p, argAp, innerArgApa, config) and
flowThroughOutOfCall(call, ccc, ret, _, allowsFieldFlow, innerArgApa, apa, config) and
pos = ret.getReturnPosition() and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
pragma[nomagic]
private predicate flowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp, Ap ap,
Configuration config
) {
exists(ApApprox argApa |
@@ -1620,7 +1611,7 @@ private module MkStage<StageSig PrevStage> {
allowsFieldFlow, argApa, pragma[only_bind_into](config)) and
fwdFlow(arg, _, _, _, _, pragma[only_bind_into](argAp), argApa,
pragma[only_bind_into](config)) and
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), _,
returnFlowsThrough(_, _, _, _, p, pragma[only_bind_into](argAp), ap,
pragma[only_bind_into](config)) and
if allowsFieldFlow = false then argAp instanceof ApNil else any()
)
@@ -1639,12 +1630,13 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate flowOutOfCallAp(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, NodeEx out, boolean allowsFieldFlow,
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, NodeEx out, boolean allowsFieldFlow,
Ap ap, Configuration config
) {
exists(ApApprox apa |
flowOutOfCallApa(call, ret, kind, out, allowsFieldFlow, apa, config) and
fwdFlow(ret, _, _, _, _, ap, apa, config)
flowOutOfCallApa(call, ret, _, out, allowsFieldFlow, apa, config) and
fwdFlow(ret, _, _, _, _, ap, apa, config) and
pos = ret.getReturnPosition()
)
}
@@ -1739,17 +1731,17 @@ private module MkStage<StageSig PrevStage> {
)
or
// flow through a callable
exists(DataFlowCall call, ReturnKindExt returnKind0, Ap returnAp0 |
revFlowInToReturn(call, node, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
exists(DataFlowCall call, ParamNodeEx p, Ap innerReturnAp |
revFlowThrough(call, returnCtx, p, state, _, returnAp, ap, innerReturnAp, config) and
flowThroughIntoCall(call, node, p, _, ap, innerReturnAp, config)
)
or
// flow out of a callable
exists(ReturnKindExt kind |
revFlowOut(_, node, kind, state, _, _, ap, config) and
if returnFlowsThrough(node, kind, state, _, _, _, ap, config)
exists(ReturnPosition pos |
revFlowOut(_, node, pos, state, _, _, ap, config) and
if returnFlowsThrough(node, pos, state, _, _, _, ap, config)
then (
returnCtx = TReturnCtxMaybeFlowThrough(kind) and
returnCtx = TReturnCtxMaybeFlowThrough(pos) and
returnAp = apSome(ap)
) else (
returnCtx = TReturnCtxNoFlowThrough() and returnAp = apNone()
@@ -1782,47 +1774,33 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate revFlowOut(
DataFlowCall call, RetNodeEx ret, ReturnKindExt kind, FlowState state, ReturnCtx returnCtx,
DataFlowCall call, RetNodeEx ret, ReturnPosition pos, FlowState state, ReturnCtx returnCtx,
ApOption returnAp, Ap ap, Configuration config
) {
exists(NodeEx out, boolean allowsFieldFlow |
revFlow(out, state, returnCtx, returnAp, ap, config) and
flowOutOfCallAp(call, ret, kind, out, allowsFieldFlow, ap, config) and
flowOutOfCallAp(call, ret, pos, out, allowsFieldFlow, ap, config) and
if allowsFieldFlow = false then ap instanceof ApNil else any()
)
}
/**
* Same as `flowThroughIntoCall`, but restricted to calls that are reached
* in the flow covered by `revFlow`, where data might flow through the target
* callable and back out at `call`.
*/
pragma[nomagic]
private predicate revFlowThroughIntoCall(
DataFlowCall call, ArgNodeEx arg, ParamNodeEx p, boolean allowsFieldFlow, Ap argAp,
Configuration config
) {
flowThroughIntoCall(call, arg, p, allowsFieldFlow, argAp, config) and
revFlowIsReturned(call, _, _, _, _, config)
}
pragma[nomagic]
private predicate revFlowParamToReturn(
ParamNodeEx p, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap, Configuration config
ParamNodeEx p, FlowState state, ReturnPosition pos, Ap returnAp, Ap ap, Configuration config
) {
revFlow(p, state, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind)
revFlow(pragma[only_bind_into](p), state, TReturnCtxMaybeFlowThrough(pos), apSome(returnAp),
pragma[only_bind_into](ap), pragma[only_bind_into](config)) and
parameterFlowThroughAllowed(p, pos.getKind()) and
PrevStage::parameterMayFlowThrough(p, getApprox(ap), config)
}
pragma[nomagic]
private predicate revFlowInToReturn(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnKindExt kind, Ap returnAp, Ap ap,
Configuration config
private predicate revFlowThrough(
DataFlowCall call, ReturnCtx returnCtx, ParamNodeEx p, FlowState state, ReturnPosition pos,
ApOption returnAp, Ap ap, Ap innerReturnAp, Configuration config
) {
exists(ParamNodeEx p, boolean allowsFieldFlow |
revFlowParamToReturn(p, state, kind, returnAp, ap, config) and
revFlowThroughIntoCall(call, arg, p, allowsFieldFlow, ap, config)
)
revFlowParamToReturn(p, state, pos, innerReturnAp, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, pos, innerReturnAp, config)
}
/**
@@ -1832,12 +1810,12 @@ private module MkStage<StageSig PrevStage> {
*/
pragma[nomagic]
private predicate revFlowIsReturned(
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnKindExt kind, Ap ap,
DataFlowCall call, ReturnCtx returnCtx, ApOption returnAp, ReturnPosition pos, Ap ap,
Configuration config
) {
exists(RetNodeEx ret, FlowState state, CcCall ccc |
revFlowOut(call, ret, kind, state, returnCtx, returnAp, ap, config) and
returnFlowsThrough(ret, kind, state, ccc, _, _, ap, config) and
revFlowOut(call, ret, pos, state, returnCtx, returnAp, ap, config) and
returnFlowsThrough(ret, pos, state, ccc, _, _, ap, config) and
matchesCall(ccc, call)
)
}
@@ -1915,17 +1893,17 @@ private module MkStage<StageSig PrevStage> {
pragma[nomagic]
private predicate parameterFlowsThroughRev(
ParamNodeEx p, Ap ap, ReturnKindExt kind, Ap returnAp, Configuration config
ParamNodeEx p, Ap ap, ReturnPosition pos, Ap returnAp, Configuration config
) {
revFlow(p, _, TReturnCtxMaybeFlowThrough(kind), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, kind)
revFlow(p, _, TReturnCtxMaybeFlowThrough(pos), apSome(returnAp), ap, config) and
parameterFlowThroughAllowed(p, pos.getKind())
}
pragma[nomagic]
predicate parameterMayFlowThrough(ParamNodeEx p, Ap ap, Configuration config) {
exists(RetNodeEx ret, ReturnKindExt kind |
returnFlowsThrough(ret, kind, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, kind, _, config)
exists(ReturnPosition pos |
returnFlowsThrough(_, pos, _, _, p, ap, _, config) and
parameterFlowsThroughRev(p, ap, pos, _, config)
)
}
@@ -1933,20 +1911,21 @@ private module MkStage<StageSig PrevStage> {
predicate returnMayFlowThrough(
RetNodeEx ret, Ap argAp, Ap ap, ReturnKindExt kind, Configuration config
) {
exists(ParamNodeEx p |
returnFlowsThrough(ret, kind, _, _, p, argAp, ap, config) and
parameterFlowsThroughRev(p, argAp, kind, ap, config)
exists(ParamNodeEx p, ReturnPosition pos |
returnFlowsThrough(ret, pos, _, _, p, argAp, ap, config) and
parameterFlowsThroughRev(p, argAp, pos, ap, config) and
kind = pos.getKind()
)
}
pragma[nomagic]
predicate revFlowInToReturnIsReturned(
private predicate revFlowThroughArg(
DataFlowCall call, ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp,
Ap ap, Configuration config
) {
exists(ReturnKindExt returnKind0, Ap returnAp0 |
revFlowInToReturn(call, arg, state, returnKind0, returnAp0, ap, config) and
revFlowIsReturned(call, returnCtx, returnAp, returnKind0, returnAp0, config)
exists(ParamNodeEx p, Ap innerReturnAp |
revFlowThrough(call, returnCtx, p, state, _, returnAp, ap, innerReturnAp, config) and
flowThroughIntoCall(call, arg, p, _, ap, innerReturnAp, config)
)
}
@@ -1954,7 +1933,7 @@ private module MkStage<StageSig PrevStage> {
predicate callMayFlowThroughRev(DataFlowCall call, Configuration config) {
exists(ArgNodeEx arg, FlowState state, ReturnCtx returnCtx, ApOption returnAp, Ap ap |
revFlow(arg, state, returnCtx, returnAp, ap, config) and
revFlowInToReturnIsReturned(call, arg, state, returnCtx, returnAp, ap, config)
revFlowThroughArg(call, arg, state, returnCtx, returnAp, ap, config)
)
}
@@ -1967,8 +1946,9 @@ private module MkStage<StageSig PrevStage> {
conscand = count(TypedContent f0, Ap ap | fwdConsCand(f0, ap, config)) and
states = count(FlowState state | fwdFlow(_, state, _, _, _, _, config)) and
tuples =
count(NodeEx n, FlowState state, Cc cc, ParameterPositionOption summaryCtx, ApOption argAp,
Ap ap | fwdFlow(n, state, cc, summaryCtx, argAp, ap, config))
count(NodeEx n, FlowState state, Cc cc, ParamNodeOption summaryCtx, ApOption argAp, Ap ap |
fwdFlow(n, state, cc, summaryCtx, argAp, ap, config)
)
or
fwd = false and
nodes = count(NodeEx node | revFlow(node, _, _, _, _, config)) and
@@ -2823,13 +2803,12 @@ private Configuration unbindConf(Configuration conf) {
pragma[nomagic]
private predicate nodeMayUseSummary0(
NodeEx n, DataFlowCallable c, ParameterPosition pos, FlowState state, AccessPathApprox apa,
Configuration config
NodeEx n, ParamNodeEx p, FlowState state, AccessPathApprox apa, Configuration config
) {
exists(AccessPathApprox apa0 |
c = n.getEnclosingCallable() and
Stage5::parameterMayFlowThrough(p, _, _) and
Stage5::revFlow(n, state, TReturnCtxMaybeFlowThrough(_), _, apa0, config) and
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParameterPositionSome(pos),
Stage5::fwdFlow(n, state, any(CallContextCall ccc), TParamNodeSome(p.asNode()),
TAccessPathApproxSome(apa), apa0, config)
)
}
@@ -2838,10 +2817,9 @@ pragma[nomagic]
private predicate nodeMayUseSummary(
NodeEx n, FlowState state, AccessPathApprox apa, Configuration config
) {
exists(DataFlowCallable c, ParameterPosition pos, ParamNodeEx p |
exists(ParamNodeEx p |
Stage5::parameterMayFlowThrough(p, apa, config) and
nodeMayUseSummary0(n, c, pos, state, apa, config) and
p.isParameterOf(c, pos)
nodeMayUseSummary0(n, p, state, apa, config)
)
}
@@ -3771,8 +3749,8 @@ private predicate paramFlowsThrough(
ReturnKindExt kind, FlowState state, CallContextCall cc, SummaryCtxSome sc, AccessPath ap,
AccessPathApprox apa, Configuration config
) {
exists(PathNodeMid mid, RetNodeEx ret |
pathNode(mid, ret, state, cc, sc, ap, config, _) and
exists(RetNodeEx ret |
pathNode(_, ret, state, cc, sc, ap, config, _) and
kind = ret.getKind() and
apa = ap.getApprox() and
parameterFlowThroughAllowed(sc.getParamNode(), kind)
@@ -4234,17 +4212,15 @@ private module FlowExploration {
ap = TRevPartialNil() and
exists(config.explorationLimit())
or
exists(PartialPathNodeRev mid |
revPartialPathStep(mid, node, state, sc1, sc2, sc3, ap, config) and
not clearsContentEx(node, ap.getHead()) and
(
notExpectsContent(node) or
expectsContentEx(node, ap.getHead())
) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
)
revPartialPathStep(_, node, state, sc1, sc2, sc3, ap, config) and
not clearsContentEx(node, ap.getHead()) and
(
notExpectsContent(node) or
expectsContentEx(node, ap.getHead())
) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
distSink(node.getEnclosingCallable(), config) <= config.explorationLimit()
}
pragma[nomagic]
@@ -4252,19 +4228,17 @@ private module FlowExploration {
NodeEx node, FlowState state, CallContext cc, TSummaryCtx1 sc1, TSummaryCtx2 sc2,
TSummaryCtx3 sc3, PartialAccessPath ap, Configuration config
) {
exists(PartialPathNodeFwd mid |
partialPathStep(mid, node, state, cc, sc1, sc2, sc3, ap, config) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
not clearsContentEx(node, ap.getHead().getContent()) and
(
notExpectsContent(node) or
expectsContentEx(node, ap.getHead().getContent())
) and
if node.asNode() instanceof CastingNode
then compatibleTypes(node.getDataFlowType(), ap.getType())
else any()
)
partialPathStep(_, node, state, cc, sc1, sc2, sc3, ap, config) and
not fullBarrier(node, config) and
not stateBarrier(node, state, config) and
not clearsContentEx(node, ap.getHead().getContent()) and
(
notExpectsContent(node) or
expectsContentEx(node, ap.getHead().getContent())
) and
if node.asNode() instanceof CastingNode
then compatibleTypes(node.getDataFlowType(), ap.getType())
else any()
}
/**

View File

@@ -916,15 +916,15 @@ private module Cached {
TDataFlowCallSome(DataFlowCall call)
cached
newtype TParameterPositionOption =
TParameterPositionNone() or
TParameterPositionSome(ParameterPosition pos)
newtype TParamNodeOption =
TParamNodeNone() or
TParamNodeSome(ParamNode p)
cached
newtype TReturnCtx =
TReturnCtxNone() or
TReturnCtxNoFlowThrough() or
TReturnCtxMaybeFlowThrough(ReturnKindExt kind)
TReturnCtxMaybeFlowThrough(ReturnPosition pos)
cached
newtype TTypedContentApprox =
@@ -1343,15 +1343,15 @@ class DataFlowCallOption extends TDataFlowCallOption {
}
}
/** An optional `ParameterPosition`. */
class ParameterPositionOption extends TParameterPositionOption {
/** An optional `ParamNode`. */
class ParamNodeOption extends TParamNodeOption {
string toString() {
this = TParameterPositionNone() and
this = TParamNodeNone() and
result = "(none)"
or
exists(ParameterPosition pos |
this = TParameterPositionSome(pos) and
result = pos.toString()
exists(ParamNode p |
this = TParamNodeSome(p) and
result = p.toString()
)
}
}
@@ -1363,7 +1363,7 @@ class ParameterPositionOption extends TParameterPositionOption {
*
* - `TReturnCtxNone()`: no return flow.
* - `TReturnCtxNoFlowThrough()`: return flow, but flow through is not possible.
* - `TReturnCtxMaybeFlowThrough(ReturnKindExt kind)`: return flow, of kind `kind`, and
* - `TReturnCtxMaybeFlowThrough(ReturnPosition pos)`: return flow, of kind `pos`, and
* flow through may be possible.
*/
class ReturnCtx extends TReturnCtx {
@@ -1374,9 +1374,9 @@ class ReturnCtx extends TReturnCtx {
this = TReturnCtxNoFlowThrough() and
result = "(no flow through)"
or
exists(ReturnKindExt kind |
this = TReturnCtxMaybeFlowThrough(kind) and
result = kind.toString()
exists(ReturnPosition pos |
this = TReturnCtxMaybeFlowThrough(pos) and
result = pos.toString()
)
}
}

View File

@@ -45,6 +45,16 @@ module Consistency {
) {
none()
}
/** Holds if `(c, pos, p)` should be excluded from the consistency test `uniqueParameterNodeAtPosition`. */
predicate uniqueParameterNodeAtPositionExclude(DataFlowCallable c, ParameterPosition pos, Node p) {
none()
}
/** Holds if `(c, pos, p)` should be excluded from the consistency test `uniqueParameterNodePosition`. */
predicate uniqueParameterNodePositionExclude(DataFlowCallable c, ParameterPosition pos, Node p) {
none()
}
}
private class RelevantNode extends Node {
@@ -101,9 +111,7 @@ module Consistency {
exists(int c |
c =
strictcount(Node n |
not exists(string filepath, int startline, int startcolumn, int endline, int endcolumn |
n.hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
) and
not n.hasLocationInfo(_, _, _, _, _) and
not any(ConsistencyConfiguration conf).missingLocationExclude(n)
) and
msg = "Nodes without location: " + c
@@ -248,6 +256,7 @@ module Consistency {
query predicate uniqueParameterNodeAtPosition(
DataFlowCallable c, ParameterPosition pos, Node p, string msg
) {
not any(ConsistencyConfiguration conf).uniqueParameterNodeAtPositionExclude(c, pos, p) and
isParameterNode(p, c, pos) and
not exists(unique(Node p0 | isParameterNode(p0, c, pos))) and
msg = "Parameters with overlapping positions."
@@ -256,6 +265,7 @@ module Consistency {
query predicate uniqueParameterNodePosition(
DataFlowCallable c, ParameterPosition pos, Node p, string msg
) {
not any(ConsistencyConfiguration conf).uniqueParameterNodePositionExclude(c, pos, p) and
isParameterNode(p, c, pos) and
not exists(unique(ParameterPosition pos0 | isParameterNode(p, c, pos0))) and
msg = "Parameter node with multiple positions."

View File

@@ -30,6 +30,7 @@ private newtype TOpcode =
TNegate() or
TShiftLeft() or
TShiftRight() or
TUnsignedShiftRight() or
TBitAnd() or
TBitOr() or
TBitXor() or
@@ -652,6 +653,15 @@ module Opcode {
final override string toString() { result = "ShiftRight" }
}
/**
* The `Opcode` for a `UnsignedShiftRightInstruction`.
*
* See the `UnsignedShiftRightInstruction` documentation for more details.
*/
class UnsignedShiftRight extends BinaryBitwiseOpcode, TUnsignedShiftRight {
final override string toString() { result = "UnsignedShiftRight" }
}
/**
* The `Opcode` for a `BitAndInstruction`.
*

View File

@@ -1204,6 +1204,17 @@ class ShiftRightInstruction extends BinaryBitwiseInstruction {
ShiftRightInstruction() { this.getOpcode() instanceof Opcode::ShiftRight }
}
/**
* An instruction that shifts its left operand to the right by the number of bits specified by its
* right operand.
*
* Both operands must have an integer type. The result has the same type as the left operand.
* The leftmost bits are zero-filled.
*/
class UnsignedShiftRightInstruction extends BinaryBitwiseInstruction {
UnsignedShiftRightInstruction() { this.getOpcode() instanceof Opcode::UnsignedShiftRight }
}
/**
* An instruction that performs a binary arithmetic operation involving at least one pointer
* operand.

View File

@@ -45,7 +45,7 @@ class Operand extends TStageOperand {
this = reusedPhiOperand(use, def, predecessorBlock, _)
)
or
exists(Instruction use | this = chiOperand(use, _))
this = chiOperand(_, _)
}
/** Gets a textual representation of this element. */

View File

@@ -329,12 +329,12 @@ private module Cached {
cached
Instruction getChiInstructionTotalOperand(ChiInstruction chiInstr) {
exists(
Alias::VirtualVariable vvar, OldInstruction oldInstr, Alias::MemoryLocation defLocation,
OldBlock defBlock, int defRank, int defOffset, OldBlock useBlock, int useRank
Alias::VirtualVariable vvar, OldInstruction oldInstr, OldBlock defBlock, int defRank,
int defOffset, OldBlock useBlock, int useRank
|
chiInstr = getChi(oldInstr) and
vvar = Alias::getResultMemoryLocation(oldInstr).getVirtualVariable() and
hasDefinitionAtRank(vvar, defLocation, defBlock, defRank, defOffset) and
hasDefinitionAtRank(vvar, _, defBlock, defRank, defOffset) and
hasUseAtRank(vvar, useBlock, useRank, oldInstr) and
definitionReachesUse(vvar, defBlock, defRank, useBlock, useRank) and
result = getDefinitionOrChiInstruction(defBlock, defOffset, vvar, _)

View File

@@ -1204,6 +1204,17 @@ class ShiftRightInstruction extends BinaryBitwiseInstruction {
ShiftRightInstruction() { this.getOpcode() instanceof Opcode::ShiftRight }
}
/**
* An instruction that shifts its left operand to the right by the number of bits specified by its
* right operand.
*
* Both operands must have an integer type. The result has the same type as the left operand.
* The leftmost bits are zero-filled.
*/
class UnsignedShiftRightInstruction extends BinaryBitwiseInstruction {
UnsignedShiftRightInstruction() { this.getOpcode() instanceof Opcode::UnsignedShiftRight }
}
/**
* An instruction that performs a binary arithmetic operation involving at least one pointer
* operand.

View File

@@ -45,7 +45,7 @@ class Operand extends TStageOperand {
this = reusedPhiOperand(use, def, predecessorBlock, _)
)
or
exists(Instruction use | this = chiOperand(use, _))
this = chiOperand(_, _)
}
/** Gets a textual representation of this element. */

View File

@@ -72,7 +72,19 @@ newtype TInstructionTag =
AsmInputTag(int elementIndex) { exists(AsmStmt asm | exists(asm.getChild(elementIndex))) } or
ThisAddressTag() or
ThisLoadTag() or
StructuredBindingAccessTag()
StructuredBindingAccessTag() or
// The next three cases handle generation of the constants -1, 0 and 1 for __except handling.
TryExceptGenerateNegativeOne() or
TryExceptGenerateZero() or
TryExceptGenerateOne() or
// The next three cases handle generation of comparisons for __except handling.
TryExceptCompareNegativeOne() or
TryExceptCompareZero() or
TryExceptCompareOne() or
// The next three cases handle generation of branching for __except handling.
TryExceptCompareNegativeOneBranch() or
TryExceptCompareZeroBranch() or
TryExceptCompareOneBranch()
class InstructionTag extends TInstructionTag {
final string toString() { result = "Tag" }
@@ -224,4 +236,22 @@ string getInstructionTagId(TInstructionTag tag) {
tag = ThisLoadTag() and result = "ThisLoad"
or
tag = StructuredBindingAccessTag() and result = "StructuredBindingAccess"
or
tag = TryExceptCompareNegativeOne() and result = "TryExceptCompareNegativeOne"
or
tag = TryExceptCompareZero() and result = "TryExceptCompareZero"
or
tag = TryExceptCompareOne() and result = "TryExceptCompareOne"
or
tag = TryExceptGenerateNegativeOne() and result = "TryExceptGenerateNegativeOne"
or
tag = TryExceptGenerateZero() and result = "TryExceptGenerateNegativeOne"
or
tag = TryExceptGenerateOne() and result = "TryExceptGenerateOne"
or
tag = TryExceptCompareNegativeOneBranch() and result = "TryExceptCompareNegativeOneBranch"
or
tag = TryExceptCompareZeroBranch() and result = "TryExceptCompareZeroBranch"
or
tag = TryExceptCompareOneBranch() and result = "TryExceptCompareOneBranch"
}

View File

@@ -675,6 +675,7 @@ newtype TTranslatedElement =
} or
// A statement
TTranslatedStmt(Stmt stmt) { translateStmt(stmt) } or
TTranslatedMicrosoftTryExceptHandler(MicrosoftTryExceptStmt stmt) or
// A function
TTranslatedFunction(Function func) { translateFunction(func) } or
// A constructor init list

View File

@@ -298,11 +298,11 @@ class TranslatedStringLiteralInitialization extends TranslatedDirectInitializati
opcode instanceof Opcode::Store and
resultType = getTypeForPRValue(expr.getType())
or
exists(int startIndex, int elementCount |
exists(int elementCount |
// If the initializer string isn't large enough to fill the target, then
// we have to generate another instruction sequence to store a constant
// zero into the remainder of the array.
zeroInitRange(startIndex, elementCount) and
zeroInitRange(_, elementCount) and
(
// Create a constant zero whose size is the size of the remaining
// space in the target array.

View File

@@ -13,6 +13,222 @@ private import TranslatedInitialization
TranslatedStmt getTranslatedStmt(Stmt stmt) { result.getAst() = stmt }
TranslatedMicrosoftTryExceptHandler getTranslatedMicrosoftTryExceptHandler(
MicrosoftTryExceptStmt tryExcept
) {
result.getAst() = tryExcept.getExcept()
}
class TranslatedMicrosoftTryExceptHandler extends TranslatedElement,
TTranslatedMicrosoftTryExceptHandler {
MicrosoftTryExceptStmt tryExcept;
TranslatedMicrosoftTryExceptHandler() { this = TTranslatedMicrosoftTryExceptHandler(tryExcept) }
final override string toString() { result = tryExcept.toString() }
final override Locatable getAst() { result = tryExcept.getExcept() }
override Instruction getFirstInstruction() { result = this.getChild(0).getFirstInstruction() }
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
// t1 = -1
tag = TryExceptGenerateNegativeOne() and
opcode instanceof Opcode::Constant and
resultType = getIntType()
or
// t2 = cmp t1, condition
tag = TryExceptCompareNegativeOne() and
opcode instanceof Opcode::CompareEQ and
resultType = getBoolType()
or
// if t2 goto ... else goto ...
tag = TryExceptCompareNegativeOneBranch() and
opcode instanceof Opcode::ConditionalBranch and
resultType = getVoidType()
or
// t1 = 0
tag = TryExceptGenerateZero() and
opcode instanceof Opcode::Constant and
resultType = getIntType()
or
// t2 = cmp t1, condition
tag = TryExceptCompareZero() and
opcode instanceof Opcode::CompareEQ and
resultType = getBoolType()
or
// if t2 goto ... else goto ...
tag = TryExceptCompareZeroBranch() and
opcode instanceof Opcode::ConditionalBranch and
resultType = getVoidType()
or
// t1 = 1
tag = TryExceptGenerateOne() and
opcode instanceof Opcode::Constant and
resultType = getIntType()
or
// t2 = cmp t1, condition
tag = TryExceptCompareOne() and
opcode instanceof Opcode::CompareEQ and
resultType = getBoolType()
or
// if t2 goto ... else goto ...
tag = TryExceptCompareOneBranch() and
opcode instanceof Opcode::ConditionalBranch and
resultType = getVoidType()
or
// unwind stack
tag = UnwindTag() and
opcode instanceof Opcode::Unwind and
resultType = getVoidType()
}
final override Instruction getInstructionRegisterOperand(InstructionTag tag, OperandTag operandTag) {
tag = TryExceptCompareNegativeOne() and
(
operandTag instanceof LeftOperandTag and
result = this.getTranslatedCondition().getResult()
or
operandTag instanceof RightOperandTag and
result = this.getInstruction(TryExceptGenerateNegativeOne())
)
or
tag = TryExceptCompareNegativeOneBranch() and
operandTag instanceof ConditionOperandTag and
result = this.getInstruction(TryExceptCompareNegativeOne())
or
tag = TryExceptCompareZero() and
(
operandTag instanceof LeftOperandTag and
result = this.getTranslatedCondition().getResult()
or
operandTag instanceof RightOperandTag and
result = this.getInstruction(TryExceptGenerateZero())
)
or
tag = TryExceptCompareZeroBranch() and
operandTag instanceof ConditionOperandTag and
result = this.getInstruction(TryExceptCompareZero())
or
tag = TryExceptCompareOne() and
(
operandTag instanceof LeftOperandTag and
result = this.getTranslatedCondition().getResult()
or
operandTag instanceof RightOperandTag and
result = this.getInstruction(TryExceptGenerateOne())
)
or
tag = TryExceptCompareOneBranch() and
operandTag instanceof ConditionOperandTag and
result = this.getInstruction(TryExceptCompareOne())
}
override string getInstructionConstantValue(InstructionTag tag) {
tag = TryExceptGenerateNegativeOne() and
result = "-1"
or
tag = TryExceptGenerateZero() and
result = "0"
or
tag = TryExceptGenerateOne() and
result = "1"
}
override Instruction getInstructionSuccessor(InstructionTag tag, EdgeKind kind) {
// Generate -1 -> Compare condition
tag = TryExceptGenerateNegativeOne() and
kind instanceof GotoEdge and
result = this.getInstruction(TryExceptCompareNegativeOne())
or
// Compare condition -> Branch
tag = TryExceptCompareNegativeOne() and
kind instanceof GotoEdge and
result = this.getInstruction(TryExceptCompareNegativeOneBranch())
or
// Branch -> Unwind or Generate 0
tag = TryExceptCompareNegativeOneBranch() and
(
kind instanceof TrueEdge and
// TODO: This is not really correct. The semantics of `EXCEPTION_CONTINUE_EXECUTION` is that
// we should continue execution at the point where the exception occurred. But we don't have
// any instruction to model this behavior.
result = this.getInstruction(UnwindTag())
or
kind instanceof FalseEdge and
result = this.getInstruction(TryExceptGenerateZero())
)
or
// Generate 0 -> Compare condition
tag = TryExceptGenerateZero() and
kind instanceof GotoEdge and
result = this.getInstruction(TryExceptCompareZero())
or
// Compare condition -> Branch
tag = TryExceptCompareZero() and
kind instanceof GotoEdge and
result = this.getInstruction(TryExceptCompareZeroBranch())
or
// Branch -> Unwind or Generate 1
tag = TryExceptCompareZeroBranch() and
(
kind instanceof TrueEdge and
result = this.getInstruction(UnwindTag())
or
kind instanceof FalseEdge and
result = this.getInstruction(TryExceptGenerateOne())
)
or
// Generate 1 -> Compare condition
tag = TryExceptGenerateOne() and
kind instanceof GotoEdge and
result = this.getInstruction(TryExceptCompareOne())
or
// Compare condition -> Branch
tag = TryExceptCompareOne() and
kind instanceof GotoEdge and
result = this.getInstruction(TryExceptCompareOneBranch())
or
// Branch -> Handler (the condition value is always 0, -1 or 1, and we've checked for 0 or -1 already.)
tag = TryExceptCompareOneBranch() and
(
kind instanceof TrueEdge and
result = this.getTranslatedHandler().getFirstInstruction()
)
or
// Unwind -> Parent
tag = UnwindTag() and
kind instanceof GotoEdge and
result = this.getParent().getChildSuccessor(this)
}
override Instruction getChildSuccessor(TranslatedElement child) {
child = this.getTranslatedCondition() and
result = this.getInstruction(TryExceptGenerateNegativeOne())
or
child = this.getTranslatedHandler() and
result = this.getParent().getChildSuccessor(this)
}
private TranslatedExpr getTranslatedCondition() {
result = getTranslatedExpr(tryExcept.getCondition())
}
private TranslatedStmt getTranslatedHandler() {
result = getTranslatedStmt(tryExcept.getExcept())
}
override TranslatedElement getChild(int id) {
id = 0 and
result = this.getTranslatedCondition()
or
id = 1 and
result = this.getTranslatedHandler()
}
final override Function getFunction() { result = tryExcept.getEnclosingFunction() }
}
abstract class TranslatedStmt extends TranslatedElement, TTranslatedStmt {
Stmt stmt;
@@ -249,15 +465,57 @@ class TranslatedUnreachableReturnStmt extends TranslatedReturnStmt {
}
/**
* The IR translation of a C++ `try` statement.
* A C/C++ `try` statement, or a `__try __except` or `__try __finally` statement.
*/
private class TryOrMicrosoftTryStmt extends Stmt {
TryOrMicrosoftTryStmt() {
this instanceof TryStmt or
this instanceof MicrosoftTryStmt
}
/** Gets the number of `catch block`s of this statement. */
int getNumberOfCatchClauses() {
result = this.(TryStmt).getNumberOfCatchClauses()
or
this instanceof MicrosoftTryExceptStmt and
result = 1
or
this instanceof MicrosoftTryFinallyStmt and
result = 0
}
/** Gets the `body` statement of this statement. */
Stmt getStmt() {
result = this.(TryStmt).getStmt()
or
result = this.(MicrosoftTryStmt).getStmt()
}
/** Gets the `i`th translated handler of this statement. */
TranslatedElement getTranslatedHandler(int index) {
result = getTranslatedStmt(this.(TryStmt).getChild(index + 1))
or
index = 0 and
result = getTranslatedMicrosoftTryExceptHandler(this)
}
/** Gets the `finally` statement (usually a BlockStmt), if any. */
Stmt getFinally() { result = this.(MicrosoftTryFinallyStmt).getFinally() }
}
/**
* The IR translation of a C++ `try` (or a `__try __except` or `__try __finally`) statement.
*/
class TranslatedTryStmt extends TranslatedStmt {
override TryStmt stmt;
override TryOrMicrosoftTryStmt stmt;
override TranslatedElement getChild(int id) {
id = 0 and result = getBody()
or
result = getHandler(id - 1)
or
id = stmt.getNumberOfCatchClauses() + 1 and
result = this.getFinally()
}
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CppType resultType) {
@@ -269,8 +527,20 @@ class TranslatedTryStmt extends TranslatedStmt {
override Instruction getFirstInstruction() { result = getBody().getFirstInstruction() }
override Instruction getChildSuccessor(TranslatedElement child) {
// All children go to the successor of the `try`.
child = getAChild() and result = getParent().getChildSuccessor(this)
// All non-finally children go to the successor of the `try` if
// there is no finally block, but if there is a finally block
// then we go to that one.
child = [this.getBody(), this.getHandler(_)] and
(
not exists(this.getFinally()) and
result = this.getParent().getChildSuccessor(this)
or
result = this.getFinally().getFirstInstruction()
)
or
// And after the finally block we go to the successor of the `try`.
child = this.getFinally() and
result = this.getParent().getChildSuccessor(this)
}
final Instruction getNextHandler(TranslatedHandler handler) {
@@ -290,9 +560,9 @@ class TranslatedTryStmt extends TranslatedStmt {
result = getHandler(0).getFirstInstruction()
}
private TranslatedHandler getHandler(int index) {
result = getTranslatedStmt(stmt.getChild(index + 1))
}
private TranslatedElement getHandler(int index) { result = stmt.getTranslatedHandler(index) }
private TranslatedStmt getFinally() { result = getTranslatedStmt(stmt.getFinally()) }
private TranslatedStmt getBody() { result = getTranslatedStmt(stmt.getStmt()) }
}

View File

@@ -1204,6 +1204,17 @@ class ShiftRightInstruction extends BinaryBitwiseInstruction {
ShiftRightInstruction() { this.getOpcode() instanceof Opcode::ShiftRight }
}
/**
* An instruction that shifts its left operand to the right by the number of bits specified by its
* right operand.
*
* Both operands must have an integer type. The result has the same type as the left operand.
* The leftmost bits are zero-filled.
*/
class UnsignedShiftRightInstruction extends BinaryBitwiseInstruction {
UnsignedShiftRightInstruction() { this.getOpcode() instanceof Opcode::UnsignedShiftRight }
}
/**
* An instruction that performs a binary arithmetic operation involving at least one pointer
* operand.

View File

@@ -45,7 +45,7 @@ class Operand extends TStageOperand {
this = reusedPhiOperand(use, def, predecessorBlock, _)
)
or
exists(Instruction use | this = chiOperand(use, _))
this = chiOperand(_, _)
}
/** Gets a textual representation of this element. */

View File

@@ -329,12 +329,12 @@ private module Cached {
cached
Instruction getChiInstructionTotalOperand(ChiInstruction chiInstr) {
exists(
Alias::VirtualVariable vvar, OldInstruction oldInstr, Alias::MemoryLocation defLocation,
OldBlock defBlock, int defRank, int defOffset, OldBlock useBlock, int useRank
Alias::VirtualVariable vvar, OldInstruction oldInstr, OldBlock defBlock, int defRank,
int defOffset, OldBlock useBlock, int useRank
|
chiInstr = getChi(oldInstr) and
vvar = Alias::getResultMemoryLocation(oldInstr).getVirtualVariable() and
hasDefinitionAtRank(vvar, defLocation, defBlock, defRank, defOffset) and
hasDefinitionAtRank(vvar, _, defBlock, defRank, defOffset) and
hasUseAtRank(vvar, useBlock, useRank, oldInstr) and
definitionReachesUse(vvar, defBlock, defRank, useBlock, useRank) and
result = getDefinitionOrChiInstruction(defBlock, defOffset, vvar, _)

View File

@@ -67,9 +67,7 @@ class Class = Cpp::Class; // Used for inheritance conversions
predicate getIdentityString = Print::getIdentityString/1;
predicate hasCaseEdge(string minValue, string maxValue) {
exists(Cpp::SwitchCase switchCase | hasCaseEdge(switchCase, minValue, maxValue))
}
predicate hasCaseEdge(string minValue, string maxValue) { hasCaseEdge(_, minValue, maxValue) }
predicate hasPositionalArgIndex(int argIndex) {
exists(Cpp::FunctionCall call | exists(call.getArgument(argIndex))) or

View File

@@ -99,10 +99,10 @@ class MetricClass extends Class {
}
/** Gets any method that accesses some local field. */
Function getAccessingMethod() { exists(Field f | this.accessesLocalField(result, f)) }
Function getAccessingMethod() { this.accessesLocalField(result, _) }
/** Gets any field that is accessed by a local method. */
Field getAccessedField() { exists(Function func | this.accessesLocalField(func, result)) }
Field getAccessedField() { this.accessesLocalField(_, result) }
/** Gets the Henderson-Sellers lack-of-cohesion metric. */
float getLackOfCohesionHS() {
@@ -517,10 +517,10 @@ private predicate dependsOnClassSimple(Class source, Class dest) {
)
or
// a class depends on classes for which a call to its member function is done from a function
exists(MemberFunction target, MemberFunction f, Locatable l |
exists(MemberFunction target, MemberFunction f |
f.getDeclaringType() = source and
f instanceof MemberFunction and
f.calls(target, l) and
f.calls(target, _) and
target instanceof MemberFunction and
target.getDeclaringType() = dest
)

View File

@@ -133,13 +133,15 @@ abstract class HeuristicAllocationExpr extends Expr {
/**
* Gets a constant multiplier for the allocation size given by `getSizeExpr`,
* in bytes.
* in bytes. This predicate should be used with caution as it can be
* inaccurate for allocations identified using heuristics.
*/
int getSizeMult() { none() }
/**
* Gets the size of this allocation in bytes, if it is a fixed size and that
* size can be determined.
* size can be determined. This predicate should be used with caution as it
* can be inaccurate for allocations identified using heuristics.
*/
int getSizeBytes() { none() }

View File

@@ -296,7 +296,7 @@ private predicate analyzableExpr(Expr e) {
or
// Also allow variable accesses, provided that they have SSA
// information.
exists(RangeSsaDefinition def, StackVariable v | e = def.getAUse(v))
exists(RangeSsaDefinition def | e = def.getAUse(_))
or
e instanceof UnsignedBitwiseAndExpr
or

View File

@@ -92,7 +92,7 @@ private class ArgvSource extends LocalFlowSource {
exists(Function main, Parameter argv |
main.hasGlobalName("main") and
main.getParameter(1) = argv and
this.asExpr() = argv.getAnAccess()
this.asParameter() = argv
)
}

View File

@@ -127,9 +127,9 @@ deprecated private predicate betweenFunctionsValueMoveTo(
not unreachable(src) and
not unreachable(dest) and
(
exists(Call call, Function called, int i |
exists(Call call, int i |
src = call.getArgument(i) and
resolveCallWithParam(call, called, i, dest) and
resolveCallWithParam(call, _, i, dest) and
destFromArg = true
)
or
@@ -151,8 +151,8 @@ deprecated private predicate betweenFunctionsValueMoveTo(
)
or
// If a parameter of type reference is tainted inside a function, taint the argument too
exists(Call call, Function f, int pi, Parameter p |
resolveCallWithParam(call, f, pi, p) and
exists(Call call, int pi, Parameter p |
resolveCallWithParam(call, _, pi, p) and
p.getType() instanceof ReferenceType and
src = p and
dest = call.getArgument(pi) and

View File

@@ -34,7 +34,7 @@ class Stmt extends StmtParent, @stmt {
}
/** Gets a child of this statement. */
Element getAChild() { exists(int n | result = this.getChild(n)) }
Element getAChild() { result = this.getChild(_) }
/** Gets the parent of this statement, if any. */
StmtParent getParent() { stmtparents(underlyingElement(this), _, unresolveElement(result)) }

View File

@@ -183,7 +183,7 @@ private newtype GvnBase =
// global variable will only get the same value number if they are
// guaranteed to have the same value.
GVN_OtherVariable(Variable x, ControlFlowNode dominator) { mk_OtherVariable(x, dominator, _) } or
GVN_FieldAccess(GVN s, Field f) {
deprecated GVN_FieldAccess(GVN s, Field f) {
mk_DotFieldAccess(s, f, _) or
mk_PointerFieldAccess_with_deref(s, f, _) or
mk_ImplicitThisFieldAccess_with_deref(s, f, _)
@@ -192,7 +192,7 @@ private newtype GvnBase =
// time the pointer was dereferenced, so we need to include a definition
// location. As a crude (but safe) approximation, we use
// `mostRecentSideEffect` to compute a definition location.
GVN_Deref(GVN p, ControlFlowNode dominator) {
deprecated GVN_Deref(GVN p, ControlFlowNode dominator) {
mk_Deref(p, dominator, _) or
mk_PointerFieldAccess(p, _, dominator, _) or
mk_ImplicitThisFieldAccess_with_qualifier(p, _, dominator, _)
@@ -201,10 +201,12 @@ private newtype GvnBase =
mk_ThisExpr(fcn, _) or
mk_ImplicitThisFieldAccess(fcn, _, _, _)
} or
GVN_Conversion(Type t, GVN child) { mk_Conversion(t, child, _) } or
GVN_BinaryOp(GVN lhs, GVN rhs, string opname) { mk_BinaryOp(lhs, rhs, opname, _) } or
GVN_UnaryOp(GVN child, string opname) { mk_UnaryOp(child, opname, _) } or
GVN_ArrayAccess(GVN x, GVN i, ControlFlowNode dominator) { mk_ArrayAccess(x, i, dominator, _) } or
deprecated GVN_Conversion(Type t, GVN child) { mk_Conversion(t, child, _) } or
deprecated GVN_BinaryOp(GVN lhs, GVN rhs, string opname) { mk_BinaryOp(lhs, rhs, opname, _) } or
deprecated GVN_UnaryOp(GVN child, string opname) { mk_UnaryOp(child, opname, _) } or
deprecated GVN_ArrayAccess(GVN x, GVN i, ControlFlowNode dominator) {
mk_ArrayAccess(x, i, dominator, _)
} or
// Any expression that is not handled by the cases above is
// given a unique number based on the expression itself.
GVN_Unanalyzable(Expr e) { not analyzableExpr(e) }
@@ -340,7 +342,7 @@ private predicate analyzableDotFieldAccess(DotFieldAccess access) {
not analyzableConst(access)
}
private predicate mk_DotFieldAccess(GVN qualifier, Field target, DotFieldAccess access) {
deprecated private predicate mk_DotFieldAccess(GVN qualifier, Field target, DotFieldAccess access) {
analyzableDotFieldAccess(access) and
target = access.getTarget() and
qualifier = globalValueNumber(access.getQualifier().getFullyConverted())
@@ -353,7 +355,7 @@ private predicate analyzablePointerFieldAccess(PointerFieldAccess access) {
not analyzableConst(access)
}
private predicate mk_PointerFieldAccess(
deprecated private predicate mk_PointerFieldAccess(
GVN qualifier, Field target, ControlFlowNode dominator, PointerFieldAccess access
) {
analyzablePointerFieldAccess(access) and
@@ -366,7 +368,7 @@ private predicate mk_PointerFieldAccess(
* `obj->field` is equivalent to `(*obj).field`, so we need to wrap an
* extra `GVN_Deref` around the qualifier.
*/
private predicate mk_PointerFieldAccess_with_deref(
deprecated private predicate mk_PointerFieldAccess_with_deref(
GVN new_qualifier, Field target, PointerFieldAccess access
) {
exists(GVN qualifier, ControlFlowNode dominator |
@@ -391,7 +393,7 @@ private predicate mk_ImplicitThisFieldAccess(
fcn = access.getEnclosingFunction()
}
private predicate mk_ImplicitThisFieldAccess_with_qualifier(
deprecated private predicate mk_ImplicitThisFieldAccess_with_qualifier(
GVN qualifier, Field target, ControlFlowNode dominator, ImplicitThisFieldAccess access
) {
exists(Function fcn |
@@ -400,7 +402,7 @@ private predicate mk_ImplicitThisFieldAccess_with_qualifier(
)
}
private predicate mk_ImplicitThisFieldAccess_with_deref(
deprecated private predicate mk_ImplicitThisFieldAccess_with_deref(
GVN new_qualifier, Field target, ImplicitThisFieldAccess access
) {
exists(GVN qualifier, ControlFlowNode dominator |
@@ -434,7 +436,7 @@ private predicate analyzableConversion(Conversion conv) {
not analyzableConst(conv)
}
private predicate mk_Conversion(Type t, GVN child, Conversion conv) {
deprecated private predicate mk_Conversion(Type t, GVN child, Conversion conv) {
analyzableConversion(conv) and
t = conv.getUnspecifiedType() and
child = globalValueNumber(conv.getExpr())
@@ -448,7 +450,7 @@ private predicate analyzableBinaryOp(BinaryOperation op) {
not analyzableConst(op)
}
private predicate mk_BinaryOp(GVN lhs, GVN rhs, string opname, BinaryOperation op) {
deprecated private predicate mk_BinaryOp(GVN lhs, GVN rhs, string opname, BinaryOperation op) {
analyzableBinaryOp(op) and
lhs = globalValueNumber(op.getLeftOperand().getFullyConverted()) and
rhs = globalValueNumber(op.getRightOperand().getFullyConverted()) and
@@ -463,7 +465,7 @@ private predicate analyzableUnaryOp(UnaryOperation op) {
not analyzableConst(op)
}
private predicate mk_UnaryOp(GVN child, string opname, UnaryOperation op) {
deprecated private predicate mk_UnaryOp(GVN child, string opname, UnaryOperation op) {
analyzableUnaryOp(op) and
child = globalValueNumber(op.getOperand().getFullyConverted()) and
opname = op.getOperator()
@@ -486,7 +488,9 @@ private predicate analyzableArrayAccess(ArrayExpr ae) {
not analyzableConst(ae)
}
private predicate mk_ArrayAccess(GVN base, GVN offset, ControlFlowNode dominator, ArrayExpr ae) {
deprecated private predicate mk_ArrayAccess(
GVN base, GVN offset, ControlFlowNode dominator, ArrayExpr ae
) {
analyzableArrayAccess(ae) and
base = globalValueNumber(ae.getArrayBase().getFullyConverted()) and
offset = globalValueNumber(ae.getArrayOffset().getFullyConverted()) and
@@ -499,7 +503,7 @@ private predicate analyzablePointerDereferenceExpr(PointerDereferenceExpr deref)
not analyzableConst(deref)
}
private predicate mk_Deref(GVN p, ControlFlowNode dominator, PointerDereferenceExpr deref) {
deprecated private predicate mk_Deref(GVN p, ControlFlowNode dominator, PointerDereferenceExpr deref) {
analyzablePointerDereferenceExpr(deref) and
p = globalValueNumber(deref.getOperand().getFullyConverted()) and
dominator = mostRecentSideEffect(deref)

View File

@@ -475,9 +475,7 @@ private predicate mk_NonmemberFunctionCall(Function fcn, HC_Args args, FunctionC
fc.getTarget() = fcn and
analyzableNonmemberFunctionCall(fc) and
(
exists(HashCons head, HC_Args tail |
mk_ArgConsInner(head, tail, fc.getNumberOfArguments() - 1, args, fc)
)
mk_ArgConsInner(_, _, fc.getNumberOfArguments() - 1, args, fc)
or
fc.getNumberOfArguments() = 0 and
args = HC_EmptyArgs()
@@ -494,9 +492,7 @@ private predicate analyzableExprCall(ExprCall ec) {
private predicate mk_ExprCall(HashCons hc, HC_Args args, ExprCall ec) {
hc.getAnExpr() = ec.getExpr() and
(
exists(HashCons head, HC_Args tail |
mk_ArgConsInner(head, tail, ec.getNumberOfArguments() - 1, args, ec)
)
mk_ArgConsInner(_, _, ec.getNumberOfArguments() - 1, args, ec)
or
ec.getNumberOfArguments() = 0 and
args = HC_EmptyArgs()
@@ -516,9 +512,7 @@ private predicate mk_MemberFunctionCall(Function fcn, HashCons qual, HC_Args arg
analyzableMemberFunctionCall(fc) and
hashCons(fc.getQualifier().getFullyConverted()) = qual and
(
exists(HashCons head, HC_Args tail |
mk_ArgConsInner(head, tail, fc.getNumberOfArguments() - 1, args, fc)
)
mk_ArgConsInner(_, _, fc.getNumberOfArguments() - 1, args, fc)
or
fc.getNumberOfArguments() = 0 and
args = HC_EmptyArgs()
@@ -541,10 +535,8 @@ private predicate mk_ArgCons(HashCons hc, int i, HC_Args list, Call c) {
analyzableCall(c) and
hc = hashCons(c.getArgument(i).getFullyConverted()) and
(
exists(HashCons head, HC_Args tail |
mk_ArgConsInner(head, tail, i - 1, list, c) and
i > 0
)
mk_ArgConsInner(_, _, i - 1, list, c) and
i > 0
or
i = 0 and
list = HC_EmptyArgs()

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