Compare commits

...

138 Commits

Author SHA1 Message Date
Esben Sparre Andreasen
e5d9f56a75 Remove some CodeInjection sinks 2022-01-31 11:15:11 +01:00
Max Schaefer
e12cd2c689 Revert "JS: Recognize DomSanitizer from @angular/core"
This reverts commit ff1d0cc4c7.
2021-11-18 15:01:27 +00:00
Henry Mercer
bc0994c69f Remove NoSQL sinks since September 2018 2021-11-18 15:01:26 +00:00
Esben Sparre Andreasen
6d02573e25 Remove additional Xss sinks 2021-11-18 15:01:26 +00:00
Esben Sparre Andreasen
1fd8d707b1 Remove additional SQL sinks 2021-11-18 15:01:26 +00:00
Esben Sparre Andreasen
6e8351b6e5 Remove additional path-injection sinks 2021-11-18 15:01:26 +00:00
Esben Sparre Andreasen
66915ff64c Add benjamin-button.md 2021-11-18 15:01:26 +00:00
Esben Sparre Andreasen
1a2b950df0 Remove pseudo-properties 2021-11-18 15:01:26 +00:00
Esben Sparre Andreasen
2a14ac93d4 Remove 2020 sinks from SqlInjection.ql 2021-11-18 15:01:26 +00:00
Esben Sparre Andreasen
c2e223ca44 Remove 2020 sinks from Xss.ql 2021-11-18 15:01:26 +00:00
Esben Sparre Andreasen
10e24ec5dd Remove 2020 sinks from TaintedPath.ql 2021-11-18 15:01:25 +00:00
Henry Mercer
46958e5bff Merge pull request #7168 from erik-krogh/useMinInsteadofRank1
ATM: use min() instead of rank[1]
2021-11-18 14:56:49 +00:00
Anders Schack-Mulligen
6815a13a00 Merge pull request #6931 from hvitved/dataflow/restrict-derived-summaries
Data flow: Restrict derived flow summaries
2021-11-18 15:31:55 +01:00
Erik Krogh Kristensen
2af7817691 use min() instead of rank[1] 2021-11-18 14:26:55 +01:00
Geoffrey White
6c2713dd8b Merge pull request #7159 from MathiasVP/pointers-are-always-iterators
C++: Always recognize pointers as iterators
2021-11-18 11:14:44 +00:00
Tony Torralba
9d22ec88fd Merge pull request #7165 from github/workflow/coverage/update
Update CSV framework coverage reports
2021-11-18 10:37:34 +01:00
Erik Krogh Kristensen
1cca377e7d Merge pull request #6561 from erik-krogh/htmlReg
JS/Py/Ruby: add a bad-tag-filter query
2021-11-18 09:39:13 +01:00
github-actions[bot]
ecdaeb0c10 Add changed framework coverage reports 2021-11-18 00:09:24 +00:00
Mathias Vorreiter Pedersen
c998370c84 C++: Accept more test changes. 2021-11-17 15:22:17 +00:00
Mathias Vorreiter Pedersen
36585a7469 C++: Accept test changes. 2021-11-17 14:41:30 +00:00
Mathias Vorreiter Pedersen
6dc6a78293 C++: Add a 'IteratorByPointer' class so pointers are always iterators. 2021-11-17 14:41:19 +00:00
Alex Ford
08b6a17097 Merge pull request #7151 from github/ruby/methodcallnode
Ruby: add `getMethodName` predicate to `DataFlow::CallNode` class
2021-11-17 14:40:07 +00:00
Anders Schack-Mulligen
22ebe68b1b Merge pull request #7132 from aschackmull/java/overrides
Java: Fix overrides to not be transitive.
2021-11-17 15:38:11 +01:00
Anders Schack-Mulligen
1645fcf79c Merge pull request #7088 from aschackmull/java/parameterized-subtyping
Java: Improve algorithm for subtyping of parameterized types.
2021-11-17 15:28:28 +01:00
Arthur Baars
5ddfb37f29 Merge pull request #7155 from aibaars/ruby-qualified-import
Ruby: QL generator: use qualified imports
2021-11-17 12:40:14 +01:00
Arthur Baars
6f24947ec6 Merge pull request #7156 from aibaars/ruby-prepare-db-upgrade-fix
Ruby: Fix scripts/prepare-db-upgrade.sh
2021-11-17 12:39:55 +01:00
Benjamin Muskalla
3c3a65243f Merge pull request #6664 from bmuskalla/bmuskalla/modelGenerator
Java: Initial CSV model generator
2021-11-17 12:30:45 +01:00
Arthur Baars
fbb3e8d780 Fix scripts/prepare-db-upgrade.sh 2021-11-17 12:11:20 +01:00
Geoffrey White
d232283647 Merge pull request #7149 from geoffw0/non-https-url2
C++: Minor improvements to 'Failure to use HTTPS URLs' query
2021-11-17 10:05:30 +00:00
Tom Hvitved
4eacbd1cbe Ruby: Sync files 2021-11-17 10:49:51 +01:00
Tom Hvitved
6d58dd2823 Java: Update expected test output 2021-11-17 10:49:51 +01:00
Tom Hvitved
3da73b9001 C#: Update expected test output 2021-11-17 10:49:49 +01:00
Tom Hvitved
58dd75881c C#: Update flow summary to avoid negative recursion 2021-11-17 10:39:13 +01:00
Tom Hvitved
ac41451798 Data flow: Sync files 2021-11-17 10:39:12 +01:00
Tom Hvitved
0c1285f5d9 Data flow: Restrict derived flow summaries 2021-11-17 10:39:12 +01:00
Arthur Baars
7c2841f058 Ruby: QL generator: use qualified imports 2021-11-17 10:37:44 +01:00
Erik Krogh Kristensen
474c808373 Merge pull request #7137 from erik-krogh/functionExport
JS: recognize library inputs when the library exports "through" a function
2021-11-17 09:49:02 +01:00
Anders Schack-Mulligen
69671ce90d Java: cache overrides 2021-11-17 09:16:58 +01:00
Tom Hvitved
7cfc696d62 Merge pull request #7141 from hvitved/ruby/synthesis-realnode-recursion
Ruby: Eliminate unnecessary recursion through `RealNode`
2021-11-17 09:03:30 +01:00
Pierre
f846915b58 Merge pull request #7069 from github/turbo-apple-silicon-requirements-1
Add requirements for Apple Silicon
2021-11-17 00:04:06 +01:00
Alex Ford
c8cdbfa352 ruby: push getMethodName into DataFlow::CallNode 2021-11-16 17:11:26 +00:00
Benjamin Muskalla
b4eadefb92 Fix test 2021-11-16 17:28:01 +01:00
Alex Ford
286c894f34 ruby: add DataFlow::MethodCallNode class 2021-11-16 15:39:47 +00:00
Chris Smowton
188915e597 Fix typos 2021-11-16 15:30:00 +00:00
Anders Schack-Mulligen
76606b5995 Java: Add more comments. 2021-11-16 16:11:14 +01:00
Geoffrey White
ea9640a39d C++: Autoformat. 2021-11-16 14:26:42 +00:00
Anders Schack-Mulligen
d408105fad Java: Fix bad join-order. 2021-11-16 14:25:19 +01:00
Geoffrey White
5ef71e6ef3 C++: Add a few more sinks. 2021-11-16 13:02:56 +00:00
Tom Hvitved
9e8e2e2b48 Ruby: Update CFG test output (some nodes have been reordered) 2021-11-16 12:45:24 +01:00
Tom Hvitved
e7b091086d Ruby: Eliminate unnecessary recursion through RealNode 2021-11-16 12:24:17 +01:00
Geoffrey White
aafa5762ad C++: Add a CWE tag associated with OWASP A8. 2021-11-16 11:21:25 +00:00
Benjamin Muskalla
0e6bb28016 Only consider store steps 2021-11-16 10:46:24 +01:00
Erik Krogh Kristensen
b9ea4a8709 recognize library inputs when the library exports "through" a function 2021-11-15 22:43:38 +01:00
Benjamin Muskalla
fd9199c0c0 Simplify handling of tainting fields 2021-11-15 16:40:09 +01:00
Benjamin Muskalla
d7ed325b3f Refactor content flow into predicate 2021-11-15 16:30:55 +01:00
Benjamin Muskalla
f4310898b3 Capture sources flowing into parameters 2021-11-15 16:28:28 +01:00
Anders Schack-Mulligen
1cd42ea668 Java: Fix test and some references. 2021-11-15 16:03:04 +01:00
Benjamin Muskalla
8040d9cfcf Only consider true return statements as sinks 2021-11-15 15:29:01 +01:00
Benjamin Muskalla
e6e52a3b32 190 2021-11-15 15:18:03 +01:00
Anders Schack-Mulligen
c616f5784d Java: Fix overrides to not be transitive. 2021-11-15 13:54:53 +01:00
Benjamin Muskalla
dc022430ee Remove superflous instanceof 2021-11-15 13:07:02 +01:00
Benjamin Muskalla
412bd32f45 Move more predicates into configuration 2021-11-15 13:04:23 +01:00
Benjamin Muskalla
b84c03672d Prefer types to TargetAPI 2021-11-15 12:43:46 +01:00
Benjamin Muskalla
bca6cecd1c Remove basic support for lambda flow 2021-11-15 12:38:30 +01:00
Benjamin Muskalla
78e3906ea7 Exclude more JDK internals 2021-11-15 11:58:10 +01:00
Benjamin Muskalla
cce3780481 Restrict param2return value features 2021-11-15 09:57:23 +01:00
Benjamin Muskalla
a0b7f267ff Only capture taint from own fields
Also exclude `Charset` as relevant taint-carrying type. This is generally
what we want to lets us avoid tracking arguments that lead to FP.
2021-11-12 10:15:15 +01:00
Benjamin Muskalla
0234e77d2f Let sink node be pluggable in any call context 2021-11-12 09:43:05 +01:00
Benjamin Muskalla
b8809a20d8 Support propagating taint of inner object 2021-11-12 09:39:59 +01:00
Erik Krogh Kristensen
b639a8d183 update ruby example
Co-authored-by: Nick Rolfe <nickrolfe@github.com>
2021-11-11 14:04:38 +01:00
Benjamin Muskalla
2d4176bec0 Ignore Number-derived types 2021-11-10 16:30:27 +01:00
Benjamin Muskalla
dbd393b77a Support flow into field of referenced objects 2021-11-10 16:30:27 +01:00
Benjamin Muskalla
974c7b0898 Avoid cross-class flow for field writes 2021-11-10 16:30:26 +01:00
Benjamin Muskalla
74ac234f1c Restrict field access to same type 2021-11-10 16:30:26 +01:00
Benjamin Muskalla
8740e879b4 Fix docs 2021-11-10 16:30:26 +01:00
Benjamin Muskalla
a546b38ee0 Restrict field access to corresponding type 2021-11-10 16:30:26 +01:00
Benjamin Muskalla
6960a7b97e Remove extraneous last column 2021-11-10 16:30:25 +01:00
Benjamin Muskalla
ef972159a6 Fix bug when generating output in a subfolder 2021-11-10 16:30:25 +01:00
Benjamin Muskalla
4cfd978bfe Support generating in respective folders 2021-11-10 16:30:25 +01:00
Benjamin Muskalla
b92758883b Auto-format generated qll files 2021-11-10 16:30:25 +01:00
Benjamin Muskalla
e2bd792fc2 Consider bulk-like data for argument accessors 2021-11-10 16:30:25 +01:00
Benjamin Muskalla
739fe75194 Support flow for factory and strategy pattern
* Support models for factories that create
new instances of an object while tainting it with incoming data
* Support models to infer super types for
private implementations to expose the models
at the right level
2021-11-10 16:30:24 +01:00
Benjamin Muskalla
58de6d143f Add docs to explain the models captured by the predicates 2021-11-10 16:30:24 +01:00
Benjamin Muskalla
747ab122c3 Restrict fluent api models to same type access 2021-11-10 16:30:24 +01:00
Benjamin Muskalla
8564c9001a Fix naming for source nodes 2021-11-10 16:30:24 +01:00
Benjamin Muskalla
9500c9c8bc Support lambda flow for source models
Also rely on public API to detect the source node
2021-11-10 16:30:24 +01:00
Benjamin Muskalla
35baa1c3df Support bulkdata for boxed types as well 2021-11-10 16:30:23 +01:00
Benjamin Muskalla
83b4070f31 Fix bug to accept bulk data for char/byte arrays 2021-11-10 16:30:23 +01:00
Benjamin Muskalla
281f25403d Match enclosing unit without casting to specific nodes 2021-11-10 16:30:23 +01:00
Benjamin Muskalla
bc10fd94cb Support generating only specific models 2021-11-10 16:30:23 +01:00
Benjamin Muskalla
0e9fcc6c39 Only generate models for local supertypes
Avoid generating models for classes
implementing external SPI (e.g. `FileFilter`).
Keep `toString` models intact as they're
commonly used as taint-propagation method
(e.g. see `Joiner`).
2021-11-10 16:30:23 +01:00
Benjamin Muskalla
157f56f48a Capture model for defining interface
Instead of modeling individual implementations, take a more general
approach of reuse dataflows for interfaces defined by a library. This allows
tracking flows across all implementations and aligns better with how we
manually model frameworks. This may have some FPs given all possible flows
are modeled for a specific interface but also covers more scenarios where
we don't know which implementation of an interface is used.
2021-11-10 16:30:22 +01:00
Benjamin Muskalla
f36bb8baaf Exclude models for simpler types
Avoid generating models for types that can't really propagate taint
in a valuable way (e.g. primitivies, BigInt, ..). Keep tracking
bulk-like data (e.g. char[] or byte[]).
2021-11-10 16:30:22 +01:00
Benjamin Muskalla
842f617bc1 Order sinks and sources first 2021-11-10 16:30:22 +01:00
Benjamin Muskalla
be150f269b Formatting 2021-11-10 16:30:22 +01:00
Benjamin Muskalla
2654e27123 Exclude known internal APIs from being modeled 2021-11-10 16:30:22 +01:00
Benjamin Muskalla
6b2460d4a1 Formatting 2021-11-10 16:30:21 +01:00
Benjamin Muskalla
060862ab3b Avoid certain test sources in models 2021-11-10 16:30:21 +01:00
Benjamin Muskalla
e607953b9c Simplify query 2021-11-10 16:30:21 +01:00
Benjamin Muskalla
9a859334d4 Formatting 2021-11-10 16:30:21 +01:00
Benjamin Muskalla
6c59333716 Remove workaround that accounted for missing flow 2021-11-10 16:30:21 +01:00
Benjamin Muskalla
7dae6122d9 Support CharSequence#toString
Given CharSequence is often used as an
alias for String, ensure taint through toString is flowing
2021-11-10 16:30:20 +01:00
Benjamin Muskalla
ca9d5439f0 Restrict source configuration to return nodes 2021-11-10 16:30:20 +01:00
Benjamin Muskalla
7a7ec06819 Simplify sink configuration 2021-11-10 16:30:20 +01:00
Benjamin Muskalla
1a4fd7bc7d Allow camelcase names 2021-11-10 16:30:20 +01:00
Benjamin Muskalla
2b2ac82fb7 Fix bug in sink detection 2021-11-10 16:30:20 +01:00
Benjamin Muskalla
c616eb1473 Fix finding more sources 2021-11-10 16:30:19 +01:00
Benjamin Muskalla
38579ef25b Add proper metadata to queries 2021-11-10 16:30:19 +01:00
Benjamin Muskalla
a80d50cbc0 Simplify field flow 2021-11-10 16:30:19 +01:00
Benjamin Muskalla
a1d8dfb524 Initial support for source models 2021-11-10 16:30:19 +01:00
Benjamin Muskalla
c844f5382f Add script to generate flow models 2021-11-10 16:30:19 +01:00
Benjamin Muskalla
f9fea15a52 Initial support for capturing sink models 2021-11-10 16:30:18 +01:00
Benjamin Muskalla
364de55b8d Support parameter->parameter flow 2021-11-10 16:30:18 +01:00
Benjamin Muskalla
cd11ef3bf6 Support outgoing taint flow from fields 2021-11-10 16:30:18 +01:00
Benjamin Muskalla
c3462be2c9 Capture argument->return value flows 2021-11-10 16:30:18 +01:00
Benjamin Muskalla
4ca006ba3d Only expose visible innner classes 2021-11-10 16:30:18 +01:00
Benjamin Muskalla
88032afdc3 Add test for final class 2021-11-10 16:30:17 +01:00
Benjamin Muskalla
ec772fb6b2 Add support for qualifier flow 2021-11-10 16:30:17 +01:00
Benjamin Muskalla
32ef40c77b Add scaffolding for summary model generator 2021-11-10 16:30:17 +01:00
Anders Schack-Mulligen
1efe1e0d10 Java: Improve algorithm for subtyping of parameterized types. 2021-11-09 15:49:17 +01:00
Pierre
4af3775b72 Add requirements for Apple Silicon 2021-11-08 01:37:31 +01:00
Erik Krogh Kristensen
02f500b9c2 Merge branch 'main' into htmlReg 2021-11-04 12:58:42 +01:00
Erik Krogh Kristensen
8a4b043cb1 fix imports 2021-10-26 15:39:45 +02:00
Erik Krogh Kristensen
62e729501c make the RegExpEscape::getUnescaped predicate public in python 2021-10-26 15:25:14 +02:00
Erik Krogh Kristensen
97264b5dda add the bad tag filter query to ruby 2021-10-26 15:25:12 +02:00
Erik Krogh Kristensen
c15ddf6e92 update ReDoSUtil in ruby 2021-10-26 15:03:09 +02:00
Erik Krogh Kristensen
2ddf445caf move ruby files to match file structure from js/py 2021-10-26 14:54:12 +02:00
Erik Krogh Kristensen
44afa34e37 Merge branch 'main' of github.com:github/codeql into htmlReg 2021-10-26 14:46:27 +02:00
Erik Krogh Kristensen
8d6cac76cc apply suggestions from asgerf 2021-10-04 12:45:02 +02:00
Erik Krogh Kristensen
aafae24ef2 update qhelp 2021-09-28 23:11:02 +02:00
Erik Krogh Kristensen
8d556ed1e1 Update python/ql/lib/semmle/python/security/BadTagFilterQuery.qll
Co-authored-by: Rasmus Wriedt Larsen <rasmuswriedtlarsen@gmail.com>
2021-09-28 23:04:28 +02:00
Erik Krogh Kristensen
99ed4a1a89 add a bad-tag-filter query for Python and JavaScript 2021-09-21 15:04:03 +02:00
Erik Krogh Kristensen
fd64ff9ef1 don't give group numbers to non-capturing groups 2021-09-21 12:15:27 +02:00
Erik Krogh Kristensen
c40ffab093 make isStartState public in ReDoSUtil 2021-09-21 12:14:21 +02:00
Erik Krogh Kristensen
672e4a3d72 cache TopLevel::isMinified 2021-09-21 12:13:37 +02:00
Erik Krogh Kristensen
60993214d5 cache isInterpretedAsRegExp 2021-09-21 12:13:37 +02:00
Erik Krogh Kristensen
01e345c2cc implement RegExpWordBoundary in RegexTreeView 2021-09-21 12:13:37 +02:00
Erik Krogh Kristensen
8535e6f281 use toUnicode in RegexTreeView 2021-09-21 12:13:37 +02:00
141 changed files with 4231 additions and 2181 deletions

51
benjamin-button.md Normal file
View File

@@ -0,0 +1,51 @@
# benjamin-buttons.md
This file describes the changes that have been applied to
the library to make it behave as if it was younger.
## TaintedPath.ql
Sinks added between 2020-01-01 and 2020-10-06 have been removed. Found by looking at:
- the commit titles of https://github.com/github/codeql/commits/main/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected
- the PR titles of https://github.com/github/codeql/pulls?page=2&q=is%3Apr+label%3AJS+is%3Aclosed+sink
Sinks added between 2018-08-02 and 2020-01-01 have been removed. Found by looking at:
- the commit titles of https://github.com/github/codeql/commits/main/javascript/ql/test/query-tests/Security/CWE-022/TaintedPath/TaintedPath.expected
- the PR titles of https://github.com/github/codeql/pulls?page=2&q=is%3Apr+label%3AJS+is%3Aclosed+sink
- the PR titles of https://github.com/github/codeql/pulls?page=2&q=is%3Apr+label%3AJS+is%3Aclosed+pathinjection
- the PR titles of https://github.com/github/codeql/pulls?page=2&q=is%3Apr+label%3AJS+is%3Aclosed+tainted-path
Sinks from the "graceful-fs" and "fs-extra" (added before the open-sourcing squash).
## Xss.ql
Sinks added between 2020-01-01 and 2020-10-06 have been removed. Found by looking at:
- the commit titles of https://github.com/github/codeql/commits/main/javascript/ql/test/query-tests/Security/CWE-079/Xss.expected
- the PR titles of https://github.com/github/codeql/pulls?page=2&q=is%3Apr+label%3AJS+is%3Aclosed+sink
- recursive type tracking for `jQuery::dollar`, `DOM::domValueRef`.
## SqlInjection.ql
Sinks added between 2020-01-01 and 2020-10-06 have been removed. Found by looking at:
- the commit titles of https://github.com/github/codeql/commits/main/javascript/ql/test/query-tests/Security/CWE-089
- the PR titles of https://github.com/github/codeql/pulls?page=2&q=is%3Apr+label%3AJS+is%3Aclosed+sink
Sinks added between 2018-08-02 and 2020-01-01 have been removed. Found by looking at:
- the commit titles of https://github.com/github/codeql/commits/main/javascript/ql/test/query-tests/Security/CWE-089
- the PR titles of https://github.com/github/codeql/pulls?page=2&q=is%3Apr+label%3AJS+is%3Aclosed+sink
- the PR titles of https://github.com/github/codeql/pulls?page=2&q=is%3Apr+label%3AJS+is%3Aclosed+sql
TypeTracking in SQL.qll (added before the open-sourcing squash)
The model of `mssql` and `sequelize` (added before the open-sourcing squash)
## PseudoProperties
Pseudo-properties (`$name$`) used in type-tracking and global dataflow configurations have been disabled.
Found by searching for `"\$.*\$"`.

View File

@@ -471,7 +471,12 @@
"ReDoS Polynomial Python/JS": [ "ReDoS Polynomial Python/JS": [
"javascript/ql/lib/semmle/javascript/security/performance/SuperlinearBackTracking.qll", "javascript/ql/lib/semmle/javascript/security/performance/SuperlinearBackTracking.qll",
"python/ql/lib/semmle/python/security/performance/SuperlinearBackTracking.qll", "python/ql/lib/semmle/python/security/performance/SuperlinearBackTracking.qll",
"ruby/ql/lib/codeql/ruby/regexp/SuperlinearBackTracking.qll" "ruby/ql/lib/codeql/ruby/security/performance/SuperlinearBackTracking.qll"
],
"BadTagFilterQuery Python/JS/Ruby": [
"javascript/ql/lib/semmle/javascript/security/BadTagFilterQuery.qll",
"python/ql/lib/semmle/python/security/BadTagFilterQuery.qll",
"ruby/ql/lib/codeql/ruby/security/BadTagFilterQuery.qll"
], ],
"CFG": [ "CFG": [
"csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraphImplShared.qll", "csharp/ql/lib/semmle/code/csharp/controlflow/internal/ControlFlowGraphImplShared.qll",

View File

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

View File

@@ -7,6 +7,7 @@
* @id cpp/non-https-url * @id cpp/non-https-url
* @tags security * @tags security
* external/cwe/cwe-319 * external/cwe/cwe-319
* external/cwe/cwe-345
*/ */
import cpp import cpp
@@ -61,7 +62,11 @@ class HttpStringToUrlOpenConfig extends TaintTracking::Configuration {
// accessed as a URL, for example using it in a network access. Some // accessed as a URL, for example using it in a network access. Some
// URLs are only ever displayed or used for data processing. // URLs are only ever displayed or used for data processing.
exists(FunctionCall fc | exists(FunctionCall fc |
fc.getTarget().hasGlobalOrStdName(["system", "gethostbyname", "getaddrinfo"]) and fc.getTarget()
.hasGlobalOrStdName([
"system", "gethostbyname", "gethostbyname2", "gethostbyname_r", "getaddrinfo",
"X509_load_http", "X509_CRL_load_http"
]) and
sink.asExpr() = fc.getArgument(0) sink.asExpr() = fc.getArgument(0)
or or
fc.getTarget().hasGlobalOrStdName(["send", "URLDownloadToFile", "URLDownloadToCacheFile"]) and fc.getTarget().hasGlobalOrStdName(["send", "URLDownloadToFile", "URLDownloadToCacheFile"]) and

View File

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

View File

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

View File

@@ -299,12 +299,15 @@
| file://:0:0:0:0 | (unnamed parameter 0) | file://:0:0:0:0 | (unnamed parameter 0) | | | file://:0:0:0:0 | (unnamed parameter 0) | file://:0:0:0:0 | (unnamed parameter 0) | |
| file://:0:0:0:0 | (unnamed parameter 0) | file://:0:0:0:0 | (unnamed parameter 0) | | | file://:0:0:0:0 | (unnamed parameter 0) | file://:0:0:0:0 | (unnamed parameter 0) | |
| file://:0:0:0:0 | (unnamed parameter 0) | file://:0:0:0:0 | (unnamed parameter 0) | | | file://:0:0:0:0 | (unnamed parameter 0) | file://:0:0:0:0 | (unnamed parameter 0) | |
| format.cpp:16:21:16:21 | s | format.cpp:16:21:16:21 | s | |
| format.cpp:16:21:16:21 | s | format.cpp:22:22:22:22 | s | | | format.cpp:16:21:16:21 | s | format.cpp:22:22:22:22 | s | |
| format.cpp:16:31:16:31 | n | format.cpp:22:25:22:25 | n | | | format.cpp:16:31:16:31 | n | format.cpp:22:25:22:25 | n | |
| format.cpp:16:46:16:51 | format | format.cpp:16:46:16:51 | format | |
| format.cpp:16:46:16:51 | format | format.cpp:22:28:22:33 | format | | | format.cpp:16:46:16:51 | format | format.cpp:22:28:22:33 | format | |
| format.cpp:20:10:20:13 | args | format.cpp:22:36:22:39 | args | | | format.cpp:20:10:20:13 | args | format.cpp:22:36:22:39 | args | |
| format.cpp:22:12:22:20 | call to vsnprintf | format.cpp:22:3:22:40 | ... = ... | | | format.cpp:22:12:22:20 | call to vsnprintf | format.cpp:22:3:22:40 | ... = ... | |
| format.cpp:22:12:22:20 | call to vsnprintf | format.cpp:25:9:25:14 | result | | | format.cpp:22:12:22:20 | call to vsnprintf | format.cpp:25:9:25:14 | result | |
| format.cpp:22:22:22:22 | ref arg s | format.cpp:16:21:16:21 | s | |
| format.cpp:50:21:50:24 | {...} | format.cpp:51:17:51:22 | buffer | | | format.cpp:50:21:50:24 | {...} | format.cpp:51:17:51:22 | buffer | |
| format.cpp:50:21:50:24 | {...} | format.cpp:52:8:52:13 | buffer | | | format.cpp:50:21:50:24 | {...} | format.cpp:52:8:52:13 | buffer | |
| format.cpp:50:23:50:23 | 0 | format.cpp:50:21:50:24 | {...} | TAINT | | format.cpp:50:23:50:23 | 0 | format.cpp:50:21:50:24 | {...} | TAINT |
@@ -3344,7 +3347,9 @@
| smart_pointer.cpp:93:8:93:8 | ref arg q | smart_pointer.cpp:94:8:94:8 | q | | | smart_pointer.cpp:93:8:93:8 | ref arg q | smart_pointer.cpp:94:8:94:8 | q | |
| smart_pointer.cpp:94:8:94:8 | q | smart_pointer.cpp:94:9:94:9 | call to operator-> | | | smart_pointer.cpp:94:8:94:8 | q | smart_pointer.cpp:94:9:94:9 | call to operator-> | |
| smart_pointer.cpp:94:8:94:8 | ref arg q | smart_pointer.cpp:86:67:86:67 | q | | | smart_pointer.cpp:94:8:94:8 | ref arg q | smart_pointer.cpp:86:67:86:67 | q | |
| smart_pointer.cpp:97:17:97:18 | pa | smart_pointer.cpp:97:17:97:18 | pa | |
| smart_pointer.cpp:97:17:97:18 | pa | smart_pointer.cpp:98:5:98:6 | pa | | | smart_pointer.cpp:97:17:97:18 | pa | smart_pointer.cpp:98:5:98:6 | pa | |
| smart_pointer.cpp:98:5:98:6 | pa [post update] | smart_pointer.cpp:97:17:97:18 | pa | |
| smart_pointer.cpp:98:5:98:20 | ... = ... | smart_pointer.cpp:98:9:98:9 | x [post update] | | | smart_pointer.cpp:98:5:98:20 | ... = ... | smart_pointer.cpp:98:9:98:9 | x [post update] | |
| smart_pointer.cpp:98:13:98:18 | call to source | smart_pointer.cpp:98:5:98:20 | ... = ... | | | smart_pointer.cpp:98:13:98:18 | call to source | smart_pointer.cpp:98:5:98:20 | ... = ... | |
| smart_pointer.cpp:102:25:102:50 | call to unique_ptr | smart_pointer.cpp:103:11:103:11 | p | | | smart_pointer.cpp:102:25:102:50 | call to unique_ptr | smart_pointer.cpp:103:11:103:11 | p | |
@@ -5923,11 +5928,13 @@
| taint.cpp:172:10:172:15 | buffer | taint.cpp:172:10:172:15 | ref arg buffer | TAINT | | taint.cpp:172:10:172:15 | buffer | taint.cpp:172:10:172:15 | ref arg buffer | TAINT |
| taint.cpp:172:10:172:15 | ref arg buffer | taint.cpp:173:8:173:13 | buffer | | | taint.cpp:172:10:172:15 | ref arg buffer | taint.cpp:173:8:173:13 | buffer | |
| taint.cpp:172:18:172:24 | tainted | taint.cpp:172:10:172:15 | ref arg buffer | TAINT | | taint.cpp:172:18:172:24 | tainted | taint.cpp:172:10:172:15 | ref arg buffer | TAINT |
| taint.cpp:180:19:180:19 | p | taint.cpp:180:19:180:19 | p | |
| taint.cpp:180:19:180:19 | p | taint.cpp:181:9:181:9 | p | | | taint.cpp:180:19:180:19 | p | taint.cpp:181:9:181:9 | p | |
| taint.cpp:181:9:181:9 | p | taint.cpp:181:8:181:9 | * ... | TAINT | | taint.cpp:181:9:181:9 | p | taint.cpp:181:8:181:9 | * ... | TAINT |
| taint.cpp:185:11:185:16 | call to source | taint.cpp:186:11:186:11 | x | | | taint.cpp:185:11:185:16 | call to source | taint.cpp:186:11:186:11 | x | |
| taint.cpp:186:10:186:11 | ref arg & ... | taint.cpp:186:11:186:11 | x [inner post update] | | | taint.cpp:186:10:186:11 | ref arg & ... | taint.cpp:186:11:186:11 | x [inner post update] | |
| taint.cpp:186:11:186:11 | x | taint.cpp:186:10:186:11 | & ... | | | taint.cpp:186:11:186:11 | x | taint.cpp:186:10:186:11 | & ... | |
| taint.cpp:192:23:192:28 | source | taint.cpp:192:23:192:28 | source | |
| taint.cpp:192:23:192:28 | source | taint.cpp:194:13:194:18 | source | | | taint.cpp:192:23:192:28 | source | taint.cpp:194:13:194:18 | source | |
| taint.cpp:193:6:193:6 | x | taint.cpp:194:10:194:10 | x | | | taint.cpp:193:6:193:6 | x | taint.cpp:194:10:194:10 | x | |
| taint.cpp:193:6:193:6 | x | taint.cpp:195:7:195:7 | x | | | taint.cpp:193:6:193:6 | x | taint.cpp:195:7:195:7 | x | |
@@ -5935,6 +5942,7 @@
| taint.cpp:194:9:194:10 | ref arg & ... | taint.cpp:194:10:194:10 | x [inner post update] | | | taint.cpp:194:9:194:10 | ref arg & ... | taint.cpp:194:10:194:10 | x [inner post update] | |
| taint.cpp:194:9:194:10 | ref arg & ... | taint.cpp:195:7:195:7 | x | | | taint.cpp:194:9:194:10 | ref arg & ... | taint.cpp:195:7:195:7 | x | |
| taint.cpp:194:10:194:10 | x | taint.cpp:194:9:194:10 | & ... | | | taint.cpp:194:10:194:10 | x | taint.cpp:194:9:194:10 | & ... | |
| taint.cpp:194:13:194:18 | ref arg source | taint.cpp:192:23:192:28 | source | |
| taint.cpp:194:13:194:18 | source | taint.cpp:194:2:194:7 | call to memcpy | TAINT | | taint.cpp:194:13:194:18 | source | taint.cpp:194:2:194:7 | call to memcpy | TAINT |
| taint.cpp:194:13:194:18 | source | taint.cpp:194:9:194:10 | ref arg & ... | TAINT | | taint.cpp:194:13:194:18 | source | taint.cpp:194:9:194:10 | ref arg & ... | TAINT |
| taint.cpp:207:6:207:11 | call to source | taint.cpp:207:2:207:13 | ... = ... | | | taint.cpp:207:6:207:11 | call to source | taint.cpp:207:2:207:13 | ... = ... | |
@@ -6040,18 +6048,22 @@
| taint.cpp:304:2:304:6 | ... = ... | taint.cpp:304:2:304:2 | a [post update] | | | taint.cpp:304:2:304:6 | ... = ... | taint.cpp:304:2:304:2 | a [post update] | |
| taint.cpp:304:6:304:6 | b | taint.cpp:302:21:302:21 | a | | | taint.cpp:304:6:304:6 | b | taint.cpp:302:21:302:21 | a | |
| taint.cpp:304:6:304:6 | b | taint.cpp:304:2:304:6 | ... = ... | | | taint.cpp:304:6:304:6 | b | taint.cpp:304:2:304:6 | ... = ... | |
| taint.cpp:307:21:307:21 | a | taint.cpp:307:21:307:21 | a | |
| taint.cpp:307:21:307:21 | a | taint.cpp:309:3:309:3 | a | | | taint.cpp:307:21:307:21 | a | taint.cpp:309:3:309:3 | a | |
| taint.cpp:307:28:307:28 | b | taint.cpp:309:7:309:7 | b | | | taint.cpp:307:28:307:28 | b | taint.cpp:309:7:309:7 | b | |
| taint.cpp:309:2:309:3 | * ... [post update] | taint.cpp:307:21:307:21 | a | |
| taint.cpp:309:2:309:3 | * ... [post update] | taint.cpp:309:3:309:3 | a [inner post update] | | | taint.cpp:309:2:309:3 | * ... [post update] | taint.cpp:309:3:309:3 | a [inner post update] | |
| taint.cpp:309:2:309:7 | ... = ... | taint.cpp:309:2:309:3 | * ... [post update] | | | taint.cpp:309:2:309:7 | ... = ... | taint.cpp:309:2:309:3 | * ... [post update] | |
| taint.cpp:309:3:309:3 | a | taint.cpp:309:2:309:3 | * ... | TAINT | | taint.cpp:309:3:309:3 | a | taint.cpp:309:2:309:3 | * ... | TAINT |
| taint.cpp:309:7:309:7 | b | taint.cpp:309:2:309:7 | ... = ... | | | taint.cpp:309:7:309:7 | b | taint.cpp:309:2:309:7 | ... = ... | |
| taint.cpp:312:21:312:21 | a | taint.cpp:312:21:312:21 | a | |
| taint.cpp:312:21:312:21 | a | taint.cpp:317:3:317:3 | a | | | taint.cpp:312:21:312:21 | a | taint.cpp:317:3:317:3 | a | |
| taint.cpp:312:28:312:28 | b | taint.cpp:316:6:316:6 | b | | | taint.cpp:312:28:312:28 | b | taint.cpp:316:6:316:6 | b | |
| taint.cpp:316:6:316:6 | b | taint.cpp:316:6:316:10 | ... + ... | TAINT | | taint.cpp:316:6:316:6 | b | taint.cpp:316:6:316:10 | ... + ... | TAINT |
| taint.cpp:316:6:316:10 | ... + ... | taint.cpp:316:2:316:10 | ... = ... | | | taint.cpp:316:6:316:10 | ... + ... | taint.cpp:316:2:316:10 | ... = ... | |
| taint.cpp:316:6:316:10 | ... + ... | taint.cpp:317:7:317:7 | c | | | taint.cpp:316:6:316:10 | ... + ... | taint.cpp:317:7:317:7 | c | |
| taint.cpp:316:10:316:10 | 1 | taint.cpp:316:6:316:10 | ... + ... | TAINT | | taint.cpp:316:10:316:10 | 1 | taint.cpp:316:6:316:10 | ... + ... | TAINT |
| taint.cpp:317:2:317:3 | * ... [post update] | taint.cpp:312:21:312:21 | a | |
| taint.cpp:317:2:317:3 | * ... [post update] | taint.cpp:317:3:317:3 | a [inner post update] | | | taint.cpp:317:2:317:3 | * ... [post update] | taint.cpp:317:3:317:3 | a [inner post update] | |
| taint.cpp:317:2:317:7 | ... = ... | taint.cpp:317:2:317:3 | * ... [post update] | | | taint.cpp:317:2:317:7 | ... = ... | taint.cpp:317:2:317:3 | * ... [post update] | |
| taint.cpp:317:3:317:3 | a | taint.cpp:317:2:317:3 | * ... | TAINT | | taint.cpp:317:3:317:3 | a | taint.cpp:317:2:317:3 | * ... | TAINT |
@@ -6113,6 +6125,7 @@
| taint.cpp:347:13:347:13 | d | taint.cpp:347:12:347:13 | & ... | | | taint.cpp:347:13:347:13 | d | taint.cpp:347:12:347:13 | & ... | |
| taint.cpp:348:14:348:14 | ref arg e | taint.cpp:355:7:355:7 | e | | | taint.cpp:348:14:348:14 | ref arg e | taint.cpp:355:7:355:7 | e | |
| taint.cpp:348:17:348:17 | ref arg t | taint.cpp:350:7:350:7 | t | | | taint.cpp:348:17:348:17 | ref arg t | taint.cpp:350:7:350:7 | t | |
| taint.cpp:367:24:367:29 | source | taint.cpp:367:24:367:29 | source | |
| taint.cpp:367:24:367:29 | source | taint.cpp:371:13:371:18 | source | | | taint.cpp:367:24:367:29 | source | taint.cpp:371:13:371:18 | source | |
| taint.cpp:367:24:367:29 | source | taint.cpp:373:14:373:19 | source | | | taint.cpp:367:24:367:29 | source | taint.cpp:373:14:373:19 | source | |
| taint.cpp:371:6:371:11 | call to strdup | taint.cpp:371:2:371:19 | ... = ... | | | taint.cpp:371:6:371:11 | call to strdup | taint.cpp:371:2:371:19 | ... = ... | |
@@ -6130,6 +6143,7 @@
| taint.cpp:383:6:383:12 | call to strndup | taint.cpp:384:7:384:7 | a | | | taint.cpp:383:6:383:12 | call to strndup | taint.cpp:384:7:384:7 | a | |
| taint.cpp:383:14:383:27 | hello, world | taint.cpp:383:6:383:12 | call to strndup | TAINT | | taint.cpp:383:14:383:27 | hello, world | taint.cpp:383:6:383:12 | call to strndup | TAINT |
| taint.cpp:383:30:383:35 | source | taint.cpp:383:6:383:12 | call to strndup | TAINT | | taint.cpp:383:30:383:35 | source | taint.cpp:383:6:383:12 | call to strndup | TAINT |
| taint.cpp:387:27:387:32 | source | taint.cpp:387:27:387:32 | source | |
| taint.cpp:387:27:387:32 | source | taint.cpp:391:13:391:18 | source | | | taint.cpp:387:27:387:32 | source | taint.cpp:391:13:391:18 | source | |
| taint.cpp:391:6:391:11 | call to wcsdup | taint.cpp:391:2:391:19 | ... = ... | | | taint.cpp:391:6:391:11 | call to wcsdup | taint.cpp:391:2:391:19 | ... = ... | |
| taint.cpp:391:6:391:11 | call to wcsdup | taint.cpp:393:7:393:7 | a | | | taint.cpp:391:6:391:11 | call to wcsdup | taint.cpp:393:7:393:7 | a | |
@@ -6137,6 +6151,7 @@
| taint.cpp:392:6:392:11 | call to wcsdup | taint.cpp:392:2:392:28 | ... = ... | | | taint.cpp:392:6:392:11 | call to wcsdup | taint.cpp:392:2:392:28 | ... = ... | |
| taint.cpp:392:6:392:11 | call to wcsdup | taint.cpp:394:7:394:7 | b | | | taint.cpp:392:6:392:11 | call to wcsdup | taint.cpp:394:7:394:7 | b | |
| taint.cpp:392:13:392:27 | hello, world | taint.cpp:392:6:392:11 | call to wcsdup | TAINT | | taint.cpp:392:13:392:27 | hello, world | taint.cpp:392:6:392:11 | call to wcsdup | TAINT |
| taint.cpp:397:25:397:30 | source | taint.cpp:397:25:397:30 | source | |
| taint.cpp:397:25:397:30 | source | taint.cpp:401:14:401:19 | source | | | taint.cpp:397:25:397:30 | source | taint.cpp:401:14:401:19 | source | |
| taint.cpp:397:25:397:30 | source | taint.cpp:403:15:403:20 | source | | | taint.cpp:397:25:397:30 | source | taint.cpp:403:15:403:20 | source | |
| taint.cpp:401:6:401:12 | call to strdupa | taint.cpp:401:2:401:20 | ... = ... | | | taint.cpp:401:6:401:12 | call to strdupa | taint.cpp:401:2:401:20 | ... = ... | |
@@ -6239,6 +6254,7 @@
| taint.cpp:485:6:485:6 | 0 | taint.cpp:493:7:493:7 | y | | | taint.cpp:485:6:485:6 | 0 | taint.cpp:493:7:493:7 | y | |
| taint.cpp:490:7:490:7 | ref arg x | taint.cpp:492:7:492:7 | x | | | taint.cpp:490:7:490:7 | ref arg x | taint.cpp:492:7:492:7 | x | |
| taint.cpp:490:10:490:10 | ref arg y | taint.cpp:493:7:493:7 | y | | | taint.cpp:490:10:490:10 | ref arg y | taint.cpp:493:7:493:7 | y | |
| taint.cpp:502:26:502:32 | source1 | taint.cpp:502:26:502:32 | source1 | |
| taint.cpp:502:26:502:32 | source1 | taint.cpp:505:28:505:34 | source1 | | | taint.cpp:502:26:502:32 | source1 | taint.cpp:505:28:505:34 | source1 | |
| taint.cpp:503:15:503:21 | 0 | taint.cpp:505:12:505:15 | line | | | taint.cpp:503:15:503:21 | 0 | taint.cpp:505:12:505:15 | line | |
| taint.cpp:503:15:503:21 | 0 | taint.cpp:507:7:507:10 | line | | | taint.cpp:503:15:503:21 | 0 | taint.cpp:507:7:507:10 | line | |
@@ -6248,29 +6264,39 @@
| taint.cpp:505:12:505:15 | line | taint.cpp:505:11:505:15 | & ... | | | taint.cpp:505:12:505:15 | line | taint.cpp:505:11:505:15 | & ... | |
| taint.cpp:505:18:505:19 | ref arg & ... | taint.cpp:505:19:505:19 | n [inner post update] | | | taint.cpp:505:18:505:19 | ref arg & ... | taint.cpp:505:19:505:19 | n [inner post update] | |
| taint.cpp:505:19:505:19 | n | taint.cpp:505:18:505:19 | & ... | | | taint.cpp:505:19:505:19 | n | taint.cpp:505:18:505:19 | & ... | |
| taint.cpp:505:28:505:34 | ref arg source1 | taint.cpp:502:26:502:32 | source1 | |
| taint.cpp:505:28:505:34 | source1 | taint.cpp:505:11:505:15 | ref arg & ... | TAINT | | taint.cpp:505:28:505:34 | source1 | taint.cpp:505:11:505:15 | ref arg & ... | TAINT |
| taint.cpp:514:24:514:29 | source | taint.cpp:514:24:514:29 | source | |
| taint.cpp:514:24:514:29 | source | taint.cpp:516:27:516:32 | source | | | taint.cpp:514:24:514:29 | source | taint.cpp:516:27:516:32 | source | |
| taint.cpp:515:22:515:29 | ,.-;:_ | taint.cpp:516:35:516:39 | delim | | | taint.cpp:515:22:515:29 | ,.-;:_ | taint.cpp:516:35:516:39 | delim | |
| taint.cpp:515:22:515:29 | ,.-;:_ | taint.cpp:518:7:518:11 | delim | | | taint.cpp:515:22:515:29 | ,.-;:_ | taint.cpp:518:7:518:11 | delim | |
| taint.cpp:516:20:516:25 | call to strtok | taint.cpp:517:7:517:15 | tokenized | | | taint.cpp:516:20:516:25 | call to strtok | taint.cpp:517:7:517:15 | tokenized | |
| taint.cpp:516:27:516:32 | ref arg source | taint.cpp:514:24:514:29 | source | |
| taint.cpp:516:27:516:32 | source | taint.cpp:516:20:516:25 | call to strtok | TAINT | | taint.cpp:516:27:516:32 | source | taint.cpp:516:20:516:25 | call to strtok | TAINT |
| taint.cpp:525:26:525:28 | ptr | taint.cpp:525:26:525:28 | ptr | |
| taint.cpp:525:26:525:28 | ptr | taint.cpp:526:10:526:12 | ptr | | | taint.cpp:525:26:525:28 | ptr | taint.cpp:526:10:526:12 | ptr | |
| taint.cpp:525:26:525:28 | ptr | taint.cpp:527:7:527:9 | ptr | | | taint.cpp:525:26:525:28 | ptr | taint.cpp:527:7:527:9 | ptr | |
| taint.cpp:525:26:525:28 | ptr | taint.cpp:528:8:528:10 | ptr | | | taint.cpp:525:26:525:28 | ptr | taint.cpp:528:8:528:10 | ptr | |
| taint.cpp:525:36:525:41 | source | taint.cpp:526:15:526:20 | source | | | taint.cpp:525:36:525:41 | source | taint.cpp:526:15:526:20 | source | |
| taint.cpp:526:10:526:12 | ptr | taint.cpp:526:2:526:8 | call to _strset | | | taint.cpp:526:10:526:12 | ptr | taint.cpp:526:2:526:8 | call to _strset | |
| taint.cpp:526:10:526:12 | ref arg ptr | taint.cpp:525:26:525:28 | ptr | |
| taint.cpp:526:10:526:12 | ref arg ptr | taint.cpp:527:7:527:9 | ptr | | | taint.cpp:526:10:526:12 | ref arg ptr | taint.cpp:527:7:527:9 | ptr | |
| taint.cpp:526:10:526:12 | ref arg ptr | taint.cpp:528:8:528:10 | ptr | | | taint.cpp:526:10:526:12 | ref arg ptr | taint.cpp:528:8:528:10 | ptr | |
| taint.cpp:526:15:526:20 | source | taint.cpp:526:2:526:8 | call to _strset | TAINT | | taint.cpp:526:15:526:20 | source | taint.cpp:526:2:526:8 | call to _strset | TAINT |
| taint.cpp:526:15:526:20 | source | taint.cpp:526:10:526:12 | ref arg ptr | | | taint.cpp:526:15:526:20 | source | taint.cpp:526:10:526:12 | ref arg ptr | |
| taint.cpp:527:7:527:9 | ref arg ptr | taint.cpp:525:26:525:28 | ptr | |
| taint.cpp:527:7:527:9 | ref arg ptr | taint.cpp:528:8:528:10 | ptr | | | taint.cpp:527:7:527:9 | ref arg ptr | taint.cpp:528:8:528:10 | ptr | |
| taint.cpp:528:8:528:10 | ptr | taint.cpp:528:7:528:10 | * ... | TAINT | | taint.cpp:528:8:528:10 | ptr | taint.cpp:528:7:528:10 | * ... | TAINT |
| taint.cpp:531:26:531:31 | source | taint.cpp:531:26:531:31 | source | |
| taint.cpp:531:26:531:31 | source | taint.cpp:532:10:532:15 | source | | | taint.cpp:531:26:531:31 | source | taint.cpp:532:10:532:15 | source | |
| taint.cpp:531:26:531:31 | source | taint.cpp:533:7:533:12 | source | | | taint.cpp:531:26:531:31 | source | taint.cpp:533:7:533:12 | source | |
| taint.cpp:532:10:532:15 | ref arg source | taint.cpp:531:26:531:31 | source | |
| taint.cpp:532:10:532:15 | ref arg source | taint.cpp:533:7:533:12 | source | | | taint.cpp:532:10:532:15 | ref arg source | taint.cpp:533:7:533:12 | source | |
| taint.cpp:532:10:532:15 | source | taint.cpp:532:2:532:8 | call to _strset | | | taint.cpp:532:10:532:15 | source | taint.cpp:532:2:532:8 | call to _strset | |
| taint.cpp:532:18:532:18 | 0 | taint.cpp:532:2:532:8 | call to _strset | TAINT | | taint.cpp:532:18:532:18 | 0 | taint.cpp:532:2:532:8 | call to _strset | TAINT |
| taint.cpp:532:18:532:18 | 0 | taint.cpp:532:10:532:15 | ref arg source | | | taint.cpp:532:18:532:18 | 0 | taint.cpp:532:10:532:15 | ref arg source | |
| taint.cpp:533:7:533:12 | ref arg source | taint.cpp:531:26:531:31 | source | |
| taint.cpp:540:24:540:29 | source | taint.cpp:540:24:540:29 | source | |
| taint.cpp:540:24:540:29 | source | taint.cpp:542:14:542:19 | source | | | taint.cpp:540:24:540:29 | source | taint.cpp:542:14:542:19 | source | |
| taint.cpp:541:6:541:6 | x | taint.cpp:542:11:542:11 | x | | | taint.cpp:541:6:541:6 | x | taint.cpp:542:11:542:11 | x | |
| taint.cpp:541:6:541:6 | x | taint.cpp:543:7:543:7 | x | | | taint.cpp:541:6:541:6 | x | taint.cpp:543:7:543:7 | x | |
@@ -6280,6 +6306,7 @@
| taint.cpp:542:11:542:11 | x | taint.cpp:542:10:542:11 | & ... | | | taint.cpp:542:11:542:11 | x | taint.cpp:542:10:542:11 | & ... | |
| taint.cpp:542:14:542:19 | source | taint.cpp:542:2:542:8 | call to mempcpy | TAINT | | taint.cpp:542:14:542:19 | source | taint.cpp:542:2:542:8 | call to mempcpy | TAINT |
| taint.cpp:542:14:542:19 | source | taint.cpp:542:10:542:11 | ref arg & ... | TAINT | | taint.cpp:542:14:542:19 | source | taint.cpp:542:10:542:11 | ref arg & ... | TAINT |
| taint.cpp:550:24:550:29 | source | taint.cpp:550:24:550:29 | source | |
| taint.cpp:550:24:550:29 | source | taint.cpp:552:16:552:21 | source | | | taint.cpp:550:24:550:29 | source | taint.cpp:552:16:552:21 | source | |
| taint.cpp:551:6:551:9 | dest | taint.cpp:552:10:552:13 | dest | | | taint.cpp:551:6:551:9 | dest | taint.cpp:552:10:552:13 | dest | |
| taint.cpp:551:6:551:9 | dest | taint.cpp:552:35:552:38 | dest | | | taint.cpp:551:6:551:9 | dest | taint.cpp:552:35:552:38 | dest | |
@@ -6288,29 +6315,42 @@
| taint.cpp:552:10:552:13 | ref arg dest | taint.cpp:553:7:553:10 | dest | | | taint.cpp:552:10:552:13 | ref arg dest | taint.cpp:553:7:553:10 | dest | |
| taint.cpp:552:16:552:21 | source | taint.cpp:552:2:552:8 | call to memccpy | TAINT | | taint.cpp:552:16:552:21 | source | taint.cpp:552:2:552:8 | call to memccpy | TAINT |
| taint.cpp:552:16:552:21 | source | taint.cpp:552:10:552:13 | ref arg dest | TAINT | | taint.cpp:552:16:552:21 | source | taint.cpp:552:10:552:13 | ref arg dest | TAINT |
| taint.cpp:560:24:560:28 | dest1 | taint.cpp:560:24:560:28 | dest1 | |
| taint.cpp:560:24:560:28 | dest1 | taint.cpp:561:9:561:13 | dest1 | | | taint.cpp:560:24:560:28 | dest1 | taint.cpp:561:9:561:13 | dest1 | |
| taint.cpp:560:24:560:28 | dest1 | taint.cpp:562:7:562:11 | dest1 | | | taint.cpp:560:24:560:28 | dest1 | taint.cpp:562:7:562:11 | dest1 | |
| taint.cpp:560:37:560:41 | dest2 | taint.cpp:560:37:560:41 | dest2 | |
| taint.cpp:560:37:560:41 | dest2 | taint.cpp:564:9:564:13 | dest2 | | | taint.cpp:560:37:560:41 | dest2 | taint.cpp:564:9:564:13 | dest2 | |
| taint.cpp:560:37:560:41 | dest2 | taint.cpp:565:7:565:11 | dest2 | | | taint.cpp:560:37:560:41 | dest2 | taint.cpp:565:7:565:11 | dest2 | |
| taint.cpp:560:50:560:54 | clean | taint.cpp:560:50:560:54 | clean | |
| taint.cpp:560:50:560:54 | clean | taint.cpp:564:16:564:20 | clean | | | taint.cpp:560:50:560:54 | clean | taint.cpp:564:16:564:20 | clean | |
| taint.cpp:560:63:560:68 | source | taint.cpp:560:63:560:68 | source | |
| taint.cpp:560:63:560:68 | source | taint.cpp:561:16:561:21 | source | | | taint.cpp:560:63:560:68 | source | taint.cpp:561:16:561:21 | source | |
| taint.cpp:561:9:561:13 | dest1 | taint.cpp:561:2:561:7 | call to strcat | | | taint.cpp:561:9:561:13 | dest1 | taint.cpp:561:2:561:7 | call to strcat | |
| taint.cpp:561:9:561:13 | dest1 | taint.cpp:561:9:561:13 | ref arg dest1 | TAINT | | taint.cpp:561:9:561:13 | dest1 | taint.cpp:561:9:561:13 | ref arg dest1 | TAINT |
| taint.cpp:561:9:561:13 | ref arg dest1 | taint.cpp:560:24:560:28 | dest1 | |
| taint.cpp:561:9:561:13 | ref arg dest1 | taint.cpp:562:7:562:11 | dest1 | | | taint.cpp:561:9:561:13 | ref arg dest1 | taint.cpp:562:7:562:11 | dest1 | |
| taint.cpp:561:16:561:21 | source | taint.cpp:561:9:561:13 | ref arg dest1 | TAINT | | taint.cpp:561:16:561:21 | source | taint.cpp:561:9:561:13 | ref arg dest1 | TAINT |
| taint.cpp:562:7:562:11 | ref arg dest1 | taint.cpp:560:24:560:28 | dest1 | |
| taint.cpp:564:9:564:13 | dest2 | taint.cpp:564:2:564:7 | call to strcat | | | taint.cpp:564:9:564:13 | dest2 | taint.cpp:564:2:564:7 | call to strcat | |
| taint.cpp:564:9:564:13 | dest2 | taint.cpp:564:9:564:13 | ref arg dest2 | TAINT | | taint.cpp:564:9:564:13 | dest2 | taint.cpp:564:9:564:13 | ref arg dest2 | TAINT |
| taint.cpp:564:9:564:13 | ref arg dest2 | taint.cpp:560:37:560:41 | dest2 | |
| taint.cpp:564:9:564:13 | ref arg dest2 | taint.cpp:565:7:565:11 | dest2 | | | taint.cpp:564:9:564:13 | ref arg dest2 | taint.cpp:565:7:565:11 | dest2 | |
| taint.cpp:564:16:564:20 | clean | taint.cpp:564:9:564:13 | ref arg dest2 | TAINT | | taint.cpp:564:16:564:20 | clean | taint.cpp:564:9:564:13 | ref arg dest2 | TAINT |
| taint.cpp:565:7:565:11 | ref arg dest2 | taint.cpp:560:37:560:41 | dest2 | |
| taint.cpp:572:37:572:41 | dest1 | taint.cpp:572:37:572:41 | dest1 | |
| taint.cpp:572:37:572:41 | dest1 | taint.cpp:574:36:574:40 | dest1 | | | taint.cpp:572:37:572:41 | dest1 | taint.cpp:574:36:574:40 | dest1 | |
| taint.cpp:572:37:572:41 | dest1 | taint.cpp:575:7:575:11 | dest1 | | | taint.cpp:572:37:572:41 | dest1 | taint.cpp:575:7:575:11 | dest1 | |
| taint.cpp:572:37:572:41 | dest1 | taint.cpp:576:8:576:12 | dest1 | | | taint.cpp:572:37:572:41 | dest1 | taint.cpp:576:8:576:12 | dest1 | |
| taint.cpp:572:65:572:67 | ptr | taint.cpp:572:65:572:67 | ptr | |
| taint.cpp:572:65:572:67 | ptr | taint.cpp:574:43:574:45 | ptr | | | taint.cpp:572:65:572:67 | ptr | taint.cpp:574:43:574:45 | ptr | |
| taint.cpp:572:65:572:67 | ptr | taint.cpp:580:43:580:45 | ptr | | | taint.cpp:572:65:572:67 | ptr | taint.cpp:580:43:580:45 | ptr | |
| taint.cpp:572:85:572:89 | dest3 | taint.cpp:572:85:572:89 | dest3 | |
| taint.cpp:572:85:572:89 | dest3 | taint.cpp:580:36:580:40 | dest3 | | | taint.cpp:572:85:572:89 | dest3 | taint.cpp:580:36:580:40 | dest3 | |
| taint.cpp:572:85:572:89 | dest3 | taint.cpp:581:7:581:11 | dest3 | | | taint.cpp:572:85:572:89 | dest3 | taint.cpp:581:7:581:11 | dest3 | |
| taint.cpp:572:85:572:89 | dest3 | taint.cpp:582:8:582:12 | dest3 | | | taint.cpp:572:85:572:89 | dest3 | taint.cpp:582:8:582:12 | dest3 | |
| taint.cpp:573:32:573:36 | clean | taint.cpp:573:32:573:36 | clean | |
| taint.cpp:573:32:573:36 | clean | taint.cpp:580:51:580:55 | clean | | | taint.cpp:573:32:573:36 | clean | taint.cpp:580:51:580:55 | clean | |
| taint.cpp:573:49:573:54 | source | taint.cpp:573:49:573:54 | source | |
| taint.cpp:573:49:573:54 | source | taint.cpp:574:51:574:56 | source | | | taint.cpp:573:49:573:54 | source | taint.cpp:574:51:574:56 | source | |
| taint.cpp:573:61:573:61 | n | taint.cpp:574:48:574:48 | n | | | taint.cpp:573:61:573:61 | n | taint.cpp:574:48:574:48 | n | |
| taint.cpp:573:61:573:61 | n | taint.cpp:580:48:580:48 | n | | | taint.cpp:573:61:573:61 | n | taint.cpp:580:48:580:48 | n | |
@@ -6318,11 +6358,14 @@
| taint.cpp:574:25:574:34 | call to _mbsncat_l | taint.cpp:578:8:578:12 | dest2 | | | taint.cpp:574:25:574:34 | call to _mbsncat_l | taint.cpp:578:8:578:12 | dest2 | |
| taint.cpp:574:36:574:40 | dest1 | taint.cpp:574:25:574:34 | call to _mbsncat_l | | | taint.cpp:574:36:574:40 | dest1 | taint.cpp:574:25:574:34 | call to _mbsncat_l | |
| taint.cpp:574:36:574:40 | dest1 | taint.cpp:574:36:574:40 | ref arg dest1 | TAINT | | taint.cpp:574:36:574:40 | dest1 | taint.cpp:574:36:574:40 | ref arg dest1 | TAINT |
| taint.cpp:574:36:574:40 | ref arg dest1 | taint.cpp:572:37:572:41 | dest1 | |
| taint.cpp:574:36:574:40 | ref arg dest1 | taint.cpp:575:7:575:11 | dest1 | | | taint.cpp:574:36:574:40 | ref arg dest1 | taint.cpp:575:7:575:11 | dest1 | |
| taint.cpp:574:36:574:40 | ref arg dest1 | taint.cpp:576:8:576:12 | dest1 | | | taint.cpp:574:36:574:40 | ref arg dest1 | taint.cpp:576:8:576:12 | dest1 | |
| taint.cpp:574:43:574:45 | ptr | taint.cpp:574:36:574:40 | ref arg dest1 | TAINT | | taint.cpp:574:43:574:45 | ptr | taint.cpp:574:36:574:40 | ref arg dest1 | TAINT |
| taint.cpp:574:48:574:48 | n | taint.cpp:574:36:574:40 | ref arg dest1 | TAINT | | taint.cpp:574:48:574:48 | n | taint.cpp:574:36:574:40 | ref arg dest1 | TAINT |
| taint.cpp:574:51:574:56 | ref arg source | taint.cpp:573:49:573:54 | source | |
| taint.cpp:574:51:574:56 | source | taint.cpp:574:36:574:40 | ref arg dest1 | TAINT | | taint.cpp:574:51:574:56 | source | taint.cpp:574:36:574:40 | ref arg dest1 | TAINT |
| taint.cpp:575:7:575:11 | ref arg dest1 | taint.cpp:572:37:572:41 | dest1 | |
| taint.cpp:575:7:575:11 | ref arg dest1 | taint.cpp:576:8:576:12 | dest1 | | | taint.cpp:575:7:575:11 | ref arg dest1 | taint.cpp:576:8:576:12 | dest1 | |
| taint.cpp:576:8:576:12 | dest1 | taint.cpp:576:7:576:12 | * ... | TAINT | | taint.cpp:576:8:576:12 | dest1 | taint.cpp:576:7:576:12 | * ... | TAINT |
| taint.cpp:577:7:577:11 | ref arg dest2 | taint.cpp:578:8:578:12 | dest2 | | | taint.cpp:577:7:577:11 | ref arg dest2 | taint.cpp:578:8:578:12 | dest2 | |
@@ -6331,15 +6374,19 @@
| taint.cpp:580:25:580:34 | call to _mbsncat_l | taint.cpp:584:8:584:12 | dest4 | | | taint.cpp:580:25:580:34 | call to _mbsncat_l | taint.cpp:584:8:584:12 | dest4 | |
| taint.cpp:580:36:580:40 | dest3 | taint.cpp:580:25:580:34 | call to _mbsncat_l | | | taint.cpp:580:36:580:40 | dest3 | taint.cpp:580:25:580:34 | call to _mbsncat_l | |
| taint.cpp:580:36:580:40 | dest3 | taint.cpp:580:36:580:40 | ref arg dest3 | TAINT | | taint.cpp:580:36:580:40 | dest3 | taint.cpp:580:36:580:40 | ref arg dest3 | TAINT |
| taint.cpp:580:36:580:40 | ref arg dest3 | taint.cpp:572:85:572:89 | dest3 | |
| taint.cpp:580:36:580:40 | ref arg dest3 | taint.cpp:581:7:581:11 | dest3 | | | taint.cpp:580:36:580:40 | ref arg dest3 | taint.cpp:581:7:581:11 | dest3 | |
| taint.cpp:580:36:580:40 | ref arg dest3 | taint.cpp:582:8:582:12 | dest3 | | | taint.cpp:580:36:580:40 | ref arg dest3 | taint.cpp:582:8:582:12 | dest3 | |
| taint.cpp:580:43:580:45 | ptr | taint.cpp:580:36:580:40 | ref arg dest3 | TAINT | | taint.cpp:580:43:580:45 | ptr | taint.cpp:580:36:580:40 | ref arg dest3 | TAINT |
| taint.cpp:580:48:580:48 | n | taint.cpp:580:36:580:40 | ref arg dest3 | TAINT | | taint.cpp:580:48:580:48 | n | taint.cpp:580:36:580:40 | ref arg dest3 | TAINT |
| taint.cpp:580:51:580:55 | clean | taint.cpp:580:36:580:40 | ref arg dest3 | TAINT | | taint.cpp:580:51:580:55 | clean | taint.cpp:580:36:580:40 | ref arg dest3 | TAINT |
| taint.cpp:580:51:580:55 | ref arg clean | taint.cpp:573:32:573:36 | clean | |
| taint.cpp:581:7:581:11 | ref arg dest3 | taint.cpp:572:85:572:89 | dest3 | |
| taint.cpp:581:7:581:11 | ref arg dest3 | taint.cpp:582:8:582:12 | dest3 | | | taint.cpp:581:7:581:11 | ref arg dest3 | taint.cpp:582:8:582:12 | dest3 | |
| taint.cpp:582:8:582:12 | dest3 | taint.cpp:582:7:582:12 | * ... | TAINT | | taint.cpp:582:8:582:12 | dest3 | taint.cpp:582:7:582:12 | * ... | TAINT |
| taint.cpp:583:7:583:11 | ref arg dest4 | taint.cpp:584:8:584:12 | dest4 | | | taint.cpp:583:7:583:11 | ref arg dest4 | taint.cpp:584:8:584:12 | dest4 | |
| taint.cpp:584:8:584:12 | dest4 | taint.cpp:584:7:584:12 | * ... | TAINT | | taint.cpp:584:8:584:12 | dest4 | taint.cpp:584:7:584:12 | * ... | TAINT |
| taint.cpp:591:24:591:29 | source | taint.cpp:591:24:591:29 | source | |
| taint.cpp:591:24:591:29 | source | taint.cpp:594:29:594:34 | source | | | taint.cpp:591:24:591:29 | source | taint.cpp:594:29:594:34 | source | |
| taint.cpp:592:23:592:30 | ,.-;:_ | taint.cpp:594:37:594:41 | delim | | | taint.cpp:592:23:592:30 | ,.-;:_ | taint.cpp:594:37:594:41 | delim | |
| taint.cpp:594:9:594:17 | tokenized | taint.cpp:594:9:594:42 | ... = ... | | | taint.cpp:594:9:594:17 | tokenized | taint.cpp:594:9:594:42 | ... = ... | |
@@ -6347,6 +6394,7 @@
| taint.cpp:594:21:594:26 | call to strsep | taint.cpp:595:10:595:18 | tokenized | | | taint.cpp:594:21:594:26 | call to strsep | taint.cpp:595:10:595:18 | tokenized | |
| taint.cpp:594:21:594:26 | call to strsep | taint.cpp:596:11:596:19 | tokenized | | | taint.cpp:594:21:594:26 | call to strsep | taint.cpp:596:11:596:19 | tokenized | |
| taint.cpp:594:28:594:34 | & ... | taint.cpp:594:21:594:26 | call to strsep | TAINT | | taint.cpp:594:28:594:34 | & ... | taint.cpp:594:21:594:26 | call to strsep | TAINT |
| taint.cpp:594:28:594:34 | ref arg & ... | taint.cpp:591:24:591:29 | source | |
| taint.cpp:594:28:594:34 | ref arg & ... | taint.cpp:594:29:594:34 | source | | | taint.cpp:594:28:594:34 | ref arg & ... | taint.cpp:594:29:594:34 | source | |
| taint.cpp:594:28:594:34 | ref arg & ... | taint.cpp:594:29:594:34 | source [inner post update] | | | taint.cpp:594:28:594:34 | ref arg & ... | taint.cpp:594:29:594:34 | source [inner post update] | |
| taint.cpp:594:29:594:34 | source | taint.cpp:594:21:594:26 | call to strsep | TAINT | | taint.cpp:594:29:594:34 | source | taint.cpp:594:21:594:26 | call to strsep | TAINT |
@@ -6354,45 +6402,63 @@
| taint.cpp:594:37:594:41 | delim | taint.cpp:594:21:594:26 | call to strsep | TAINT | | taint.cpp:594:37:594:41 | delim | taint.cpp:594:21:594:26 | call to strsep | TAINT |
| taint.cpp:595:10:595:18 | ref arg tokenized | taint.cpp:596:11:596:19 | tokenized | | | taint.cpp:595:10:595:18 | ref arg tokenized | taint.cpp:596:11:596:19 | tokenized | |
| taint.cpp:596:11:596:19 | tokenized | taint.cpp:596:10:596:19 | * ... | TAINT | | taint.cpp:596:11:596:19 | tokenized | taint.cpp:596:10:596:19 | * ... | TAINT |
| taint.cpp:606:25:606:30 | source | taint.cpp:606:25:606:30 | source | |
| taint.cpp:606:25:606:30 | source | taint.cpp:607:18:607:23 | source | | | taint.cpp:606:25:606:30 | source | taint.cpp:607:18:607:23 | source | |
| taint.cpp:606:39:606:43 | clean | taint.cpp:606:39:606:43 | clean | |
| taint.cpp:606:39:606:43 | clean | taint.cpp:611:18:611:22 | clean | | | taint.cpp:606:39:606:43 | clean | taint.cpp:611:18:611:22 | clean | |
| taint.cpp:606:82:606:87 | locale | taint.cpp:606:82:606:87 | locale | |
| taint.cpp:606:82:606:87 | locale | taint.cpp:607:26:607:31 | locale | | | taint.cpp:606:82:606:87 | locale | taint.cpp:607:26:607:31 | locale | |
| taint.cpp:606:82:606:87 | locale | taint.cpp:611:25:611:30 | locale | | | taint.cpp:606:82:606:87 | locale | taint.cpp:611:25:611:30 | locale | |
| taint.cpp:607:10:607:16 | call to _strinc | taint.cpp:606:52:606:56 | dest1 | |
| taint.cpp:607:10:607:16 | call to _strinc | taint.cpp:607:2:607:32 | ... = ... | | | taint.cpp:607:10:607:16 | call to _strinc | taint.cpp:607:2:607:32 | ... = ... | |
| taint.cpp:607:10:607:16 | call to _strinc | taint.cpp:608:7:608:11 | dest1 | | | taint.cpp:607:10:607:16 | call to _strinc | taint.cpp:608:7:608:11 | dest1 | |
| taint.cpp:607:10:607:16 | call to _strinc | taint.cpp:609:8:609:12 | dest1 | | | taint.cpp:607:10:607:16 | call to _strinc | taint.cpp:609:8:609:12 | dest1 | |
| taint.cpp:607:18:607:23 | source | taint.cpp:607:10:607:16 | call to _strinc | TAINT | | taint.cpp:607:18:607:23 | source | taint.cpp:607:10:607:16 | call to _strinc | TAINT |
| taint.cpp:607:26:607:31 | locale | taint.cpp:607:10:607:16 | call to _strinc | TAINT | | taint.cpp:607:26:607:31 | locale | taint.cpp:607:10:607:16 | call to _strinc | TAINT |
| taint.cpp:607:26:607:31 | ref arg locale | taint.cpp:606:82:606:87 | locale | |
| taint.cpp:607:26:607:31 | ref arg locale | taint.cpp:611:25:611:30 | locale | | | taint.cpp:607:26:607:31 | ref arg locale | taint.cpp:611:25:611:30 | locale | |
| taint.cpp:608:7:608:11 | ref arg dest1 | taint.cpp:606:52:606:56 | dest1 | |
| taint.cpp:608:7:608:11 | ref arg dest1 | taint.cpp:609:8:609:12 | dest1 | | | taint.cpp:608:7:608:11 | ref arg dest1 | taint.cpp:609:8:609:12 | dest1 | |
| taint.cpp:609:8:609:12 | dest1 | taint.cpp:609:7:609:12 | * ... | TAINT | | taint.cpp:609:8:609:12 | dest1 | taint.cpp:609:7:609:12 | * ... | TAINT |
| taint.cpp:611:10:611:16 | call to _strinc | taint.cpp:606:65:606:69 | dest2 | |
| taint.cpp:611:10:611:16 | call to _strinc | taint.cpp:611:2:611:31 | ... = ... | | | taint.cpp:611:10:611:16 | call to _strinc | taint.cpp:611:2:611:31 | ... = ... | |
| taint.cpp:611:10:611:16 | call to _strinc | taint.cpp:612:7:612:11 | dest2 | | | taint.cpp:611:10:611:16 | call to _strinc | taint.cpp:612:7:612:11 | dest2 | |
| taint.cpp:611:10:611:16 | call to _strinc | taint.cpp:613:8:613:12 | dest2 | | | taint.cpp:611:10:611:16 | call to _strinc | taint.cpp:613:8:613:12 | dest2 | |
| taint.cpp:611:18:611:22 | clean | taint.cpp:611:10:611:16 | call to _strinc | TAINT | | taint.cpp:611:18:611:22 | clean | taint.cpp:611:10:611:16 | call to _strinc | TAINT |
| taint.cpp:611:25:611:30 | locale | taint.cpp:611:10:611:16 | call to _strinc | TAINT | | taint.cpp:611:25:611:30 | locale | taint.cpp:611:10:611:16 | call to _strinc | TAINT |
| taint.cpp:611:25:611:30 | ref arg locale | taint.cpp:606:82:606:87 | locale | |
| taint.cpp:612:7:612:11 | ref arg dest2 | taint.cpp:606:65:606:69 | dest2 | |
| taint.cpp:612:7:612:11 | ref arg dest2 | taint.cpp:613:8:613:12 | dest2 | | | taint.cpp:612:7:612:11 | ref arg dest2 | taint.cpp:613:8:613:12 | dest2 | |
| taint.cpp:613:8:613:12 | dest2 | taint.cpp:613:7:613:12 | * ... | TAINT | | taint.cpp:613:8:613:12 | dest2 | taint.cpp:613:7:613:12 | * ... | TAINT |
| taint.cpp:616:34:616:48 | source_unsigned | taint.cpp:616:34:616:48 | source_unsigned | |
| taint.cpp:616:34:616:48 | source_unsigned | taint.cpp:617:26:617:40 | source_unsigned | | | taint.cpp:616:34:616:48 | source_unsigned | taint.cpp:617:26:617:40 | source_unsigned | |
| taint.cpp:616:57:616:62 | source | taint.cpp:616:57:616:62 | source | |
| taint.cpp:616:57:616:62 | source | taint.cpp:621:40:621:45 | source | | | taint.cpp:616:57:616:62 | source | taint.cpp:621:40:621:45 | source | |
| taint.cpp:617:18:617:24 | call to _mbsinc | taint.cpp:616:80:616:92 | dest_unsigned | |
| taint.cpp:617:18:617:24 | call to _mbsinc | taint.cpp:617:2:617:41 | ... = ... | | | taint.cpp:617:18:617:24 | call to _mbsinc | taint.cpp:617:2:617:41 | ... = ... | |
| taint.cpp:617:18:617:24 | call to _mbsinc | taint.cpp:618:7:618:19 | dest_unsigned | | | taint.cpp:617:18:617:24 | call to _mbsinc | taint.cpp:618:7:618:19 | dest_unsigned | |
| taint.cpp:617:18:617:24 | call to _mbsinc | taint.cpp:619:8:619:20 | dest_unsigned | | | taint.cpp:617:18:617:24 | call to _mbsinc | taint.cpp:619:8:619:20 | dest_unsigned | |
| taint.cpp:617:26:617:40 | source_unsigned | taint.cpp:617:18:617:24 | call to _mbsinc | TAINT | | taint.cpp:617:26:617:40 | source_unsigned | taint.cpp:617:18:617:24 | call to _mbsinc | TAINT |
| taint.cpp:618:7:618:19 | ref arg dest_unsigned | taint.cpp:616:80:616:92 | dest_unsigned | |
| taint.cpp:618:7:618:19 | ref arg dest_unsigned | taint.cpp:619:8:619:20 | dest_unsigned | | | taint.cpp:618:7:618:19 | ref arg dest_unsigned | taint.cpp:619:8:619:20 | dest_unsigned | |
| taint.cpp:619:8:619:20 | dest_unsigned | taint.cpp:619:7:619:20 | * ... | TAINT | | taint.cpp:619:8:619:20 | dest_unsigned | taint.cpp:619:7:619:20 | * ... | TAINT |
| taint.cpp:621:16:621:22 | call to _mbsinc | taint.cpp:616:101:616:104 | dest | |
| taint.cpp:621:16:621:22 | call to _mbsinc | taint.cpp:621:2:621:46 | ... = ... | | | taint.cpp:621:16:621:22 | call to _mbsinc | taint.cpp:621:2:621:46 | ... = ... | |
| taint.cpp:621:16:621:22 | call to _mbsinc | taint.cpp:622:7:622:10 | dest | | | taint.cpp:621:16:621:22 | call to _mbsinc | taint.cpp:622:7:622:10 | dest | |
| taint.cpp:621:16:621:22 | call to _mbsinc | taint.cpp:623:8:623:11 | dest | | | taint.cpp:621:16:621:22 | call to _mbsinc | taint.cpp:623:8:623:11 | dest | |
| taint.cpp:621:40:621:45 | source | taint.cpp:621:16:621:22 | call to _mbsinc | TAINT | | taint.cpp:621:40:621:45 | source | taint.cpp:621:16:621:22 | call to _mbsinc | TAINT |
| taint.cpp:622:7:622:10 | ref arg dest | taint.cpp:616:101:616:104 | dest | |
| taint.cpp:622:7:622:10 | ref arg dest | taint.cpp:623:8:623:11 | dest | | | taint.cpp:622:7:622:10 | ref arg dest | taint.cpp:623:8:623:11 | dest | |
| taint.cpp:623:8:623:11 | dest | taint.cpp:623:7:623:11 | * ... | TAINT | | taint.cpp:623:8:623:11 | dest | taint.cpp:623:7:623:11 | * ... | TAINT |
| taint.cpp:626:40:626:45 | source | taint.cpp:626:40:626:45 | source | |
| taint.cpp:626:40:626:45 | source | taint.cpp:627:18:627:23 | source | | | taint.cpp:626:40:626:45 | source | taint.cpp:627:18:627:23 | source | |
| taint.cpp:626:40:626:45 | source | taint.cpp:627:31:627:36 | source | | | taint.cpp:626:40:626:45 | source | taint.cpp:627:31:627:36 | source | |
| taint.cpp:626:40:626:45 | source | taint.cpp:633:25:633:30 | source | | | taint.cpp:626:40:626:45 | source | taint.cpp:633:25:633:30 | source | |
| taint.cpp:626:40:626:45 | source | taint.cpp:638:18:638:23 | source | | | taint.cpp:626:40:626:45 | source | taint.cpp:638:18:638:23 | source | |
| taint.cpp:626:63:626:67 | clean | taint.cpp:626:63:626:67 | clean | |
| taint.cpp:626:63:626:67 | clean | taint.cpp:633:18:633:22 | clean | | | taint.cpp:626:63:626:67 | clean | taint.cpp:633:18:633:22 | clean | |
| taint.cpp:626:63:626:67 | clean | taint.cpp:638:26:638:30 | clean | | | taint.cpp:626:63:626:67 | clean | taint.cpp:638:26:638:30 | clean | |
| taint.cpp:627:10:627:16 | call to _strdec | taint.cpp:626:85:626:89 | dest1 | |
| taint.cpp:627:10:627:16 | call to _strdec | taint.cpp:627:2:627:37 | ... = ... | | | taint.cpp:627:10:627:16 | call to _strdec | taint.cpp:627:2:627:37 | ... = ... | |
| taint.cpp:627:10:627:16 | call to _strdec | taint.cpp:628:7:628:11 | dest1 | | | taint.cpp:627:10:627:16 | call to _strdec | taint.cpp:628:7:628:11 | dest1 | |
| taint.cpp:627:10:627:16 | call to _strdec | taint.cpp:629:8:629:12 | dest1 | | | taint.cpp:627:10:627:16 | call to _strdec | taint.cpp:629:8:629:12 | dest1 | |
@@ -6400,20 +6466,25 @@
| taint.cpp:627:18:627:28 | ... + ... | taint.cpp:627:10:627:16 | call to _strdec | TAINT | | taint.cpp:627:18:627:28 | ... + ... | taint.cpp:627:10:627:16 | call to _strdec | TAINT |
| taint.cpp:627:27:627:28 | 12 | taint.cpp:627:18:627:28 | ... + ... | TAINT | | taint.cpp:627:27:627:28 | 12 | taint.cpp:627:18:627:28 | ... + ... | TAINT |
| taint.cpp:627:31:627:36 | source | taint.cpp:627:10:627:16 | call to _strdec | TAINT | | taint.cpp:627:31:627:36 | source | taint.cpp:627:10:627:16 | call to _strdec | TAINT |
| taint.cpp:628:7:628:11 | ref arg dest1 | taint.cpp:626:85:626:89 | dest1 | |
| taint.cpp:628:7:628:11 | ref arg dest1 | taint.cpp:629:8:629:12 | dest1 | | | taint.cpp:628:7:628:11 | ref arg dest1 | taint.cpp:629:8:629:12 | dest1 | |
| taint.cpp:629:8:629:12 | dest1 | taint.cpp:629:7:629:12 | * ... | TAINT | | taint.cpp:629:8:629:12 | dest1 | taint.cpp:629:7:629:12 | * ... | TAINT |
| taint.cpp:633:10:633:16 | call to _strdec | taint.cpp:626:107:626:111 | dest2 | |
| taint.cpp:633:10:633:16 | call to _strdec | taint.cpp:633:2:633:31 | ... = ... | | | taint.cpp:633:10:633:16 | call to _strdec | taint.cpp:633:2:633:31 | ... = ... | |
| taint.cpp:633:10:633:16 | call to _strdec | taint.cpp:634:7:634:11 | dest2 | | | taint.cpp:633:10:633:16 | call to _strdec | taint.cpp:634:7:634:11 | dest2 | |
| taint.cpp:633:10:633:16 | call to _strdec | taint.cpp:635:8:635:12 | dest2 | | | taint.cpp:633:10:633:16 | call to _strdec | taint.cpp:635:8:635:12 | dest2 | |
| taint.cpp:633:18:633:22 | clean | taint.cpp:633:10:633:16 | call to _strdec | TAINT | | taint.cpp:633:18:633:22 | clean | taint.cpp:633:10:633:16 | call to _strdec | TAINT |
| taint.cpp:633:25:633:30 | source | taint.cpp:633:10:633:16 | call to _strdec | TAINT | | taint.cpp:633:25:633:30 | source | taint.cpp:633:10:633:16 | call to _strdec | TAINT |
| taint.cpp:634:7:634:11 | ref arg dest2 | taint.cpp:626:107:626:111 | dest2 | |
| taint.cpp:634:7:634:11 | ref arg dest2 | taint.cpp:635:8:635:12 | dest2 | | | taint.cpp:634:7:634:11 | ref arg dest2 | taint.cpp:635:8:635:12 | dest2 | |
| taint.cpp:635:8:635:12 | dest2 | taint.cpp:635:7:635:12 | * ... | TAINT | | taint.cpp:635:8:635:12 | dest2 | taint.cpp:635:7:635:12 | * ... | TAINT |
| taint.cpp:638:10:638:16 | call to _strdec | taint.cpp:626:129:626:133 | dest3 | |
| taint.cpp:638:10:638:16 | call to _strdec | taint.cpp:638:2:638:31 | ... = ... | | | taint.cpp:638:10:638:16 | call to _strdec | taint.cpp:638:2:638:31 | ... = ... | |
| taint.cpp:638:10:638:16 | call to _strdec | taint.cpp:639:7:639:11 | dest3 | | | taint.cpp:638:10:638:16 | call to _strdec | taint.cpp:639:7:639:11 | dest3 | |
| taint.cpp:638:10:638:16 | call to _strdec | taint.cpp:640:8:640:12 | dest3 | | | taint.cpp:638:10:638:16 | call to _strdec | taint.cpp:640:8:640:12 | dest3 | |
| taint.cpp:638:18:638:23 | source | taint.cpp:638:10:638:16 | call to _strdec | TAINT | | taint.cpp:638:18:638:23 | source | taint.cpp:638:10:638:16 | call to _strdec | TAINT |
| taint.cpp:638:26:638:30 | clean | taint.cpp:638:10:638:16 | call to _strdec | TAINT | | taint.cpp:638:26:638:30 | clean | taint.cpp:638:10:638:16 | call to _strdec | TAINT |
| taint.cpp:639:7:639:11 | ref arg dest3 | taint.cpp:626:129:626:133 | dest3 | |
| taint.cpp:639:7:639:11 | ref arg dest3 | taint.cpp:640:8:640:12 | dest3 | | | taint.cpp:639:7:639:11 | ref arg dest3 | taint.cpp:640:8:640:12 | dest3 | |
| taint.cpp:640:8:640:12 | dest3 | taint.cpp:640:7:640:12 | * ... | TAINT | | taint.cpp:640:8:640:12 | dest3 | taint.cpp:640:7:640:12 | * ... | TAINT |
| taint.cpp:647:33:647:38 | source | taint.cpp:650:17:650:22 | source | | | taint.cpp:647:33:647:38 | source | taint.cpp:650:17:650:22 | source | |
@@ -6427,19 +6498,23 @@
| taint.cpp:653:6:653:14 | call to _strnextc | taint.cpp:654:7:654:7 | c | | | taint.cpp:653:6:653:14 | call to _strnextc | taint.cpp:654:7:654:7 | c | |
| taint.cpp:653:16:653:17 | | taint.cpp:653:6:653:14 | call to _strnextc | TAINT | | taint.cpp:653:16:653:17 | | taint.cpp:653:6:653:14 | call to _strnextc | TAINT |
| taint.cpp:662:9:662:12 | this | taint.cpp:662:25:662:29 | this | | | taint.cpp:662:9:662:12 | this | taint.cpp:662:25:662:29 | this | |
| taint.cpp:665:33:665:38 | source | taint.cpp:665:33:665:38 | source | |
| taint.cpp:665:33:665:38 | source | taint.cpp:667:20:667:25 | source | | | taint.cpp:665:33:665:38 | source | taint.cpp:667:20:667:25 | source | |
| taint.cpp:666:30:666:30 | c | taint.cpp:667:10:667:10 | c | | | taint.cpp:666:30:666:30 | c | taint.cpp:667:10:667:10 | c | |
| taint.cpp:666:30:666:30 | c | taint.cpp:668:8:668:8 | c | | | taint.cpp:666:30:666:30 | c | taint.cpp:668:8:668:8 | c | |
| taint.cpp:667:10:667:10 | ref arg c | taint.cpp:668:8:668:8 | c | | | taint.cpp:667:10:667:10 | ref arg c | taint.cpp:668:8:668:8 | c | |
| taint.cpp:667:12:667:15 | call to data | taint.cpp:667:3:667:8 | call to memcpy | | | taint.cpp:667:12:667:15 | call to data | taint.cpp:667:3:667:8 | call to memcpy | |
| taint.cpp:667:20:667:25 | ref arg source | taint.cpp:665:33:665:38 | source | |
| taint.cpp:667:20:667:25 | source | taint.cpp:667:3:667:8 | call to memcpy | TAINT | | taint.cpp:667:20:667:25 | source | taint.cpp:667:3:667:8 | call to memcpy | TAINT |
| taint.cpp:667:20:667:25 | source | taint.cpp:667:12:667:15 | ref arg call to data | TAINT | | taint.cpp:667:20:667:25 | source | taint.cpp:667:12:667:15 | ref arg call to data | TAINT |
| taint.cpp:674:9:674:12 | this | taint.cpp:674:31:674:35 | this | | | taint.cpp:674:9:674:12 | this | taint.cpp:674:31:674:35 | this | |
| taint.cpp:677:35:677:40 | source | taint.cpp:677:35:677:40 | source | |
| taint.cpp:677:35:677:40 | source | taint.cpp:679:20:679:25 | source | | | taint.cpp:677:35:677:40 | source | taint.cpp:679:20:679:25 | source | |
| taint.cpp:678:27:678:27 | c | taint.cpp:679:10:679:10 | c | | | taint.cpp:678:27:678:27 | c | taint.cpp:679:10:679:10 | c | |
| taint.cpp:678:27:678:27 | c | taint.cpp:680:8:680:8 | c | | | taint.cpp:678:27:678:27 | c | taint.cpp:680:8:680:8 | c | |
| taint.cpp:679:10:679:10 | ref arg c | taint.cpp:680:8:680:8 | c | | | taint.cpp:679:10:679:10 | ref arg c | taint.cpp:680:8:680:8 | c | |
| taint.cpp:679:12:679:15 | call to data | taint.cpp:679:3:679:8 | call to memcpy | | | taint.cpp:679:12:679:15 | call to data | taint.cpp:679:3:679:8 | call to memcpy | |
| taint.cpp:679:20:679:25 | ref arg source | taint.cpp:677:35:677:40 | source | |
| taint.cpp:679:20:679:25 | source | taint.cpp:679:3:679:8 | call to memcpy | TAINT | | taint.cpp:679:20:679:25 | source | taint.cpp:679:3:679:8 | call to memcpy | TAINT |
| taint.cpp:679:20:679:25 | source | taint.cpp:679:12:679:15 | ref arg call to data | TAINT | | taint.cpp:679:20:679:25 | source | taint.cpp:679:12:679:15 | ref arg call to data | TAINT |
| taint.cpp:690:14:690:14 | s | taint.cpp:691:18:691:18 | s | | | taint.cpp:690:14:690:14 | s | taint.cpp:691:18:691:18 | s | |
@@ -7782,6 +7857,7 @@
| vector.cpp:413:11:413:16 | call to source | vector.cpp:413:2:413:2 | call to operator* [post update] | TAINT | | vector.cpp:413:11:413:16 | call to source | vector.cpp:413:2:413:2 | call to operator* [post update] | TAINT |
| vector.cpp:413:11:413:16 | call to source | vector.cpp:413:2:413:18 | ... = ... | | | vector.cpp:413:11:413:16 | call to source | vector.cpp:413:2:413:18 | ... = ... | |
| vector.cpp:414:7:414:9 | ref arg v14 | vector.cpp:415:1:415:1 | v14 | | | vector.cpp:414:7:414:9 | ref arg v14 | vector.cpp:415:1:415:1 | v14 | |
| vector.cpp:417:33:417:45 | source_string | vector.cpp:417:33:417:45 | source_string | |
| vector.cpp:417:33:417:45 | source_string | vector.cpp:421:23:421:35 | source_string | | | vector.cpp:417:33:417:45 | source_string | vector.cpp:421:23:421:35 | source_string | |
| vector.cpp:417:33:417:45 | source_string | vector.cpp:428:23:428:35 | source_string | | | vector.cpp:417:33:417:45 | source_string | vector.cpp:428:23:428:35 | source_string | |
| vector.cpp:417:33:417:45 | source_string | vector.cpp:442:23:442:35 | source_string | | | vector.cpp:417:33:417:45 | source_string | vector.cpp:442:23:442:35 | source_string | |

View File

@@ -1,3 +1,3 @@
| file://:0:0:0:0 | __wchar_t * | PointerType | Wchar_t, WideCharType | | file://:0:0:0:0 | __wchar_t * | IteratorByPointer, PointerType | Wchar_t, WideCharType |
| file://:0:0:0:0 | const __wchar_t | SpecifiedType | Wchar_t, WideCharType | | file://:0:0:0:0 | const __wchar_t | SpecifiedType | Wchar_t, WideCharType |
| file://:0:0:0:0 | wchar_t | Wchar_t, WideCharType | | | file://:0:0:0:0 | wchar_t | Wchar_t, WideCharType | |

View File

@@ -1,3 +1,3 @@
| file://:0:0:0:0 | wchar_t | Wchar_t, WideCharType | | | file://:0:0:0:0 | wchar_t | Wchar_t, WideCharType | |
| file://:0:0:0:0 | wchar_t * | PointerType | CTypedefType, Wchar_t | | file://:0:0:0:0 | wchar_t * | IteratorByPointer, PointerType | CTypedefType, Wchar_t |
| ms.c:2:24:2:30 | wchar_t | CTypedefType, Wchar_t | | | ms.c:2:24:2:30 | wchar_t | CTypedefType, Wchar_t | |

View File

@@ -30,7 +30,7 @@
| char8_t | Char8Type | | | | | | char8_t | Char8Type | | | | |
| char16_t | Char16Type | | | | | | char16_t | Char16Type | | | | |
| char32_t | Char32Type | | | | | | char32_t | Char32Type | | | | |
| char * | CharPointerType | | char | | | | char * | CharPointerType, IteratorByPointer | | char | | |
| char *[3] | ArrayType | char * | char * | | | | char *[3] | ArrayType | char * | char * | | |
| char *[32] | ArrayType | char * | char * | | | | char *[32] | ArrayType | char * | char * | | |
| char *[] | ArrayType | char * | char * | | | | char *[] | ArrayType | char * | char * | | |
@@ -48,7 +48,7 @@
| const address | SpecifiedType | | address | | | | const address | SpecifiedType | | address | | |
| const address & | LValueReferenceType | | const address | | | | const address & | LValueReferenceType | | const address | | |
| const char | SpecifiedType | | char | | | | const char | SpecifiedType | | char | | |
| const char * | PointerType | | const char | | | | const char * | IteratorByPointer, PointerType | | const char | | |
| const char *[3] | ArrayType | const char * | const char * | | | | const char *[3] | ArrayType | const char * | const char * | | |
| const char *[] | ArrayType | const char * | const char * | | | | const char *[] | ArrayType | const char * | const char * | | |
| const char[5] | ArrayType | const char | const char | | | | const char[5] | ArrayType | const char | const char | | |
@@ -65,7 +65,7 @@
| float | FloatType | | | | | | float | FloatType | | | | |
| float[3] | ArrayType | float | float | | | | float[3] | ArrayType | float | float | | |
| int | IntType, MicrosoftInt32Type | | | | | | int | IntType, MicrosoftInt32Type | | | | |
| int * | IntPointerType | | int | | | | int * | IntPointerType, IteratorByPointer | | int | | |
| int[4] | ArrayType | int | int | | | | int[4] | ArrayType | int | int | | |
| int[8] | ArrayType | int | int | | | | int[8] | ArrayType | int | int | | |
| int[10] | ArrayType | int | int | | | | int[10] | ArrayType | int | int | | |
@@ -90,5 +90,5 @@
| unsigned long long | LongLongType | | | | unsigned integral | | unsigned long long | LongLongType | | | | unsigned integral |
| unsigned short | ShortType | | | | unsigned integral | | unsigned short | ShortType | | | | unsigned integral |
| void | VoidType | | | | | | void | VoidType | | | | |
| void * | VoidPointerType | | void | | | | void * | IteratorByPointer, VoidPointerType | | void | | |
| wchar_t | Wchar_t, WideCharType | | | | | | wchar_t | Wchar_t, WideCharType | | | | |

View File

@@ -1,47 +1,137 @@
edges edges
| test.cpp:26:29:26:29 | b | test.cpp:26:29:26:29 | b |
| test.cpp:26:29:26:29 | b | test.cpp:27:2:27:2 | b | | test.cpp:26:29:26:29 | b | test.cpp:27:2:27:2 | b |
| test.cpp:30:34:30:34 | b | test.cpp:31:2:31:2 | b | | test.cpp:30:34:30:34 | b | test.cpp:31:2:31:2 | b |
| test.cpp:34:31:34:31 | b | test.cpp:34:31:34:31 | b |
| test.cpp:34:31:34:31 | b | test.cpp:35:2:35:2 | b | | test.cpp:34:31:34:31 | b | test.cpp:35:2:35:2 | b |
| test.cpp:38:35:38:35 | d | test.cpp:38:35:38:35 | d |
| test.cpp:38:35:38:35 | d | test.cpp:39:2:39:2 | d |
| test.cpp:42:40:42:40 | d | test.cpp:43:2:43:2 | d |
| test.cpp:46:37:46:37 | d | test.cpp:46:37:46:37 | d |
| test.cpp:46:37:46:37 | d | test.cpp:47:2:47:2 | d |
| test.cpp:50:31:50:31 | b | test.cpp:51:11:51:11 | b | | test.cpp:50:31:50:31 | b | test.cpp:51:11:51:11 | b |
| test.cpp:57:19:57:19 | d | test.cpp:26:29:26:29 | b | | test.cpp:57:19:57:19 | d | test.cpp:26:29:26:29 | b |
| test.cpp:57:19:57:19 | d | test.cpp:57:19:57:19 | ref arg d |
| test.cpp:57:19:57:19 | ref arg d | test.cpp:58:25:58:25 | d |
| test.cpp:57:19:57:19 | ref arg d | test.cpp:59:21:59:21 | d |
| test.cpp:57:19:57:19 | ref arg d | test.cpp:61:22:61:22 | d |
| test.cpp:57:19:57:19 | ref arg d | test.cpp:62:28:62:28 | d |
| test.cpp:57:19:57:19 | ref arg d | test.cpp:63:24:63:24 | d |
| test.cpp:57:19:57:19 | ref arg d | test.cpp:95:21:95:21 | d |
| test.cpp:58:25:58:25 | d | test.cpp:30:34:30:34 | b | | test.cpp:58:25:58:25 | d | test.cpp:30:34:30:34 | b |
| test.cpp:59:21:59:21 | d | test.cpp:34:31:34:31 | b | | test.cpp:59:21:59:21 | d | test.cpp:34:31:34:31 | b |
| test.cpp:59:21:59:21 | d | test.cpp:59:21:59:21 | ref arg d |
| test.cpp:59:21:59:21 | ref arg d | test.cpp:61:22:61:22 | d |
| test.cpp:59:21:59:21 | ref arg d | test.cpp:62:28:62:28 | d |
| test.cpp:59:21:59:21 | ref arg d | test.cpp:63:24:63:24 | d |
| test.cpp:59:21:59:21 | ref arg d | test.cpp:95:21:95:21 | d |
| test.cpp:61:22:61:22 | d | test.cpp:38:35:38:35 | d |
| test.cpp:61:22:61:22 | d | test.cpp:61:22:61:22 | ref arg d |
| test.cpp:61:22:61:22 | ref arg d | test.cpp:62:28:62:28 | d |
| test.cpp:61:22:61:22 | ref arg d | test.cpp:63:24:63:24 | d |
| test.cpp:61:22:61:22 | ref arg d | test.cpp:95:21:95:21 | d |
| test.cpp:62:28:62:28 | d | test.cpp:42:40:42:40 | d |
| test.cpp:63:24:63:24 | d | test.cpp:46:37:46:37 | d |
| test.cpp:63:24:63:24 | d | test.cpp:63:24:63:24 | ref arg d |
| test.cpp:63:24:63:24 | ref arg d | test.cpp:95:21:95:21 | d |
| test.cpp:74:19:74:21 | dss | test.cpp:26:29:26:29 | b | | test.cpp:74:19:74:21 | dss | test.cpp:26:29:26:29 | b |
| test.cpp:74:19:74:21 | dss | test.cpp:74:19:74:21 | ref arg dss |
| test.cpp:74:19:74:21 | ref arg dss | test.cpp:75:25:75:27 | dss |
| test.cpp:74:19:74:21 | ref arg dss | test.cpp:76:21:76:23 | dss |
| test.cpp:74:19:74:21 | ref arg dss | test.cpp:96:21:96:23 | dss |
| test.cpp:75:25:75:27 | dss | test.cpp:30:34:30:34 | b | | test.cpp:75:25:75:27 | dss | test.cpp:30:34:30:34 | b |
| test.cpp:76:21:76:23 | dss | test.cpp:34:31:34:31 | b | | test.cpp:76:21:76:23 | dss | test.cpp:34:31:34:31 | b |
| test.cpp:76:21:76:23 | dss | test.cpp:76:21:76:23 | ref arg dss |
| test.cpp:76:21:76:23 | ref arg dss | test.cpp:96:21:96:23 | dss |
| test.cpp:86:19:86:20 | d2 | test.cpp:26:29:26:29 | b | | test.cpp:86:19:86:20 | d2 | test.cpp:26:29:26:29 | b |
| test.cpp:86:19:86:20 | d2 | test.cpp:86:19:86:20 | ref arg d2 |
| test.cpp:86:19:86:20 | ref arg d2 | test.cpp:87:25:87:26 | d2 |
| test.cpp:86:19:86:20 | ref arg d2 | test.cpp:88:21:88:22 | d2 |
| test.cpp:86:19:86:20 | ref arg d2 | test.cpp:90:22:90:23 | d2 |
| test.cpp:86:19:86:20 | ref arg d2 | test.cpp:91:28:91:29 | d2 |
| test.cpp:86:19:86:20 | ref arg d2 | test.cpp:92:24:92:25 | d2 |
| test.cpp:87:25:87:26 | d2 | test.cpp:30:34:30:34 | b | | test.cpp:87:25:87:26 | d2 | test.cpp:30:34:30:34 | b |
| test.cpp:88:21:88:22 | d2 | test.cpp:34:31:34:31 | b | | test.cpp:88:21:88:22 | d2 | test.cpp:34:31:34:31 | b |
| test.cpp:88:21:88:22 | d2 | test.cpp:88:21:88:22 | ref arg d2 |
| test.cpp:88:21:88:22 | ref arg d2 | test.cpp:90:22:90:23 | d2 |
| test.cpp:88:21:88:22 | ref arg d2 | test.cpp:91:28:91:29 | d2 |
| test.cpp:88:21:88:22 | ref arg d2 | test.cpp:92:24:92:25 | d2 |
| test.cpp:90:22:90:23 | d2 | test.cpp:38:35:38:35 | d |
| test.cpp:90:22:90:23 | d2 | test.cpp:90:22:90:23 | ref arg d2 |
| test.cpp:90:22:90:23 | ref arg d2 | test.cpp:91:28:91:29 | d2 |
| test.cpp:90:22:90:23 | ref arg d2 | test.cpp:92:24:92:25 | d2 |
| test.cpp:91:28:91:29 | d2 | test.cpp:42:40:42:40 | d |
| test.cpp:92:24:92:25 | d2 | test.cpp:46:37:46:37 | d |
| test.cpp:95:21:95:21 | d | test.cpp:50:31:50:31 | b | | test.cpp:95:21:95:21 | d | test.cpp:50:31:50:31 | b |
| test.cpp:96:21:96:23 | dss | test.cpp:50:31:50:31 | b | | test.cpp:96:21:96:23 | dss | test.cpp:50:31:50:31 | b |
nodes nodes
| test.cpp:26:29:26:29 | b | semmle.label | b | | test.cpp:26:29:26:29 | b | semmle.label | b |
| test.cpp:26:29:26:29 | b | semmle.label | b |
| test.cpp:27:2:27:2 | b | semmle.label | b | | test.cpp:27:2:27:2 | b | semmle.label | b |
| test.cpp:30:34:30:34 | b | semmle.label | b | | test.cpp:30:34:30:34 | b | semmle.label | b |
| test.cpp:31:2:31:2 | b | semmle.label | b | | test.cpp:31:2:31:2 | b | semmle.label | b |
| test.cpp:34:31:34:31 | b | semmle.label | b | | test.cpp:34:31:34:31 | b | semmle.label | b |
| test.cpp:34:31:34:31 | b | semmle.label | b |
| test.cpp:35:2:35:2 | b | semmle.label | b | | test.cpp:35:2:35:2 | b | semmle.label | b |
| test.cpp:38:35:38:35 | d | semmle.label | d |
| test.cpp:38:35:38:35 | d | semmle.label | d |
| test.cpp:39:2:39:2 | d | semmle.label | d |
| test.cpp:42:40:42:40 | d | semmle.label | d |
| test.cpp:43:2:43:2 | d | semmle.label | d |
| test.cpp:46:37:46:37 | d | semmle.label | d |
| test.cpp:46:37:46:37 | d | semmle.label | d |
| test.cpp:47:2:47:2 | d | semmle.label | d |
| test.cpp:50:31:50:31 | b | semmle.label | b | | test.cpp:50:31:50:31 | b | semmle.label | b |
| test.cpp:51:11:51:11 | b | semmle.label | b | | test.cpp:51:11:51:11 | b | semmle.label | b |
| test.cpp:57:19:57:19 | d | semmle.label | d | | test.cpp:57:19:57:19 | d | semmle.label | d |
| test.cpp:57:19:57:19 | ref arg d | semmle.label | ref arg d |
| test.cpp:58:25:58:25 | d | semmle.label | d | | test.cpp:58:25:58:25 | d | semmle.label | d |
| test.cpp:59:21:59:21 | d | semmle.label | d | | test.cpp:59:21:59:21 | d | semmle.label | d |
| test.cpp:59:21:59:21 | ref arg d | semmle.label | ref arg d |
| test.cpp:61:22:61:22 | d | semmle.label | d |
| test.cpp:61:22:61:22 | ref arg d | semmle.label | ref arg d |
| test.cpp:62:28:62:28 | d | semmle.label | d |
| test.cpp:63:24:63:24 | d | semmle.label | d |
| test.cpp:63:24:63:24 | ref arg d | semmle.label | ref arg d |
| test.cpp:74:19:74:21 | dss | semmle.label | dss | | test.cpp:74:19:74:21 | dss | semmle.label | dss |
| test.cpp:74:19:74:21 | ref arg dss | semmle.label | ref arg dss |
| test.cpp:75:25:75:27 | dss | semmle.label | dss | | test.cpp:75:25:75:27 | dss | semmle.label | dss |
| test.cpp:76:21:76:23 | dss | semmle.label | dss | | test.cpp:76:21:76:23 | dss | semmle.label | dss |
| test.cpp:76:21:76:23 | ref arg dss | semmle.label | ref arg dss |
| test.cpp:86:19:86:20 | d2 | semmle.label | d2 | | test.cpp:86:19:86:20 | d2 | semmle.label | d2 |
| test.cpp:86:19:86:20 | ref arg d2 | semmle.label | ref arg d2 |
| test.cpp:87:25:87:26 | d2 | semmle.label | d2 | | test.cpp:87:25:87:26 | d2 | semmle.label | d2 |
| test.cpp:88:21:88:22 | d2 | semmle.label | d2 | | test.cpp:88:21:88:22 | d2 | semmle.label | d2 |
| test.cpp:88:21:88:22 | ref arg d2 | semmle.label | ref arg d2 |
| test.cpp:90:22:90:23 | d2 | semmle.label | d2 |
| test.cpp:90:22:90:23 | ref arg d2 | semmle.label | ref arg d2 |
| test.cpp:91:28:91:29 | d2 | semmle.label | d2 |
| test.cpp:92:24:92:25 | d2 | semmle.label | d2 |
| test.cpp:95:21:95:21 | d | semmle.label | d | | test.cpp:95:21:95:21 | d | semmle.label | d |
| test.cpp:96:21:96:23 | dss | semmle.label | dss | | test.cpp:96:21:96:23 | dss | semmle.label | dss |
subpaths subpaths
| test.cpp:57:19:57:19 | d | test.cpp:26:29:26:29 | b | test.cpp:26:29:26:29 | b | test.cpp:57:19:57:19 | ref arg d |
| test.cpp:59:21:59:21 | d | test.cpp:34:31:34:31 | b | test.cpp:34:31:34:31 | b | test.cpp:59:21:59:21 | ref arg d |
| test.cpp:61:22:61:22 | d | test.cpp:38:35:38:35 | d | test.cpp:38:35:38:35 | d | test.cpp:61:22:61:22 | ref arg d |
| test.cpp:63:24:63:24 | d | test.cpp:46:37:46:37 | d | test.cpp:46:37:46:37 | d | test.cpp:63:24:63:24 | ref arg d |
| test.cpp:74:19:74:21 | dss | test.cpp:26:29:26:29 | b | test.cpp:26:29:26:29 | b | test.cpp:74:19:74:21 | ref arg dss |
| test.cpp:76:21:76:23 | dss | test.cpp:34:31:34:31 | b | test.cpp:34:31:34:31 | b | test.cpp:76:21:76:23 | ref arg dss |
| test.cpp:86:19:86:20 | d2 | test.cpp:26:29:26:29 | b | test.cpp:26:29:26:29 | b | test.cpp:86:19:86:20 | ref arg d2 |
| test.cpp:88:21:88:22 | d2 | test.cpp:34:31:34:31 | b | test.cpp:34:31:34:31 | b | test.cpp:88:21:88:22 | ref arg d2 |
| test.cpp:90:22:90:23 | d2 | test.cpp:38:35:38:35 | d | test.cpp:38:35:38:35 | d | test.cpp:90:22:90:23 | ref arg d2 |
#select #select
| test.cpp:27:2:27:2 | b | test.cpp:57:19:57:19 | d | test.cpp:27:2:27:2 | b | Pointer arithmetic here may be done with the wrong type because of the cast $@. | test.cpp:57:19:57:19 | d | here | | test.cpp:27:2:27:2 | b | test.cpp:57:19:57:19 | d | test.cpp:27:2:27:2 | b | Pointer arithmetic here may be done with the wrong type because of the cast $@. | test.cpp:57:19:57:19 | d | here |
| test.cpp:27:2:27:2 | b | test.cpp:74:19:74:21 | dss | test.cpp:27:2:27:2 | b | Pointer arithmetic here may be done with the wrong type because of the cast $@. | test.cpp:74:19:74:21 | dss | here | | test.cpp:27:2:27:2 | b | test.cpp:74:19:74:21 | dss | test.cpp:27:2:27:2 | b | Pointer arithmetic here may be done with the wrong type because of the cast $@. | test.cpp:74:19:74:21 | dss | here |
| test.cpp:27:2:27:2 | b | test.cpp:86:19:86:20 | d2 | test.cpp:27:2:27:2 | b | Pointer arithmetic here may be done with the wrong type because of the cast $@. | test.cpp:86:19:86:20 | d2 | here | | test.cpp:27:2:27:2 | b | test.cpp:86:19:86:20 | d2 | test.cpp:27:2:27:2 | b | Pointer arithmetic here may be done with the wrong type because of the cast $@. | test.cpp:86:19:86:20 | d2 | here |
| test.cpp:31:2:31:2 | b | test.cpp:57:19:57:19 | d | test.cpp:31:2:31:2 | b | Pointer arithmetic here may be done with the wrong type because of the cast $@. | test.cpp:57:19:57:19 | d | here |
| test.cpp:31:2:31:2 | b | test.cpp:58:25:58:25 | d | test.cpp:31:2:31:2 | b | Pointer arithmetic here may be done with the wrong type because of the cast $@. | test.cpp:58:25:58:25 | d | here | | test.cpp:31:2:31:2 | b | test.cpp:58:25:58:25 | d | test.cpp:31:2:31:2 | b | Pointer arithmetic here may be done with the wrong type because of the cast $@. | test.cpp:58:25:58:25 | d | here |
| test.cpp:31:2:31:2 | b | test.cpp:74:19:74:21 | dss | test.cpp:31:2:31:2 | b | Pointer arithmetic here may be done with the wrong type because of the cast $@. | test.cpp:74:19:74:21 | dss | here |
| test.cpp:31:2:31:2 | b | test.cpp:75:25:75:27 | dss | test.cpp:31:2:31:2 | b | Pointer arithmetic here may be done with the wrong type because of the cast $@. | test.cpp:75:25:75:27 | dss | here | | test.cpp:31:2:31:2 | b | test.cpp:75:25:75:27 | dss | test.cpp:31:2:31:2 | b | Pointer arithmetic here may be done with the wrong type because of the cast $@. | test.cpp:75:25:75:27 | dss | here |
| test.cpp:31:2:31:2 | b | test.cpp:86:19:86:20 | d2 | test.cpp:31:2:31:2 | b | Pointer arithmetic here may be done with the wrong type because of the cast $@. | test.cpp:86:19:86:20 | d2 | here |
| test.cpp:31:2:31:2 | b | test.cpp:87:25:87:26 | d2 | test.cpp:31:2:31:2 | b | Pointer arithmetic here may be done with the wrong type because of the cast $@. | test.cpp:87:25:87:26 | d2 | here | | test.cpp:31:2:31:2 | b | test.cpp:87:25:87:26 | d2 | test.cpp:31:2:31:2 | b | Pointer arithmetic here may be done with the wrong type because of the cast $@. | test.cpp:87:25:87:26 | d2 | here |
| test.cpp:35:2:35:2 | b | test.cpp:57:19:57:19 | d | test.cpp:35:2:35:2 | b | Pointer arithmetic here may be done with the wrong type because of the cast $@. | test.cpp:57:19:57:19 | d | here |
| test.cpp:35:2:35:2 | b | test.cpp:59:21:59:21 | d | test.cpp:35:2:35:2 | b | Pointer arithmetic here may be done with the wrong type because of the cast $@. | test.cpp:59:21:59:21 | d | here | | test.cpp:35:2:35:2 | b | test.cpp:59:21:59:21 | d | test.cpp:35:2:35:2 | b | Pointer arithmetic here may be done with the wrong type because of the cast $@. | test.cpp:59:21:59:21 | d | here |
| test.cpp:35:2:35:2 | b | test.cpp:74:19:74:21 | dss | test.cpp:35:2:35:2 | b | Pointer arithmetic here may be done with the wrong type because of the cast $@. | test.cpp:74:19:74:21 | dss | here |
| test.cpp:35:2:35:2 | b | test.cpp:76:21:76:23 | dss | test.cpp:35:2:35:2 | b | Pointer arithmetic here may be done with the wrong type because of the cast $@. | test.cpp:76:21:76:23 | dss | here | | test.cpp:35:2:35:2 | b | test.cpp:76:21:76:23 | dss | test.cpp:35:2:35:2 | b | Pointer arithmetic here may be done with the wrong type because of the cast $@. | test.cpp:76:21:76:23 | dss | here |
| test.cpp:35:2:35:2 | b | test.cpp:86:19:86:20 | d2 | test.cpp:35:2:35:2 | b | Pointer arithmetic here may be done with the wrong type because of the cast $@. | test.cpp:86:19:86:20 | d2 | here |
| test.cpp:35:2:35:2 | b | test.cpp:88:21:88:22 | d2 | test.cpp:35:2:35:2 | b | Pointer arithmetic here may be done with the wrong type because of the cast $@. | test.cpp:88:21:88:22 | d2 | here | | test.cpp:35:2:35:2 | b | test.cpp:88:21:88:22 | d2 | test.cpp:35:2:35:2 | b | Pointer arithmetic here may be done with the wrong type because of the cast $@. | test.cpp:88:21:88:22 | d2 | here |

View File

@@ -85,6 +85,9 @@ module Public {
/** Holds if this stack contains summary component `c`. */ /** Holds if this stack contains summary component `c`. */
predicate contains(SummaryComponent c) { c = this.drop(_).head() } predicate contains(SummaryComponent c) { c = this.drop(_).head() }
/** Gets the bottom element of this stack. */
SummaryComponent bottom() { result = this.drop(this.length() - 1).head() }
/** Gets a textual representation of this stack. */ /** Gets a textual representation of this stack. */
string toString() { string toString() {
exists(SummaryComponent head, SummaryComponentStack tail | exists(SummaryComponent head, SummaryComponentStack tail |
@@ -197,6 +200,8 @@ module Private {
or or
tail.(RequiredSummaryComponentStack).required(TParameterSummaryComponent(_)) and tail.(RequiredSummaryComponentStack).required(TParameterSummaryComponent(_)) and
head = thisParam() head = thisParam()
or
derivedFluentFlowPush(_, _, _, head, tail, _)
} }
pragma[nomagic] pragma[nomagic]
@@ -210,7 +215,7 @@ module Private {
c.propagatesFlow(output, input, preservesValue) and c.propagatesFlow(output, input, preservesValue) and
preservesValue = true and preservesValue = true and
isCallbackParameter(input) and isCallbackParameter(input) and
isContentOfArgument(output) isContentOfArgument(output, _)
or or
// flow from the receiver of a callback into the instance-parameter // flow from the receiver of a callback into the instance-parameter
exists(SummaryComponentStack s, SummaryComponentStack callbackRef | exists(SummaryComponentStack s, SummaryComponentStack callbackRef |
@@ -222,16 +227,81 @@ module Private {
output = TConsSummaryComponentStack(thisParam(), input) and output = TConsSummaryComponentStack(thisParam(), input) and
preservesValue = true preservesValue = true
) )
or
exists(SummaryComponentStack arg, SummaryComponentStack return |
derivedFluentFlow(c, input, arg, return, preservesValue)
|
arg.length() = 1 and
output = return
or
exists(SummaryComponent head, SummaryComponentStack tail |
derivedFluentFlowPush(c, input, arg, head, tail, 0) and
output = SummaryComponentStack::push(head, tail)
)
)
or
// Chain together summaries where values get passed into callbacks along the way
exists(SummaryComponentStack mid, boolean preservesValue1, boolean preservesValue2 |
c.propagatesFlow(input, mid, preservesValue1) and
c.propagatesFlow(mid, output, preservesValue2) and
mid.drop(mid.length() - 2) =
SummaryComponentStack::push(TParameterSummaryComponent(_),
SummaryComponentStack::singleton(TArgumentSummaryComponent(_))) and
preservesValue = preservesValue1.booleanAnd(preservesValue2)
)
}
/**
* Holds if `c` has a flow summary from `input` to `arg`, where `arg`
* writes to (contents of) the `i`th argument, and `c` has a
* value-preserving flow summary from the `i`th argument to a return value
* (`return`).
*
* In such a case, we derive flow from `input` to (contents of) the return
* value.
*
* As an example, this simplifies modeling of fluent methods:
* for `StringBuilder.append(x)` with a specified value flow from qualifier to
* return value and taint flow from argument 0 to the qualifier, then this
* allows us to infer taint flow from argument 0 to the return value.
*/
pragma[nomagic]
private predicate derivedFluentFlow(
SummarizedCallable c, SummaryComponentStack input, SummaryComponentStack arg,
SummaryComponentStack return, boolean preservesValue
) {
exists(int i |
summary(c, input, arg, preservesValue) and
isContentOfArgument(arg, i) and
summary(c, SummaryComponentStack::singleton(TArgumentSummaryComponent(i)), return, true) and
return.bottom() = TReturnSummaryComponent(_)
)
}
pragma[nomagic]
private predicate derivedFluentFlowPush(
SummarizedCallable c, SummaryComponentStack input, SummaryComponentStack arg,
SummaryComponent head, SummaryComponentStack tail, int i
) {
derivedFluentFlow(c, input, arg, tail, _) and
head = arg.drop(i).head() and
i = arg.length() - 2
or
exists(SummaryComponent head0, SummaryComponentStack tail0 |
derivedFluentFlowPush(c, input, arg, head0, tail0, i + 1) and
head = arg.drop(i).head() and
tail = SummaryComponentStack::push(head0, tail0)
)
} }
private predicate isCallbackParameter(SummaryComponentStack s) { private predicate isCallbackParameter(SummaryComponentStack s) {
s.head() = TParameterSummaryComponent(_) and exists(s.tail()) s.head() = TParameterSummaryComponent(_) and exists(s.tail())
} }
private predicate isContentOfArgument(SummaryComponentStack s) { private predicate isContentOfArgument(SummaryComponentStack s, int i) {
s.head() = TContentSummaryComponent(_) and isContentOfArgument(s.tail()) s.head() = TContentSummaryComponent(_) and isContentOfArgument(s.tail(), i)
or or
s = TSingletonSummaryComponentStack(TArgumentSummaryComponent(_)) s = TSingletonSummaryComponentStack(TArgumentSummaryComponent(i))
} }
private predicate outputState(SummarizedCallable c, SummaryComponentStack s) { private predicate outputState(SummarizedCallable c, SummaryComponentStack s) {
@@ -508,9 +578,14 @@ module Private {
* node, and back out to `p`. * node, and back out to `p`.
*/ */
predicate summaryAllowParameterReturnInSelf(ParamNode p) { predicate summaryAllowParameterReturnInSelf(ParamNode p) {
exists(SummarizedCallable c, int i | exists(SummarizedCallable c, int i | p.isParameterOf(c, i) |
c.clearsContent(i, _) and c.clearsContent(i, _)
p.isParameterOf(c, i) or
exists(SummaryComponentStack inputContents, SummaryComponentStack outputContents |
summary(c, inputContents, outputContents, _) and
inputContents.bottom() = pragma[only_bind_into](TArgumentSummaryComponent(i)) and
outputContents.bottom() = pragma[only_bind_into](TArgumentSummaryComponent(i))
)
) )
} }
@@ -534,22 +609,6 @@ module Private {
preservesValue = false and not summary(c, inputContents, outputContents, true) preservesValue = false and not summary(c, inputContents, outputContents, true)
) )
or or
// If flow through a method updates a parameter from some input A, and that
// parameter also is returned through B, then we'd like a combined flow from A
// to B as well. As an example, this simplifies modeling of fluent methods:
// for `StringBuilder.append(x)` with a specified value flow from qualifier to
// return value and taint flow from argument 0 to the qualifier, then this
// allows us to infer taint flow from argument 0 to the return value.
succ instanceof ParamNode and
summaryPostUpdateNode(pred, succ) and
preservesValue = true
or
// Similarly we would like to chain together summaries where values get passed
// into callbacks along the way.
pred instanceof ArgNode and
summaryPostUpdateNode(succ, pred) and
preservesValue = true
or
exists(SummarizedCallable c, int i | exists(SummarizedCallable c, int i |
pred.(ParamNode).isParameterOf(c, i) and pred.(ParamNode).isParameterOf(c, i) and
succ = summaryNode(c, TSummaryNodeClearsContentState(i, _)) and succ = summaryNode(c, TSummaryNodeClearsContentState(i, _)) and

View File

@@ -174,32 +174,34 @@ module EntityFramework {
} }
} }
private class RawSqlStringSummarizedCallable extends EFSummarizedCallable { private class RawSqlStringConstructorSummarizedCallable extends EFSummarizedCallable {
private SummaryComponentStack input_; RawSqlStringConstructorSummarizedCallable() {
private SummaryComponentStack output_;
private boolean preservesValue_;
RawSqlStringSummarizedCallable() {
exists(RawSqlStringStruct s | exists(RawSqlStringStruct s |
this = s.getAConstructor() and this = s.getAConstructor() and
input_ = SummaryComponentStack::argument(0) and this.getNumberOfParameters() > 0
this.getNumberOfParameters() > 0 and
output_ = SummaryComponentStack::return() and
preservesValue_ = false
or
this = s.getAConversionTo() and
input_ = SummaryComponentStack::argument(0) and
output_ = SummaryComponentStack::return() and
preservesValue_ = false
) )
} }
override predicate propagatesFlow( override predicate propagatesFlow(
SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue
) { ) {
input = input_ and input = SummaryComponentStack::argument(0) and
output = output_ and output = SummaryComponentStack::return() and
preservesValue = preservesValue_ preservesValue = false
}
}
private class RawSqlStringConversionSummarizedCallable extends EFSummarizedCallable {
RawSqlStringConversionSummarizedCallable() {
exists(RawSqlStringStruct s | this = s.getAConversionTo())
}
override predicate propagatesFlow(
SummaryComponentStack input, SummaryComponentStack output, boolean preservesValue
) {
input = SummaryComponentStack::argument(0) and
output = SummaryComponentStack::return() and
preservesValue = false
} }
} }

View File

@@ -33,7 +33,7 @@ namespace My.Qltest
void M5() void M5()
{ {
this.StepFieldSetter(new object()); Sink(((D)this.StepFieldSetter(new object()).Field2).Field);
Sink(this.Field); Sink(this.Field);
} }
@@ -102,7 +102,7 @@ namespace My.Qltest
Sink(d); Sink(d);
}, d1, d2); }, d1, d2);
Sink(d1.Field); Sink(d1.Field);
Sink(d2.Field2); // SPURIOUS FLOW Sink(d2.Field2);
} }
object StepArgRes(object x) { return null; } object StepArgRes(object x) { return null; }
@@ -120,7 +120,7 @@ namespace My.Qltest
object StepFieldGetter() => throw null; object StepFieldGetter() => throw null;
void StepFieldSetter(object value) => throw null; D StepFieldSetter(object value) => throw null;
object Property { get; set; } object Property { get; set; }

View File

@@ -11,8 +11,12 @@ edges
| ExternalFlow.cs:30:13:30:16 | [post] this access [field Field] : Object | ExternalFlow.cs:31:18:31:21 | this access [field Field] : Object | | ExternalFlow.cs:30:13:30:16 | [post] this access [field Field] : Object | ExternalFlow.cs:31:18:31:21 | this access [field Field] : Object |
| ExternalFlow.cs:30:26:30:37 | object creation of type Object : Object | ExternalFlow.cs:30:13:30:16 | [post] this access [field Field] : Object | | ExternalFlow.cs:30:26:30:37 | object creation of type Object : Object | ExternalFlow.cs:30:13:30:16 | [post] this access [field Field] : Object |
| ExternalFlow.cs:31:18:31:21 | this access [field Field] : Object | ExternalFlow.cs:31:18:31:39 | call to method StepFieldGetter | | ExternalFlow.cs:31:18:31:21 | this access [field Field] : Object | ExternalFlow.cs:31:18:31:39 | call to method StepFieldGetter |
| ExternalFlow.cs:36:13:36:16 | [post] this access [field Field] : Object | ExternalFlow.cs:37:18:37:21 | this access [field Field] : Object | | ExternalFlow.cs:36:19:36:62 | (...) ... [field Field] : Object | ExternalFlow.cs:36:18:36:69 | access to field Field |
| ExternalFlow.cs:36:34:36:45 | object creation of type Object : Object | ExternalFlow.cs:36:13:36:16 | [post] this access [field Field] : Object | | ExternalFlow.cs:36:22:36:25 | [post] this access [field Field] : Object | ExternalFlow.cs:37:18:37:21 | this access [field Field] : Object |
| ExternalFlow.cs:36:22:36:55 | call to method StepFieldSetter [field Field2, field Field] : Object | ExternalFlow.cs:36:22:36:62 | access to field Field2 [field Field] : Object |
| ExternalFlow.cs:36:22:36:62 | access to field Field2 [field Field] : Object | ExternalFlow.cs:36:19:36:62 | (...) ... [field Field] : Object |
| ExternalFlow.cs:36:43:36:54 | object creation of type Object : Object | ExternalFlow.cs:36:22:36:25 | [post] this access [field Field] : Object |
| ExternalFlow.cs:36:43:36:54 | object creation of type Object : Object | ExternalFlow.cs:36:22:36:55 | call to method StepFieldSetter [field Field2, field Field] : Object |
| ExternalFlow.cs:37:18:37:21 | this access [field Field] : Object | ExternalFlow.cs:37:18:37:27 | access to field Field | | ExternalFlow.cs:37:18:37:21 | this access [field Field] : Object | ExternalFlow.cs:37:18:37:27 | access to field Field |
| ExternalFlow.cs:42:13:42:16 | [post] this access [property Property] : Object | ExternalFlow.cs:43:18:43:21 | this access [property Property] : Object | | ExternalFlow.cs:42:13:42:16 | [post] this access [property Property] : Object | ExternalFlow.cs:43:18:43:21 | this access [property Property] : Object |
| ExternalFlow.cs:42:29:42:40 | object creation of type Object : Object | ExternalFlow.cs:42:13:42:16 | [post] this access [property Property] : Object | | ExternalFlow.cs:42:29:42:40 | object creation of type Object : Object | ExternalFlow.cs:42:13:42:16 | [post] this access [property Property] : Object |
@@ -48,10 +52,7 @@ edges
| ExternalFlow.cs:98:24:98:35 | object creation of type Object : Object | ExternalFlow.cs:98:13:98:14 | [post] access to local variable d1 [field Field] : Object | | ExternalFlow.cs:98:24:98:35 | object creation of type Object : Object | ExternalFlow.cs:98:13:98:14 | [post] access to local variable d1 [field Field] : Object |
| ExternalFlow.cs:100:20:100:20 | d : Object | ExternalFlow.cs:102:22:102:22 | access to parameter d | | ExternalFlow.cs:100:20:100:20 | d : Object | ExternalFlow.cs:102:22:102:22 | access to parameter d |
| ExternalFlow.cs:103:16:103:17 | access to local variable d1 [field Field] : Object | ExternalFlow.cs:100:20:100:20 | d : Object | | ExternalFlow.cs:103:16:103:17 | access to local variable d1 [field Field] : Object | ExternalFlow.cs:100:20:100:20 | d : Object |
| ExternalFlow.cs:103:16:103:17 | access to local variable d1 [field Field] : Object | ExternalFlow.cs:103:20:103:21 | [post] access to local variable d2 [field Field2] : Object |
| ExternalFlow.cs:103:20:103:21 | [post] access to local variable d2 [field Field2] : Object | ExternalFlow.cs:105:18:105:19 | access to local variable d2 [field Field2] : Object |
| ExternalFlow.cs:104:18:104:19 | access to local variable d1 [field Field] : Object | ExternalFlow.cs:104:18:104:25 | access to field Field | | ExternalFlow.cs:104:18:104:19 | access to local variable d1 [field Field] : Object | ExternalFlow.cs:104:18:104:25 | access to field Field |
| ExternalFlow.cs:105:18:105:19 | access to local variable d2 [field Field2] : Object | ExternalFlow.cs:105:18:105:26 | access to field Field2 |
nodes nodes
| ExternalFlow.cs:9:27:9:38 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | | ExternalFlow.cs:9:27:9:38 | object creation of type Object : Object | semmle.label | object creation of type Object : Object |
| ExternalFlow.cs:10:18:10:33 | call to method StepArgRes | semmle.label | call to method StepArgRes | | ExternalFlow.cs:10:18:10:33 | call to method StepArgRes | semmle.label | call to method StepArgRes |
@@ -69,8 +70,12 @@ nodes
| ExternalFlow.cs:30:26:30:37 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | | ExternalFlow.cs:30:26:30:37 | object creation of type Object : Object | semmle.label | object creation of type Object : Object |
| ExternalFlow.cs:31:18:31:21 | this access [field Field] : Object | semmle.label | this access [field Field] : Object | | ExternalFlow.cs:31:18:31:21 | this access [field Field] : Object | semmle.label | this access [field Field] : Object |
| ExternalFlow.cs:31:18:31:39 | call to method StepFieldGetter | semmle.label | call to method StepFieldGetter | | ExternalFlow.cs:31:18:31:39 | call to method StepFieldGetter | semmle.label | call to method StepFieldGetter |
| ExternalFlow.cs:36:13:36:16 | [post] this access [field Field] : Object | semmle.label | [post] this access [field Field] : Object | | ExternalFlow.cs:36:18:36:69 | access to field Field | semmle.label | access to field Field |
| ExternalFlow.cs:36:34:36:45 | object creation of type Object : Object | semmle.label | object creation of type Object : Object | | ExternalFlow.cs:36:19:36:62 | (...) ... [field Field] : Object | semmle.label | (...) ... [field Field] : Object |
| ExternalFlow.cs:36:22:36:25 | [post] this access [field Field] : Object | semmle.label | [post] this access [field Field] : Object |
| ExternalFlow.cs:36:22:36:55 | call to method StepFieldSetter [field Field2, field Field] : Object | semmle.label | call to method StepFieldSetter [field Field2, field Field] : Object |
| ExternalFlow.cs:36:22:36:62 | access to field Field2 [field Field] : Object | semmle.label | access to field Field2 [field Field] : Object |
| ExternalFlow.cs:36:43:36:54 | object creation of type Object : Object | semmle.label | object creation of type Object : Object |
| ExternalFlow.cs:37:18:37:21 | this access [field Field] : Object | semmle.label | this access [field Field] : Object | | ExternalFlow.cs:37:18:37:21 | this access [field Field] : Object | semmle.label | this access [field Field] : Object |
| ExternalFlow.cs:37:18:37:27 | access to field Field | semmle.label | access to field Field | | ExternalFlow.cs:37:18:37:27 | access to field Field | semmle.label | access to field Field |
| ExternalFlow.cs:42:13:42:16 | [post] this access [property Property] : Object | semmle.label | [post] this access [property Property] : Object | | ExternalFlow.cs:42:13:42:16 | [post] this access [property Property] : Object | semmle.label | [post] this access [property Property] : Object |
@@ -116,11 +121,8 @@ nodes
| ExternalFlow.cs:100:20:100:20 | d : Object | semmle.label | d : Object | | ExternalFlow.cs:100:20:100:20 | d : Object | semmle.label | d : Object |
| ExternalFlow.cs:102:22:102:22 | access to parameter d | semmle.label | access to parameter d | | ExternalFlow.cs:102:22:102:22 | access to parameter d | semmle.label | access to parameter d |
| ExternalFlow.cs:103:16:103:17 | access to local variable d1 [field Field] : Object | semmle.label | access to local variable d1 [field Field] : Object | | ExternalFlow.cs:103:16:103:17 | access to local variable d1 [field Field] : Object | semmle.label | access to local variable d1 [field Field] : Object |
| ExternalFlow.cs:103:20:103:21 | [post] access to local variable d2 [field Field2] : Object | semmle.label | [post] access to local variable d2 [field Field2] : Object |
| ExternalFlow.cs:104:18:104:19 | access to local variable d1 [field Field] : Object | semmle.label | access to local variable d1 [field Field] : Object | | ExternalFlow.cs:104:18:104:19 | access to local variable d1 [field Field] : Object | semmle.label | access to local variable d1 [field Field] : Object |
| ExternalFlow.cs:104:18:104:25 | access to field Field | semmle.label | access to field Field | | ExternalFlow.cs:104:18:104:25 | access to field Field | semmle.label | access to field Field |
| ExternalFlow.cs:105:18:105:19 | access to local variable d2 [field Field2] : Object | semmle.label | access to local variable d2 [field Field2] : Object |
| ExternalFlow.cs:105:18:105:26 | access to field Field2 | semmle.label | access to field Field2 |
subpaths subpaths
invalidModelRow invalidModelRow
#select #select
@@ -129,7 +131,8 @@ invalidModelRow
| ExternalFlow.cs:18:18:18:24 | access to local variable argOut1 | ExternalFlow.cs:16:30:16:41 | object creation of type Object : Object | ExternalFlow.cs:18:18:18:24 | access to local variable argOut1 | $@ | ExternalFlow.cs:16:30:16:41 | object creation of type Object : Object | object creation of type Object : Object | | ExternalFlow.cs:18:18:18:24 | access to local variable argOut1 | ExternalFlow.cs:16:30:16:41 | object creation of type Object : Object | ExternalFlow.cs:18:18:18:24 | access to local variable argOut1 | $@ | ExternalFlow.cs:16:30:16:41 | object creation of type Object : Object | object creation of type Object : Object |
| ExternalFlow.cs:25:18:25:21 | this access | ExternalFlow.cs:23:27:23:38 | object creation of type Object : Object | ExternalFlow.cs:25:18:25:21 | this access | $@ | ExternalFlow.cs:23:27:23:38 | object creation of type Object : Object | object creation of type Object : Object | | ExternalFlow.cs:25:18:25:21 | this access | ExternalFlow.cs:23:27:23:38 | object creation of type Object : Object | ExternalFlow.cs:25:18:25:21 | this access | $@ | ExternalFlow.cs:23:27:23:38 | object creation of type Object : Object | object creation of type Object : Object |
| ExternalFlow.cs:31:18:31:39 | call to method StepFieldGetter | ExternalFlow.cs:30:26:30:37 | object creation of type Object : Object | ExternalFlow.cs:31:18:31:39 | call to method StepFieldGetter | $@ | ExternalFlow.cs:30:26:30:37 | object creation of type Object : Object | object creation of type Object : Object | | ExternalFlow.cs:31:18:31:39 | call to method StepFieldGetter | ExternalFlow.cs:30:26:30:37 | object creation of type Object : Object | ExternalFlow.cs:31:18:31:39 | call to method StepFieldGetter | $@ | ExternalFlow.cs:30:26:30:37 | object creation of type Object : Object | object creation of type Object : Object |
| ExternalFlow.cs:37:18:37:27 | access to field Field | ExternalFlow.cs:36:34:36:45 | object creation of type Object : Object | ExternalFlow.cs:37:18:37:27 | access to field Field | $@ | ExternalFlow.cs:36:34:36:45 | object creation of type Object : Object | object creation of type Object : Object | | ExternalFlow.cs:36:18:36:69 | access to field Field | ExternalFlow.cs:36:43:36:54 | object creation of type Object : Object | ExternalFlow.cs:36:18:36:69 | access to field Field | $@ | ExternalFlow.cs:36:43:36:54 | object creation of type Object : Object | object creation of type Object : Object |
| ExternalFlow.cs:37:18:37:27 | access to field Field | ExternalFlow.cs:36:43:36:54 | object creation of type Object : Object | ExternalFlow.cs:37:18:37:27 | access to field Field | $@ | ExternalFlow.cs:36:43:36:54 | object creation of type Object : Object | object creation of type Object : Object |
| ExternalFlow.cs:43:18:43:42 | call to method StepPropertyGetter | ExternalFlow.cs:42:29:42:40 | object creation of type Object : Object | ExternalFlow.cs:43:18:43:42 | call to method StepPropertyGetter | $@ | ExternalFlow.cs:42:29:42:40 | object creation of type Object : Object | object creation of type Object : Object | | ExternalFlow.cs:43:18:43:42 | call to method StepPropertyGetter | ExternalFlow.cs:42:29:42:40 | object creation of type Object : Object | ExternalFlow.cs:43:18:43:42 | call to method StepPropertyGetter | $@ | ExternalFlow.cs:42:29:42:40 | object creation of type Object : Object | object creation of type Object : Object |
| ExternalFlow.cs:49:18:49:30 | access to property Property | ExternalFlow.cs:48:37:48:48 | object creation of type Object : Object | ExternalFlow.cs:49:18:49:30 | access to property Property | $@ | ExternalFlow.cs:48:37:48:48 | object creation of type Object : Object | object creation of type Object : Object | | ExternalFlow.cs:49:18:49:30 | access to property Property | ExternalFlow.cs:48:37:48:48 | object creation of type Object : Object | ExternalFlow.cs:49:18:49:30 | access to property Property | $@ | ExternalFlow.cs:48:37:48:48 | object creation of type Object : Object | object creation of type Object : Object |
| ExternalFlow.cs:55:18:55:41 | call to method StepElementGetter | ExternalFlow.cs:54:36:54:47 | object creation of type Object : Object | ExternalFlow.cs:55:18:55:41 | call to method StepElementGetter | $@ | ExternalFlow.cs:54:36:54:47 | object creation of type Object : Object | object creation of type Object : Object | | ExternalFlow.cs:55:18:55:41 | call to method StepElementGetter | ExternalFlow.cs:54:36:54:47 | object creation of type Object : Object | ExternalFlow.cs:55:18:55:41 | call to method StepElementGetter | $@ | ExternalFlow.cs:54:36:54:47 | object creation of type Object : Object | object creation of type Object : Object |
@@ -141,4 +144,3 @@ invalidModelRow
| ExternalFlow.cs:92:18:92:18 | (...) ... | ExternalFlow.cs:90:21:90:34 | object creation of type String : String | ExternalFlow.cs:92:18:92:18 | (...) ... | $@ | ExternalFlow.cs:90:21:90:34 | object creation of type String : String | object creation of type String : String | | ExternalFlow.cs:92:18:92:18 | (...) ... | ExternalFlow.cs:90:21:90:34 | object creation of type String : String | ExternalFlow.cs:92:18:92:18 | (...) ... | $@ | ExternalFlow.cs:90:21:90:34 | object creation of type String : String | object creation of type String : String |
| ExternalFlow.cs:102:22:102:22 | access to parameter d | ExternalFlow.cs:98:24:98:35 | object creation of type Object : Object | ExternalFlow.cs:102:22:102:22 | access to parameter d | $@ | ExternalFlow.cs:98:24:98:35 | object creation of type Object : Object | object creation of type Object : Object | | ExternalFlow.cs:102:22:102:22 | access to parameter d | ExternalFlow.cs:98:24:98:35 | object creation of type Object : Object | ExternalFlow.cs:102:22:102:22 | access to parameter d | $@ | ExternalFlow.cs:98:24:98:35 | object creation of type Object : Object | object creation of type Object : Object |
| ExternalFlow.cs:104:18:104:25 | access to field Field | ExternalFlow.cs:98:24:98:35 | object creation of type Object : Object | ExternalFlow.cs:104:18:104:25 | access to field Field | $@ | ExternalFlow.cs:98:24:98:35 | object creation of type Object : Object | object creation of type Object : Object | | ExternalFlow.cs:104:18:104:25 | access to field Field | ExternalFlow.cs:98:24:98:35 | object creation of type Object : Object | ExternalFlow.cs:104:18:104:25 | access to field Field | $@ | ExternalFlow.cs:98:24:98:35 | object creation of type Object : Object | object creation of type Object : Object |
| ExternalFlow.cs:105:18:105:26 | access to field Field2 | ExternalFlow.cs:98:24:98:35 | object creation of type Object : Object | ExternalFlow.cs:105:18:105:26 | access to field Field2 | $@ | ExternalFlow.cs:98:24:98:35 | object creation of type Object : Object | object creation of type Object : Object |

View File

@@ -17,6 +17,7 @@ class SummaryModelTest extends SummaryModelCsv {
"My.Qltest;D;false;StepArgQual;(System.Object);;Argument[0];Argument[-1];taint", "My.Qltest;D;false;StepArgQual;(System.Object);;Argument[0];Argument[-1];taint",
"My.Qltest;D;false;StepFieldGetter;();;Field[My.Qltest.D.Field] of Argument[-1];ReturnValue;value", "My.Qltest;D;false;StepFieldGetter;();;Field[My.Qltest.D.Field] of Argument[-1];ReturnValue;value",
"My.Qltest;D;false;StepFieldSetter;(System.Object);;Argument[0];Field[My.Qltest.D.Field] of Argument[-1];value", "My.Qltest;D;false;StepFieldSetter;(System.Object);;Argument[0];Field[My.Qltest.D.Field] of Argument[-1];value",
"My.Qltest;D;false;StepFieldSetter;(System.Object);;Argument[-1];Field[My.Qltest.D.Field2] of ReturnValue;value",
"My.Qltest;D;false;StepPropertyGetter;();;Property[My.Qltest.D.Property] of Argument[-1];ReturnValue;value", "My.Qltest;D;false;StepPropertyGetter;();;Property[My.Qltest.D.Property] of Argument[-1];ReturnValue;value",
"My.Qltest;D;false;StepPropertySetter;(System.Object);;Argument[0];Property[My.Qltest.D.Property] of Argument[-1];value", "My.Qltest;D;false;StepPropertySetter;(System.Object);;Argument[0];Property[My.Qltest.D.Property] of Argument[-1];value",
"My.Qltest;D;false;StepElementGetter;();;Element of Argument[-1];ReturnValue;value", "My.Qltest;D;false;StepElementGetter;();;Element of Argument[-1];ReturnValue;value",

View File

@@ -403,6 +403,7 @@
| LocalDataFlow.cs:235:9:235:14 | access to local variable sink36 | LocalDataFlow.cs:235:9:235:33 | call to method AppendLine | | LocalDataFlow.cs:235:9:235:14 | access to local variable sink36 | LocalDataFlow.cs:235:9:235:33 | call to method AppendLine |
| LocalDataFlow.cs:235:9:235:14 | access to local variable sink36 | LocalDataFlow.cs:236:15:236:20 | access to local variable sink36 | | LocalDataFlow.cs:235:9:235:14 | access to local variable sink36 | LocalDataFlow.cs:236:15:236:20 | access to local variable sink36 |
| LocalDataFlow.cs:235:27:235:32 | access to local variable sink35 | LocalDataFlow.cs:235:9:235:14 | [post] access to local variable sink36 | | LocalDataFlow.cs:235:27:235:32 | access to local variable sink35 | LocalDataFlow.cs:235:9:235:14 | [post] access to local variable sink36 |
| LocalDataFlow.cs:235:27:235:32 | access to local variable sink35 | LocalDataFlow.cs:235:9:235:33 | call to method AppendLine |
| LocalDataFlow.cs:239:13:239:51 | SSA def(nonSink10) | LocalDataFlow.cs:240:15:240:23 | access to local variable nonSink10 | | LocalDataFlow.cs:239:13:239:51 | SSA def(nonSink10) | LocalDataFlow.cs:240:15:240:23 | access to local variable nonSink10 |
| LocalDataFlow.cs:239:25:239:51 | object creation of type StringBuilder | LocalDataFlow.cs:239:13:239:51 | SSA def(nonSink10) | | LocalDataFlow.cs:239:25:239:51 | object creation of type StringBuilder | LocalDataFlow.cs:239:13:239:51 | SSA def(nonSink10) |
| LocalDataFlow.cs:239:43:239:50 | access to local variable nonSink0 | LocalDataFlow.cs:239:25:239:51 | object creation of type StringBuilder | | LocalDataFlow.cs:239:43:239:50 | access to local variable nonSink0 | LocalDataFlow.cs:239:25:239:51 | object creation of type StringBuilder |
@@ -419,6 +420,7 @@
| LocalDataFlow.cs:243:9:243:17 | access to local variable nonSink10 | LocalDataFlow.cs:243:9:243:38 | call to method AppendLine | | LocalDataFlow.cs:243:9:243:17 | access to local variable nonSink10 | LocalDataFlow.cs:243:9:243:38 | call to method AppendLine |
| LocalDataFlow.cs:243:9:243:17 | access to local variable nonSink10 | LocalDataFlow.cs:244:15:244:23 | access to local variable nonSink10 | | LocalDataFlow.cs:243:9:243:17 | access to local variable nonSink10 | LocalDataFlow.cs:244:15:244:23 | access to local variable nonSink10 |
| LocalDataFlow.cs:243:30:243:37 | access to local variable nonSink0 | LocalDataFlow.cs:243:9:243:17 | [post] access to local variable nonSink10 | | LocalDataFlow.cs:243:30:243:37 | access to local variable nonSink0 | LocalDataFlow.cs:243:9:243:17 | [post] access to local variable nonSink10 |
| LocalDataFlow.cs:243:30:243:37 | access to local variable nonSink0 | LocalDataFlow.cs:243:9:243:38 | call to method AppendLine |
| LocalDataFlow.cs:247:13:247:52 | SSA def(taintedDataContract) | LocalDataFlow.cs:248:22:248:40 | access to local variable taintedDataContract | | LocalDataFlow.cs:247:13:247:52 | SSA def(taintedDataContract) | LocalDataFlow.cs:248:22:248:40 | access to local variable taintedDataContract |
| LocalDataFlow.cs:247:13:247:52 | SSA qualifier def(taintedDataContract.AList) | LocalDataFlow.cs:250:22:250:46 | access to property AList | | LocalDataFlow.cs:247:13:247:52 | SSA qualifier def(taintedDataContract.AList) | LocalDataFlow.cs:250:22:250:46 | access to property AList |
| LocalDataFlow.cs:247:13:247:52 | SSA qualifier def(taintedDataContract.AString) | LocalDataFlow.cs:248:22:248:48 | access to property AString | | LocalDataFlow.cs:247:13:247:52 | SSA qualifier def(taintedDataContract.AString) | LocalDataFlow.cs:248:22:248:48 | access to property AString |

View File

@@ -20,7 +20,10 @@ setup, as outlined in the steps below.
If you use Linux, Windows, or macOS version 10.14 ("Mojave") or earlier, simply If you use Linux, Windows, or macOS version 10.14 ("Mojave") or earlier, simply
follow the steps below. For macOS version 10.15 ("Catalina") or newer, steps 1 follow the steps below. For macOS version 10.15 ("Catalina") or newer, steps 1
and 4 are slightly different---for further details, see the sections labeled and 4 are slightly different---for further details, see the sections labeled
**Information for macOS "Catalina" (or newer) users**. **Information for macOS "Catalina" (or newer) users**. If you are using macOS
on Apple Silicon (e.g. Apple M1), ensure that the `Xcode command-line developer
tools <https://developer.apple.com/downloads/index.action>`__ and `Rosetta 2
<https://support.apple.com/en-us/HT211861>`__ are installed.
For information about installing the CodeQL CLI in a CI system to create results For information about installing the CodeQL CLI in a CI system to create results
to display in GitHub as code scanning alerts, see to display in GitHub as code scanning alerts, see

View File

@@ -0,0 +1,2 @@
lgtm,codescanning
* The predicate `Method.overrides(Method)` was accidentally transitive. This has been fixed. This fix also affects `Method.overridesOrInstantiates(Method)` and `Method.getASourceOverriddenMethod()`.

View File

@@ -27,7 +27,7 @@ jakarta.ws.rs.container,,9,,,,,,,,,,,,,,,,,,,,,,9,,
jakarta.ws.rs.core,2,,149,,,,,,,,,,,,,,,,2,,,,,,94,55 jakarta.ws.rs.core,2,,149,,,,,,,,,,,,,,,,2,,,,,,94,55
java.beans,,,1,,,,,,,,,,,,,,,,,,,,,,1, java.beans,,,1,,,,,,,,,,,,,,,,,,,,,,1,
java.io,3,,31,,3,,,,,,,,,,,,,,,,,,,,30,1 java.io,3,,31,,3,,,,,,,,,,,,,,,,,,,,30,1
java.lang,,,51,,,,,,,,,,,,,,,,,,,,,,41,10 java.lang,,,52,,,,,,,,,,,,,,,,,,,,,,42,10
java.net,10,3,7,,,,,,,,,,,,10,,,,,,,,,3,7, java.net,10,3,7,,,,,,,,,,,,10,,,,,,,,,3,7,
java.nio,10,,4,,10,,,,,,,,,,,,,,,,,,,,4, java.nio,10,,4,,10,,,,,,,,,,,,,,,,,,,,4,
java.sql,7,,,,,,,,,,,,,,,,7,,,,,,,,, java.sql,7,,,,,,,,,,,,,,,,7,,,,,,,,,
1 package sink source summary sink:bean-validation sink:create-file sink:groovy sink:header-splitting sink:information-leak sink:intent-start sink:jexl sink:jndi-injection sink:ldap sink:mvel sink:ognl-injection sink:open-url sink:set-hostname-verifier sink:sql sink:url-open-stream sink:url-redirect sink:xpath sink:xslt sink:xss source:contentprovider source:remote summary:taint summary:value
27 jakarta.ws.rs.core 2 149 2 94 55
28 java.beans 1 1
29 java.io 3 31 3 30 1
30 java.lang 51 52 41 42 10
31 java.net 10 3 7 10 3 7
32 java.nio 10 4 10 4
33 java.sql 7 7

View File

@@ -15,9 +15,9 @@ Java framework & library support
`Apache HttpComponents <https://hc.apache.org/>`_,"``org.apache.hc.core5.*``, ``org.apache.http``",5,136,28,,,3,,,,25 `Apache HttpComponents <https://hc.apache.org/>`_,"``org.apache.hc.core5.*``, ``org.apache.http``",5,136,28,,,3,,,,25
`Google Guava <https://guava.dev/>`_,``com.google.common.*``,,728,6,,6,,,,, `Google Guava <https://guava.dev/>`_,``com.google.common.*``,,728,6,,6,,,,,
`JSON-java <https://github.com/stleary/JSON-java>`_,``org.json``,,236,,,,,,,, `JSON-java <https://github.com/stleary/JSON-java>`_,``org.json``,,236,,,,,,,,
Java Standard Library,``java.*``,3,523,30,13,,,7,,,10 Java Standard Library,``java.*``,3,524,30,13,,,7,,,10
Java extensions,"``javax.*``, ``jakarta.*``",54,552,32,,,4,,1,1,2 Java extensions,"``javax.*``, ``jakarta.*``",54,552,32,,,4,,1,1,2
`Spring <https://spring.io/>`_,``org.springframework.*``,29,469,91,,,,19,14,,29 `Spring <https://spring.io/>`_,``org.springframework.*``,29,469,91,,,,19,14,,29
Others,"``cn.hutool.core.codec``, ``com.esotericsoftware.kryo.io``, ``com.esotericsoftware.kryo5.io``, ``com.fasterxml.jackson.core``, ``com.fasterxml.jackson.databind``, ``com.opensymphony.xwork2.ognl``, ``com.unboundid.ldap.sdk``, ``flexjson``, ``groovy.lang``, ``groovy.util``, ``jodd.json``, ``net.sf.saxon.s9api``, ``ognl``, ``org.apache.commons.codec``, ``org.apache.commons.jexl2``, ``org.apache.commons.jexl3``, ``org.apache.commons.ognl``, ``org.apache.directory.ldap.client.api``, ``org.apache.ibatis.jdbc``, ``org.apache.shiro.codec``, ``org.apache.shiro.jndi``, ``org.codehaus.groovy.control``, ``org.dom4j``, ``org.hibernate``, ``org.jooq``, ``org.mvel2``, ``org.xml.sax``, ``org.xmlpull.v1``, ``play.mvc``, ``ratpack.core.form``, ``ratpack.core.handling``, ``ratpack.core.http``, ``ratpack.exec``, ``ratpack.form``, ``ratpack.func``, ``ratpack.handling``, ``ratpack.http``, ``ratpack.util``",39,99,151,,,,14,18,, Others,"``cn.hutool.core.codec``, ``com.esotericsoftware.kryo.io``, ``com.esotericsoftware.kryo5.io``, ``com.fasterxml.jackson.core``, ``com.fasterxml.jackson.databind``, ``com.opensymphony.xwork2.ognl``, ``com.unboundid.ldap.sdk``, ``flexjson``, ``groovy.lang``, ``groovy.util``, ``jodd.json``, ``net.sf.saxon.s9api``, ``ognl``, ``org.apache.commons.codec``, ``org.apache.commons.jexl2``, ``org.apache.commons.jexl3``, ``org.apache.commons.ognl``, ``org.apache.directory.ldap.client.api``, ``org.apache.ibatis.jdbc``, ``org.apache.shiro.codec``, ``org.apache.shiro.jndi``, ``org.codehaus.groovy.control``, ``org.dom4j``, ``org.hibernate``, ``org.jooq``, ``org.mvel2``, ``org.xml.sax``, ``org.xmlpull.v1``, ``play.mvc``, ``ratpack.core.form``, ``ratpack.core.handling``, ``ratpack.core.http``, ``ratpack.exec``, ``ratpack.form``, ``ratpack.func``, ``ratpack.handling``, ``ratpack.http``, ``ratpack.util``",39,99,151,,,,14,18,,
Totals,,175,5368,431,13,6,10,107,33,1,66 Totals,,175,5369,431,13,6,10,107,33,1,66

View File

@@ -285,7 +285,20 @@ private predicate overrides(Method m1, Method m2) {
or or
m2.isProtected() m2.isProtected()
or or
m2.isPackageProtected() and t1.getPackage() = t2.getPackage() m2.isPackageProtected() and
pragma[only_bind_out](t1.getPackage()) = pragma[only_bind_out](t2.getPackage())
)
}
pragma[nomagic]
private predicate overridesCandidateType(RefType tsup, string sig, RefType t, Method m) {
virtualMethodWithSignature(sig, t, m) and
t.extendsOrImplements(tsup)
or
exists(RefType mid |
overridesCandidateType(mid, sig, t, m) and
mid.extendsOrImplements(tsup) and
not virtualMethodWithSignature(sig, mid, _)
) )
} }
@@ -294,11 +307,10 @@ private predicate overrides(Method m1, Method m2) {
* ignoring any access modifiers. Additionally, this predicate binds * ignoring any access modifiers. Additionally, this predicate binds
* `t1` to the type declaring `m1` and `t2` to the type declaring `m2`. * `t1` to the type declaring `m1` and `t2` to the type declaring `m2`.
*/ */
pragma[noopt] cached
predicate overridesIgnoringAccess(Method m1, RefType t1, Method m2, RefType t2) { predicate overridesIgnoringAccess(Method m1, RefType t1, Method m2, RefType t2) {
exists(string sig | exists(string sig |
virtualMethodWithSignature(sig, t1, m1) and overridesCandidateType(t2, sig, t1, m1) and
t1.extendsOrImplements+(t2) and
virtualMethodWithSignature(sig, t2, m2) virtualMethodWithSignature(sig, t2, m2)
) )
} }

View File

@@ -31,7 +31,7 @@ predicate hasSubtype(RefType t, Type sub) {
arraySubtype(t, sub) and t != sub arraySubtype(t, sub) and t != sub
or or
// Type parameter containment for parameterized types. // Type parameter containment for parameterized types.
parContainmentSubtype(t, sub) and t != sub parContainmentSubtype(t, sub)
or or
// Type variables are subtypes of their upper bounds. // Type variables are subtypes of their upper bounds.
typeVarSubtypeBound(t, sub) and t != sub typeVarSubtypeBound(t, sub) and t != sub
@@ -59,19 +59,23 @@ private predicate arraySubtype(Array sup, Array sub) {
* ) * )
* ``` * ```
* For performance several transformations are made. First, the `forex` is * For performance several transformations are made. First, the `forex` is
* written as a loop where `typeArgumentsContain(_, pt, psub, n)` encode that * written as a loop where `typePrefixContains(ppt, ppsub)` encode that
* the `forex` holds for `i in [0..n]`. Second, the relation is split into two * `ppt` and `ppsub` are prefixes of `pt` and `ptsub` and that
* cases depending on whether `pt.getNumberOfTypeArguments()` is 1 or 2+, as * the `forex` holds for `i in [0..n-1]` where `n` is the length of the prefixes.
* this allows us to unroll the loop and collapse the first two iterations. The * Second, the recursive case that determines containment of length `n+1`
* base case for `typeArgumentsContain` is therefore `n=1` and this allows an * prefixes is split into three cases depending on whether there is
* improved join order implemented by `contains01`. * non-reflexive type parameter containment:
* - only in the length `n` prefix,
* - only in the `n`th position,
* - both in the length `n` prefix and the `n`th position.
*/ */
private predicate parContainmentSubtype(ParameterizedType pt, ParameterizedType psub) { private predicate parContainmentSubtype(ParameterizedType pt, ParameterizedType psub) {
pt != psub and exists(ParameterizedPrefix ppt, ParameterizedPrefix ppsub |
typeArgumentsContain(_, pt, psub, pt.getNumberOfTypeArguments() - 1) typePrefixContains(ppt, ppsub) and
or ppt.equals(pt) and
typeArgumentsContain0(_, pt, psub) ppsub.equals(psub)
)
} }
/** /**
@@ -94,100 +98,116 @@ private RefType parameterisationTypeArgumentVarianceCand(
varianceCandidate(t) varianceCandidate(t)
} }
/** private newtype TParameterizedPrefix =
* Holds if every type argument of `s` (up to `n` with `n >= 1`) contains the TGenericType(GenericType g) or
* corresponding type argument of `t`. Both `s` and `t` are constrained to TTypeParam(ParameterizedPrefix pp, RefType t) { prefixMatches(pp, t, _, _) }
* being parameterizations of `g`.
*/ /** Holds if `pp` is a length `n` prefix of `pt`. */
pragma[nomagic] private predicate prefixMatches(ParameterizedPrefix pp, ParameterizedType pt, int n) {
private predicate typeArgumentsContain( pp = TGenericType(pt.getGenericType()) and n = 0
GenericType g, ParameterizedType s, ParameterizedType t, int n
) {
contains01(g, s, t) and n = 1
or or
contains(g, s, t, n) and exists(ParameterizedPrefix pp0, RefType t |
typeArgumentsContain(g, s, t, n - 1) pp = TTypeParam(pp0, t) and prefixMatches(pp0, t, pt, n - 1)
}
private predicate typeArgumentsContain0(
GenericType g, ParameterizedType sParm, ParameterizedType tParm
) {
exists(RefType s, RefType t |
containsAux0(g, tParm, s, t) and
s = parameterisationTypeArgument(g, sParm, 0) and
s != t
) )
} }
/** /**
* Holds if the `n`-th type argument of `sParm` contain the `n`-th type * Holds if `pp` is a length `n` prefix of `pt` and `t` is the `n`th type
* argument of `tParm` for both `n = 0` and `n = 1`, where both `sParm` and * argument of `pt`.
* `tParm` are parameterizations of the same generic type `g`.
*
* This is equivalent to
* ```
* contains(g, sParm, tParm, 0) and
* contains(g, sParm, tParm, 1)
* ```
* except `contains` is restricted to only include `n >= 2`.
*/ */
private predicate contains01(GenericType g, ParameterizedType sParm, ParameterizedType tParm) { private predicate prefixMatches(ParameterizedPrefix pp, RefType t, ParameterizedType pt, int n) {
exists(RefType s0, RefType t0, RefType s1, RefType t1 | prefixMatches(pp, pt, n) and
contains01Aux0(g, tParm, s0, t0, t1) and t = pt.getTypeArgument(n)
contains01Aux1(g, sParm, s0, s1, t1)
)
}
pragma[nomagic]
private predicate contains01Aux0(
GenericType g, ParameterizedType tParm, RefType s0, RefType t0, RefType t1
) {
typeArgumentContains(g, s0, t0, 0) and
t0 = parameterisationTypeArgument(g, tParm, 0) and
t1 = parameterisationTypeArgument(g, tParm, 1)
}
pragma[nomagic]
private predicate contains01Aux1(
GenericType g, ParameterizedType sParm, RefType s0, RefType s1, RefType t1
) {
typeArgumentContains(g, s1, t1, 1) and
s0 = parameterisationTypeArgumentVarianceCand(g, sParm, 0) and
s1 = parameterisationTypeArgumentVarianceCand(g, sParm, 1)
}
pragma[nomagic]
private predicate containsAux0(GenericType g, ParameterizedType tParm, RefType s, RefType t) {
typeArgumentContains(g, s, t, 0) and
t = parameterisationTypeArgument(g, tParm, 0) and
g.getNumberOfTypeParameters() = 1
} }
/** /**
* Holds if the `n`-th type argument of `sParm` contain the `n`-th type * A prefix of a `ParameterizedType`. This encodes the corresponding
* argument of `tParm`, where both `sParm` and `tParm` are parameterizations of * `GenericType` and the first `n` type arguments where `n` is the prefix
* the same generic type `g`. The index `n` is restricted to `n >= 2`, the * length.
* cases `n < 2` are handled by `contains01`.
*
* See JLS 4.5.1, Type Arguments of Parameterized Types.
*/ */
private predicate contains(GenericType g, ParameterizedType sParm, ParameterizedType tParm, int n) { private class ParameterizedPrefix extends TParameterizedPrefix {
exists(RefType s, RefType t | string toString() { result = "ParameterizedPrefix" }
containsAux(g, tParm, n, s, t) and
s = parameterisationTypeArgumentVarianceCand(g, sParm, n) predicate equals(ParameterizedType pt) { prefixMatches(this, pt, pt.getNumberOfTypeArguments()) }
/** Holds if this prefix has length `n`, applies to `g`, and equals `TTypeParam(pp, t)`. */
predicate split(GenericType g, ParameterizedPrefix pp, RefType t, int n) {
this = TTypeParam(pp, t) and
(
pp = TGenericType(g) and n = 0
or
pp.split(g, _, _, n - 1)
)
}
}
/**
* Holds if every type argument of `pps` contains the corresponding type
* argument of `ppt`. Both `pps` and `ppt` are constrained to be equal-length
* prefixes of parameterizations of the same `GenericType`.
*/
pragma[nomagic]
private predicate typePrefixContains(ParameterizedPrefix pps, ParameterizedPrefix ppt) {
// Let `pps = TTypeParam(pps0, s)` and `ppt = TTypeParam(ppt0, t)`.
// Case 1: pps0 = ppt0 and typeArgumentContains(_, s, t, _)
typePrefixContains_base(pps, ppt)
or
// Case 2: typePrefixContains(pps0, ppt0) and s = t
typePrefixContains_ext_eq(pps, ppt)
or
// Case 3: typePrefixContains(pps0, ppt0) and typeArgumentContains(_, s, t, _)
typePrefixContains_ext_neq(pps, ppt)
}
private predicate typePrefixContains_base(ParameterizedPrefix pps, ParameterizedPrefix ppt) {
exists(ParameterizedPrefix pp, RefType s |
pps = TTypeParam(pp, s) and
typePrefixContainsAux2(ppt, pp, s)
)
}
private predicate typePrefixContains_ext_eq(ParameterizedPrefix pps, ParameterizedPrefix ppt) {
exists(ParameterizedPrefix pps0, ParameterizedPrefix ppt0, RefType t |
typePrefixContains(pragma[only_bind_into](pps0), pragma[only_bind_into](ppt0)) and
pps = TTypeParam(pragma[only_bind_into](pps0), t) and
ppt = TTypeParam(ppt0, t)
)
}
private predicate typePrefixContains_ext_neq(ParameterizedPrefix pps, ParameterizedPrefix ppt) {
exists(ParameterizedPrefix ppt0, RefType s |
typePrefixContainsAux1(pps, ppt0, s) and
typePrefixContainsAux2(ppt, ppt0, s)
) )
} }
pragma[nomagic] pragma[nomagic]
private predicate containsAux(GenericType g, ParameterizedType tParm, int n, RefType s, RefType t) { private predicate typePrefixContainsAux1(
typeArgumentContains(g, s, t, n) and ParameterizedPrefix pps, ParameterizedPrefix ppt0, RefType s
t = parameterisationTypeArgument(g, tParm, n) and ) {
n >= 2 exists(ParameterizedPrefix pps0 |
typePrefixContains(pps0, ppt0) and
pps = TTypeParam(pps0, s) and
s instanceof Wildcard // manual magic, implied by `typeArgumentContains(_, s, t, _)`
)
}
pragma[nomagic]
private predicate typePrefixContainsAux2(
ParameterizedPrefix ppt, ParameterizedPrefix ppt0, RefType s
) {
exists(GenericType g, int n, RefType t |
// Implies `ppt = TTypeParam(ppt0, t)`
ppt.split(g, ppt0, t, n) and
typeArgumentContains(g, s, t, n)
)
} }
/** /**
* Holds if the type argument `s` contains the type argument `t`, where both * Holds if the type argument `s` contains the type argument `t`, where both
* type arguments occur as index `n` in an instantiation of `g`. * type arguments occur as index `n` in an instantiation of `g`.
*
* The case `s = t` is not included.
*/ */
pragma[noinline] pragma[noinline]
private predicate typeArgumentContains(GenericType g, RefType s, RefType t, int n) { private predicate typeArgumentContains(GenericType g, RefType s, RefType t, int n) {
@@ -205,18 +225,18 @@ private predicate typeArgumentContainsAux2(GenericType g, RefType s, RefType t,
* Holds if the type argument `s` contains the type argument `t`, where both * Holds if the type argument `s` contains the type argument `t`, where both
* type arguments occur as index `n` in some parameterized types. * type arguments occur as index `n` in some parameterized types.
* *
* The case `s = t` is not included.
*
* See JLS 4.5.1, Type Arguments of Parameterized Types. * See JLS 4.5.1, Type Arguments of Parameterized Types.
*/ */
private predicate typeArgumentContainsAux1(RefType s, RefType t, int n) { private predicate typeArgumentContainsAux1(RefType s, RefType t, int n) {
exists(int i | s = parameterisationTypeArgumentVarianceCand(_, _, pragma[only_bind_into](n)) and
s = parameterisationTypeArgumentVarianceCand(_, _, i) and t = parameterisationTypeArgument(_, _, pragma[only_bind_into](n)) and
t = parameterisationTypeArgument(_, _, n) and s != t and
i <= n and (
n <= i
|
exists(RefType tUpperBound | tUpperBound = t.(Wildcard).getUpperBound().getType() | exists(RefType tUpperBound | tUpperBound = t.(Wildcard).getUpperBound().getType() |
// ? extends T <= ? extends S if T <: S // ? extends T <= ? extends S if T <: S
hasSubtypeStar(s.(Wildcard).getUpperBound().getType(), tUpperBound) hasSubtypeStar1(s.(Wildcard).getUpperBound().getType(), tUpperBound)
or or
// ? extends T <= ? // ? extends T <= ?
s.(Wildcard).isUnconstrained() s.(Wildcard).isUnconstrained()
@@ -224,7 +244,7 @@ private predicate typeArgumentContainsAux1(RefType s, RefType t, int n) {
or or
exists(RefType tLowerBound | tLowerBound = t.(Wildcard).getLowerBound().getType() | exists(RefType tLowerBound | tLowerBound = t.(Wildcard).getLowerBound().getType() |
// ? super T <= ? super S if s <: T // ? super T <= ? super S if s <: T
hasSubtypeStar(tLowerBound, s.(Wildcard).getLowerBound().getType()) hasSubtypeStar2(tLowerBound, s.(Wildcard).getLowerBound().getType())
or or
// ? super T <= ? // ? super T <= ?
s.(Wildcard).isUnconstrained() s.(Wildcard).isUnconstrained()
@@ -233,14 +253,14 @@ private predicate typeArgumentContainsAux1(RefType s, RefType t, int n) {
wildcardExtendsObject(s) wildcardExtendsObject(s)
) )
or or
// T <= T
s = t
or
// T <= ? extends T // T <= ? extends T
hasSubtypeStar(s.(Wildcard).getUpperBound().getType(), t) hasSubtypeStar1(s.(Wildcard).getUpperBound().getType(), t)
or or
// T <= ? super T // T <= ? super T
hasSubtypeStar(t, s.(Wildcard).getLowerBound().getType()) hasSubtypeStar2(t, s.(Wildcard).getLowerBound().getType())
// or
// T <= T
// but this case is handled directly in `typePrefixContains`
) )
} }
@@ -249,12 +269,38 @@ private predicate wildcardExtendsObject(Wildcard wc) {
wc.getUpperBound().getType() instanceof TypeObject wc.getUpperBound().getType() instanceof TypeObject
} }
private predicate hasSubtypeStar(RefType t, RefType sub) { // manual magic for `hasSubtypeStar1`
sub = t private predicate getAWildcardUpperBound(RefType t) {
t = any(Wildcard w).getUpperBound().getType()
}
// manual magic for `hasSubtypeStar2`
private predicate getAWildcardLowerBound(RefType t) {
t = any(Wildcard w).getLowerBound().getType()
}
/**
* Holds if `hasSubtype*(t, sub)`, but manual-magic'ed with `getAWildcardUpperBound(t)`.
*/
pragma[nomagic]
private predicate hasSubtypeStar1(RefType t, RefType sub) {
sub = t and getAWildcardUpperBound(t)
or or
hasSubtype(t, sub) hasSubtype(t, sub) and getAWildcardUpperBound(t)
or or
exists(RefType mid | hasSubtypeStar(t, mid) and hasSubtype(mid, sub)) exists(RefType mid | hasSubtypeStar1(t, mid) and hasSubtype(mid, sub))
}
/**
* Holds if `hasSubtype*(t, sub)`, but manual-magic'ed with `getAWildcardLowerBound(sub)`.
*/
pragma[nomagic]
private predicate hasSubtypeStar2(RefType t, RefType sub) {
sub = t and getAWildcardLowerBound(sub)
or
hasSubtype(t, sub) and getAWildcardLowerBound(sub)
or
exists(RefType mid | hasSubtype(t, mid) and hasSubtypeStar2(mid, sub))
} }
/** Holds if type `t` declares member `m`. */ /** Holds if type `t` declares member `m`. */

View File

@@ -85,6 +85,9 @@ module Public {
/** Holds if this stack contains summary component `c`. */ /** Holds if this stack contains summary component `c`. */
predicate contains(SummaryComponent c) { c = this.drop(_).head() } predicate contains(SummaryComponent c) { c = this.drop(_).head() }
/** Gets the bottom element of this stack. */
SummaryComponent bottom() { result = this.drop(this.length() - 1).head() }
/** Gets a textual representation of this stack. */ /** Gets a textual representation of this stack. */
string toString() { string toString() {
exists(SummaryComponent head, SummaryComponentStack tail | exists(SummaryComponent head, SummaryComponentStack tail |
@@ -197,6 +200,8 @@ module Private {
or or
tail.(RequiredSummaryComponentStack).required(TParameterSummaryComponent(_)) and tail.(RequiredSummaryComponentStack).required(TParameterSummaryComponent(_)) and
head = thisParam() head = thisParam()
or
derivedFluentFlowPush(_, _, _, head, tail, _)
} }
pragma[nomagic] pragma[nomagic]
@@ -210,7 +215,7 @@ module Private {
c.propagatesFlow(output, input, preservesValue) and c.propagatesFlow(output, input, preservesValue) and
preservesValue = true and preservesValue = true and
isCallbackParameter(input) and isCallbackParameter(input) and
isContentOfArgument(output) isContentOfArgument(output, _)
or or
// flow from the receiver of a callback into the instance-parameter // flow from the receiver of a callback into the instance-parameter
exists(SummaryComponentStack s, SummaryComponentStack callbackRef | exists(SummaryComponentStack s, SummaryComponentStack callbackRef |
@@ -222,16 +227,81 @@ module Private {
output = TConsSummaryComponentStack(thisParam(), input) and output = TConsSummaryComponentStack(thisParam(), input) and
preservesValue = true preservesValue = true
) )
or
exists(SummaryComponentStack arg, SummaryComponentStack return |
derivedFluentFlow(c, input, arg, return, preservesValue)
|
arg.length() = 1 and
output = return
or
exists(SummaryComponent head, SummaryComponentStack tail |
derivedFluentFlowPush(c, input, arg, head, tail, 0) and
output = SummaryComponentStack::push(head, tail)
)
)
or
// Chain together summaries where values get passed into callbacks along the way
exists(SummaryComponentStack mid, boolean preservesValue1, boolean preservesValue2 |
c.propagatesFlow(input, mid, preservesValue1) and
c.propagatesFlow(mid, output, preservesValue2) and
mid.drop(mid.length() - 2) =
SummaryComponentStack::push(TParameterSummaryComponent(_),
SummaryComponentStack::singleton(TArgumentSummaryComponent(_))) and
preservesValue = preservesValue1.booleanAnd(preservesValue2)
)
}
/**
* Holds if `c` has a flow summary from `input` to `arg`, where `arg`
* writes to (contents of) the `i`th argument, and `c` has a
* value-preserving flow summary from the `i`th argument to a return value
* (`return`).
*
* In such a case, we derive flow from `input` to (contents of) the return
* value.
*
* As an example, this simplifies modeling of fluent methods:
* for `StringBuilder.append(x)` with a specified value flow from qualifier to
* return value and taint flow from argument 0 to the qualifier, then this
* allows us to infer taint flow from argument 0 to the return value.
*/
pragma[nomagic]
private predicate derivedFluentFlow(
SummarizedCallable c, SummaryComponentStack input, SummaryComponentStack arg,
SummaryComponentStack return, boolean preservesValue
) {
exists(int i |
summary(c, input, arg, preservesValue) and
isContentOfArgument(arg, i) and
summary(c, SummaryComponentStack::singleton(TArgumentSummaryComponent(i)), return, true) and
return.bottom() = TReturnSummaryComponent(_)
)
}
pragma[nomagic]
private predicate derivedFluentFlowPush(
SummarizedCallable c, SummaryComponentStack input, SummaryComponentStack arg,
SummaryComponent head, SummaryComponentStack tail, int i
) {
derivedFluentFlow(c, input, arg, tail, _) and
head = arg.drop(i).head() and
i = arg.length() - 2
or
exists(SummaryComponent head0, SummaryComponentStack tail0 |
derivedFluentFlowPush(c, input, arg, head0, tail0, i + 1) and
head = arg.drop(i).head() and
tail = SummaryComponentStack::push(head0, tail0)
)
} }
private predicate isCallbackParameter(SummaryComponentStack s) { private predicate isCallbackParameter(SummaryComponentStack s) {
s.head() = TParameterSummaryComponent(_) and exists(s.tail()) s.head() = TParameterSummaryComponent(_) and exists(s.tail())
} }
private predicate isContentOfArgument(SummaryComponentStack s) { private predicate isContentOfArgument(SummaryComponentStack s, int i) {
s.head() = TContentSummaryComponent(_) and isContentOfArgument(s.tail()) s.head() = TContentSummaryComponent(_) and isContentOfArgument(s.tail(), i)
or or
s = TSingletonSummaryComponentStack(TArgumentSummaryComponent(_)) s = TSingletonSummaryComponentStack(TArgumentSummaryComponent(i))
} }
private predicate outputState(SummarizedCallable c, SummaryComponentStack s) { private predicate outputState(SummarizedCallable c, SummaryComponentStack s) {
@@ -508,9 +578,14 @@ module Private {
* node, and back out to `p`. * node, and back out to `p`.
*/ */
predicate summaryAllowParameterReturnInSelf(ParamNode p) { predicate summaryAllowParameterReturnInSelf(ParamNode p) {
exists(SummarizedCallable c, int i | exists(SummarizedCallable c, int i | p.isParameterOf(c, i) |
c.clearsContent(i, _) and c.clearsContent(i, _)
p.isParameterOf(c, i) or
exists(SummaryComponentStack inputContents, SummaryComponentStack outputContents |
summary(c, inputContents, outputContents, _) and
inputContents.bottom() = pragma[only_bind_into](TArgumentSummaryComponent(i)) and
outputContents.bottom() = pragma[only_bind_into](TArgumentSummaryComponent(i))
)
) )
} }
@@ -534,22 +609,6 @@ module Private {
preservesValue = false and not summary(c, inputContents, outputContents, true) preservesValue = false and not summary(c, inputContents, outputContents, true)
) )
or or
// If flow through a method updates a parameter from some input A, and that
// parameter also is returned through B, then we'd like a combined flow from A
// to B as well. As an example, this simplifies modeling of fluent methods:
// for `StringBuilder.append(x)` with a specified value flow from qualifier to
// return value and taint flow from argument 0 to the qualifier, then this
// allows us to infer taint flow from argument 0 to the return value.
succ instanceof ParamNode and
summaryPostUpdateNode(pred, succ) and
preservesValue = true
or
// Similarly we would like to chain together summaries where values get passed
// into callbacks along the way.
pred instanceof ArgNode and
summaryPostUpdateNode(succ, pred) and
preservesValue = true
or
exists(SummarizedCallable c, int i | exists(SummarizedCallable c, int i |
pred.(ParamNode).isParameterOf(c, i) and pred.(ParamNode).isParameterOf(c, i) and
succ = summaryNode(c, TSummaryNodeClearsContentState(i, _)) and succ = summaryNode(c, TSummaryNodeClearsContentState(i, _)) and

View File

@@ -262,7 +262,7 @@ class ManagedBeanImplEntryPoint extends EntryPoint, RegisteredManagedBeanImpl {
// Find the method that will be called for each method on each managed bean that this class // Find the method that will be called for each method on each managed bean that this class
// implements. // implements.
this.inherits(result) and this.inherits(result) and
result.overrides(this.getAnImplementedManagedBean().getAMethod()) result.overrides+(this.getAnImplementedManagedBean().getAMethod())
} }
} }

View File

@@ -19,7 +19,7 @@ class Struts1ActionEntryPoint extends EntryPoint, Class {
exists(Method methodFromAction | exists(Method methodFromAction |
methodFromAction.getDeclaringType().hasQualifiedName("org.apache.struts.action", "Action") methodFromAction.getDeclaringType().hasQualifiedName("org.apache.struts.action", "Action")
| |
result.(Method).overrides(methodFromAction) result.(Method).overrides+(methodFromAction)
) )
or or
this.getASupertype*().hasQualifiedName("org.apache.struts.actions", "DispatchAction") and this.getASupertype*().hasQualifiedName("org.apache.struts.actions", "DispatchAction") and

View File

@@ -54,7 +54,8 @@ private class StringSummaryCsv extends SummaryModelCsv {
"java.lang;StringBuffer;true;StringBuffer;(CharSequence);;Argument[0];Argument[-1];taint", "java.lang;StringBuffer;true;StringBuffer;(CharSequence);;Argument[0];Argument[-1];taint",
"java.lang;StringBuffer;true;StringBuffer;(String);;Argument[0];Argument[-1];taint", "java.lang;StringBuffer;true;StringBuffer;(String);;Argument[0];Argument[-1];taint",
"java.lang;StringBuilder;true;StringBuilder;;;Argument[0];Argument[-1];taint", "java.lang;StringBuilder;true;StringBuilder;;;Argument[0];Argument[-1];taint",
"java.lang;CharSequence;true;subSequence;;;Argument[-1];ReturnValue;taint" "java.lang;CharSequence;true;subSequence;;;Argument[-1];ReturnValue;taint",
"java.lang;CharSequence;true;toString;;;Argument[-1];ReturnValue;taint"
] ]
} }
} }

View File

@@ -27,7 +27,7 @@ class ThriftIface extends Interface {
Method getAnImplementingMethod() { Method getAnImplementingMethod() {
result.getDeclaringType().(Class).getASupertype+() = this and result.getDeclaringType().(Class).getASupertype+() = this and
result.overrides(this.getAMethod()) and result.overrides+(this.getAMethod()) and
not result.getFile() = this.getFile() not result.getFile() = this.getFile()
} }
} }

View File

@@ -572,7 +572,7 @@ class RemoteInterface extends Interface {
* abstract methods or overriding within an interface hierarchy. * abstract methods or overriding within an interface hierarchy.
*/ */
Method getARemoteMethodImplementationChecked() { Method getARemoteMethodImplementationChecked() {
result.overrides(this.getARemoteMethod()) and result.overrides+(this.getARemoteMethod()) and
exists(result.getBody()) exists(result.getBody())
} }

View File

@@ -54,7 +54,6 @@ where
sup.isSynchronized() and sup.isSynchronized() and
not sub.isSynchronized() and not sub.isSynchronized() and
not delegatingOverride(sub, sup) and not delegatingOverride(sub, sup) and
not exists(Method mid | sub.overrides(mid) and mid.overrides(sup)) and
supSrc = sup.getDeclaringType().getSourceDeclaration() supSrc = sup.getDeclaringType().getSourceDeclaration()
select sub, select sub,
"Method '" + sub.getName() + "' overrides a synchronized method in $@ but is not synchronized.", "Method '" + sub.getName() + "' overrides a synchronized method in $@ but is not synchronized.",

View File

@@ -45,7 +45,7 @@ where
// which is an access to the object being initialized, ... // which is an access to the object being initialized, ...
ma = unqualifiedCallToNonAbstractMethod(c, m) and ma = unqualifiedCallToNonAbstractMethod(c, m) and
// ... there exists an overriding method in a subtype, // ... there exists an overriding method in a subtype,
n.overrides(m) and n.overrides+(m) and
n.getDeclaringType().getASupertype+() = c.getDeclaringType() and n.getDeclaringType().getASupertype+() = c.getDeclaringType() and
// ... the method is in a supertype of c, // ... the method is in a supertype of c,
m.getDeclaringType() = c.getDeclaringType().getASupertype*() and m.getDeclaringType() = c.getDeclaringType().getASupertype*() and

View File

@@ -0,0 +1,57 @@
/**
* @name Capture sink models.
* @description Finds public methods that act as sinks as they flow into a a known sink.
* @id java/utils/model-generator/sink-models
*/
import java
private import Telemetry.ExternalAPI
private import semmle.code.java.dataflow.DataFlow
private import semmle.code.java.dataflow.TaintTracking
private import semmle.code.java.dataflow.ExternalFlow
private import ModelGeneratorUtils
private import semmle.code.java.dataflow.internal.DataFlowNodes::Private
class PropagateToSinkConfiguration extends TaintTracking::Configuration {
PropagateToSinkConfiguration() { this = "parameters or flowing into sinks" }
override predicate isSource(DataFlow::Node source) {
(source.asExpr().(FieldAccess).isOwnFieldAccess() or source instanceof DataFlow::ParameterNode) and
source.getEnclosingCallable().isPublic() and
exists(RefType t |
t = source.getEnclosingCallable().getDeclaringType().getAnAncestor() and
not t instanceof TypeObject and
t.isPublic()
) and
isRelevantForModels(source.getEnclosingCallable())
}
override predicate isSink(DataFlow::Node sink) { sinkNode(sink, _) }
override DataFlow::FlowFeature getAFeature() {
result instanceof DataFlow::FeatureHasSourceCallContext
}
}
string asInputArgument(DataFlow::Node source) {
exists(int pos |
source.(DataFlow::ParameterNode).isParameterOf(_, pos) and
result = "Argument[" + pos + "]"
)
or
source.asExpr() instanceof FieldAccess and
result = "Argument[-1]"
}
string captureSink(TargetAPI api) {
exists(DataFlow::Node src, DataFlow::Node sink, PropagateToSinkConfiguration config, string kind |
config.hasFlow(src, sink) and
sinkNode(sink, kind) and
api = src.getEnclosingCallable() and
result = asSinkModel(api, asInputArgument(src), kind)
)
}
from TargetAPI api, string sink
where sink = captureSink(api)
select sink order by sink

View File

@@ -0,0 +1,53 @@
/**
* @name Capture source models.
* @description Finds APIs that act as sources as they expose already known sources.
* @id java/utils/model-generator/sink-models
*/
import java
private import Telemetry.ExternalAPI
private import semmle.code.java.dataflow.DataFlow
private import semmle.code.java.dataflow.TaintTracking
private import semmle.code.java.dataflow.ExternalFlow
private import ModelGeneratorUtils
private import semmle.code.java.dataflow.internal.FlowSummaryImplSpecific
private import semmle.code.java.dataflow.internal.FlowSummaryImpl
private import semmle.code.java.dataflow.internal.DataFlowImplCommon
private import semmle.code.java.dataflow.internal.DataFlowPrivate
private import semmle.code.java.dataflow.internal.DataFlowNodes::Private
class FromSourceConfiguration extends TaintTracking::Configuration {
FromSourceConfiguration() { this = "FromSourceConfiguration" }
override predicate isSource(DataFlow::Node source) { sourceNode(source, _) }
override predicate isSink(DataFlow::Node sink) {
exists(TargetAPI c |
sink instanceof ReturnNodeExt and
sink.getEnclosingCallable() = c and
c.isPublic() and
c.fromSource()
)
}
override DataFlow::FlowFeature getAFeature() {
result instanceof DataFlow::FeatureHasSinkCallContext
}
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
isRelevantTaintStep(node1, node2)
}
}
string captureSource(TargetAPI api) {
exists(DataFlow::Node source, DataFlow::Node sink, FromSourceConfiguration config, string kind |
config.hasFlow(source, sink) and
sourceNode(source, kind) and
api = source.getEnclosingCallable() and
result = asSourceModel(api, returnNodeAsOutput(api, sink), kind)
)
}
from TargetAPI api, string sink
where sink = captureSource(api)
select sink order by sink

View File

@@ -0,0 +1,232 @@
/**
* @name Capture summary models.
* @description Finds applicable summary models to be used by other queries.
* @id java/utils/model-generator/summary-models
*/
import java
import semmle.code.java.dataflow.TaintTracking
import semmle.code.java.dataflow.internal.DataFlowImplCommon
import semmle.code.java.dataflow.internal.DataFlowNodes
import semmle.code.java.dataflow.internal.DataFlowPrivate
import semmle.code.java.dataflow.InstanceAccess
import ModelGeneratorUtils
string captureFlow(TargetAPI api) {
result = captureQualifierFlow(api) or
result = captureParameterFlowToReturnValue(api) or
result = captureFieldFlowIn(api) or
result = captureParameterToParameterFlow(api) or
result = captureFieldFlow(api)
}
/**
* Capture fluent APIs that return `this`.
* Example of a fluent API:
* ```
* public class Foo {
* public Foo someAPI() {
* // some side-effect
* return this;
* }
* }
* ```
*/
string captureQualifierFlow(TargetAPI api) {
exists(ReturnStmt rtn |
rtn.getEnclosingCallable() = api and
rtn.getResult().(ThisAccess).isOwnInstanceAccess()
) and
result = asValueModel(api, "Argument[-1]", "ReturnValue")
}
class FieldToReturnConfig extends TaintTracking::Configuration {
FieldToReturnConfig() { this = "FieldToReturnConfig" }
override predicate isSource(DataFlow::Node source) {
source instanceof DataFlow::InstanceParameterNode
}
override predicate isSink(DataFlow::Node sink) {
sink instanceof ReturnNodeExt and
not sink.(ReturnNode).asExpr().(ThisAccess).isOwnInstanceAccess() and
not exists(captureQualifierFlow(sink.asExpr().getEnclosingCallable()))
}
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
isRelevantTaintStep(node1, node2)
}
override DataFlow::FlowFeature getAFeature() {
result instanceof DataFlow::FeatureEqualSourceSinkCallContext
}
}
/**
* Capture APIs that return tainted instance data.
* Example of an API that returns tainted instance data:
* ```
* public class Foo {
* private String tainted;
*
* public String returnsTainted() {
* return tainted;
* }
*
* public void putsTaintIntoParameter(List<String> foo) {
* foo.add(tainted);
* }
* }
* ```
* Captured Model:
* ```
* p;Foo;true;returnsTainted;;Argument[-1];ReturnValue;taint
* p;Foo;true;putsTaintIntoParameter;(List);Argument[-1];Argument[0];taint
* ```
*/
string captureFieldFlow(TargetAPI api) {
exists(FieldToReturnConfig config, ReturnNodeExt returnNodeExt |
config.hasFlow(_, returnNodeExt) and
returnNodeExt.getEnclosingCallable() = api and
not api.getDeclaringType() instanceof EnumType and
isRelevantType(returnNodeExt.getType())
|
result = asTaintModel(api, "Argument[-1]", returnNodeAsOutput(api, returnNodeExt))
)
}
class ParameterToFieldConfig extends TaintTracking::Configuration {
ParameterToFieldConfig() { this = "ParameterToFieldConfig" }
override predicate isSource(DataFlow::Node source) {
source instanceof DataFlow::ParameterNode and
isRelevantType(source.getType())
}
override predicate isSink(DataFlow::Node sink) {
thisAccess(sink.(DataFlow::PostUpdateNode).getPreUpdateNode())
}
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
store(node1, _, node2, _)
}
override DataFlow::FlowFeature getAFeature() {
result instanceof DataFlow::FeatureEqualSourceSinkCallContext
}
}
private predicate thisAccess(DataFlow::Node n) {
n.asExpr().(InstanceAccess).isOwnInstanceAccess()
or
n.(DataFlow::ImplicitInstanceAccess).getInstanceAccess() instanceof OwnInstanceAccess
}
/**
* Captures APIs that accept input and store them in a field.
* Example:
* ```
* public class Foo {
* private String tainted;
* public void doSomething(String input) {
* tainted = input;
* }
* ```
* Captured Model:
* `p;Foo;true;doSomething;(String);Argument[0];Argument[-1];taint`
*/
string captureFieldFlowIn(TargetAPI api) {
exists(DataFlow::Node source, ParameterToFieldConfig config |
config.hasFlow(source, _) and
source.asParameter().getCallable() = api
|
result =
asTaintModel(api, "Argument[" + source.asParameter().getPosition() + "]", "Argument[-1]")
)
}
class ParameterToReturnValueTaintConfig extends TaintTracking::Configuration {
ParameterToReturnValueTaintConfig() { this = "ParameterToReturnValueTaintConfig" }
override predicate isSource(DataFlow::Node source) {
exists(TargetAPI api |
api = source.asParameter().getCallable() and
isRelevantType(api.getReturnType()) and
isRelevantType(source.asParameter().getType())
)
}
override predicate isSink(DataFlow::Node sink) { sink instanceof ReturnNode }
// consider store steps to track taint across objects to model factory methods returning tainted objects
override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
store(node1, _, node2, _)
}
override DataFlow::FlowFeature getAFeature() {
result instanceof DataFlow::FeatureEqualSourceSinkCallContext
}
}
predicate paramFlowToReturnValueExists(Parameter p) {
exists(ParameterToReturnValueTaintConfig config, ReturnStmt rtn |
config.hasFlow(DataFlow::parameterNode(p), DataFlow::exprNode(rtn.getResult()))
)
}
/**
* Capture APIs that return (parts of) data passed in as a parameter.
* Example:
* ```
* public class Foo {
*
* public String returnData(String tainted) {
* return tainted.substring(0,10)
* }
* }
* ```
* Captured Model:
* ```
* p;Foo;true;returnData;;Argument[0];ReturnValue;taint
* ```
*/
string captureParameterFlowToReturnValue(TargetAPI api) {
exists(Parameter p |
p = api.getAParameter() and
paramFlowToReturnValueExists(p)
|
result = asTaintModel(api, parameterAccess(p), "ReturnValue")
)
}
/**
* Capture APIs that pass tainted data from a parameter to a parameter.
* Example:
* ```
* public class Foo {
*
* public void addToList(String tainted, List<String> foo) {
* foo.add(tainted);
* }
* }
* ```
* Captured Model:
* ```
* p;Foo;true;addToList;;Argument[0];Argument[1];taint
* ```
*/
string captureParameterToParameterFlow(TargetAPI api) {
exists(DataFlow::ParameterNode source, DataFlow::PostUpdateNode sink |
source.getEnclosingCallable() = api and
sink.getPreUpdateNode().asExpr() = api.getAParameter().getAnAccess() and
TaintTracking::localTaint(source, sink)
|
result =
asTaintModel(api, parameterAccess(source.asParameter()),
parameterAccess(sink.getPreUpdateNode().asExpr().(VarAccess).getVariable().(Parameter)))
)
}
from TargetAPI api, string flow
where flow = captureFlow(api)
select flow order by flow

View File

@@ -0,0 +1,178 @@
#!/usr/bin/python3
import json
import os
import os.path
import shlex
import subprocess
import sys
import tempfile
def printHelp():
print("""Usage:
GenerateFlowModel.py <library-database> <outputQll> [--with-sinks] [--with-sources] [--with-summaries]
This generates summary, source and sink models for the code in the database.
The files will be placed in `java/ql/lib/semmle/code/java/frameworks/<outputQll>` where
outputQll is the name (and path) of the output QLL file. Usually, models are grouped by their
respective frameworks.
Which models are generated is controlled by the flags:
--with-sinks
--with-sources
--with-summaries
If none of these flags are specified, all models are generated.
Example invocations:
$ GenerateFlowModel.py /tmp/dbs/apache_commons-codec_45649c8 "apache/Codec.qll"
$ GenerateFlowModel.py /tmp/dbs/jdk15_db "javase/jdk_sinks.qll" --with-sinks
Requirements: `codeql` should both appear on your path.
""")
if any(s == "--help" for s in sys.argv):
printHelp()
sys.exit(0)
generateSinks = False
generateSources = False
generateSummaries = False
if "--with-sinks" in sys.argv:
sys.argv.remove("--with-sinks")
generateSinks = True
if "--with-sources" in sys.argv:
sys.argv.remove("--with-sources")
generateSources = True
if "--with-summaries" in sys.argv:
sys.argv.remove("--with-summaries")
generateSummaries = True
if not generateSinks and not generateSources and not generateSummaries:
generateSinks = generateSources = generateSummaries = True
if len(sys.argv) != 3:
printHelp()
sys.exit(1)
codeQlRoot = subprocess.check_output(
["git", "rev-parse", "--show-toplevel"]).decode("utf-8").strip()
targetQll = sys.argv[2]
if not targetQll.endswith(".qll"):
targetQll += ".qll"
filename = os.path.basename(targetQll)
shortname = filename[:-4]
generatedFrameworks = os.path.join(
codeQlRoot, "java/ql/lib/semmle/code/java/frameworks/")
frameworkTarget = os.path.join(generatedFrameworks, targetQll)
workDir = tempfile.mkdtemp()
os.makedirs(generatedFrameworks, exist_ok=True)
def runQuery(infoMessage, query):
print("########## Querying " + infoMessage + "...")
database = sys.argv[1]
queryFile = os.path.join(os.path.dirname(
__file__), query)
resultBqrs = os.path.join(workDir, "out.bqrs")
cmd = ['codeql', 'query', 'run', queryFile, '--database',
database, '--output', resultBqrs, '--threads', '8']
ret = subprocess.call(cmd)
if ret != 0:
print("Failed to generate " + infoMessage +
". Failed command was: " + shlex.join(cmd))
sys.exit(1)
return readRows(resultBqrs)
def readRows(bqrsFile):
generatedJson = os.path.join(workDir, "out.json")
cmd = ['codeql', 'bqrs', 'decode', bqrsFile,
'--format=json', '--output', generatedJson]
ret = subprocess.call(cmd)
if ret != 0:
print("Failed to decode BQRS. Failed command was: " + shlex.join(cmd))
sys.exit(1)
with open(generatedJson) as f:
results = json.load(f)
try:
results['#select']['tuples']
except KeyError:
print('Unexpected JSON output - no tuples found')
exit(1)
rows = ""
for (row) in results['#select']['tuples']:
rows += " \"" + row[0] + "\",\n"
return rows[:-2]
def asCsvModel(superclass, kind, rows):
classTemplate = """
private class {0}{1}Csv extends {2} {{
override predicate row(string row) {{
row =
[
{3}
]
}}
}}
"""
if rows.strip() == "":
return ""
return classTemplate.format(shortname[0].upper() + shortname[1:], kind.capitalize(), superclass, rows)
if generateSummaries:
summaryRows = runQuery("summary models", "CaptureSummaryModels.ql")
summaryCsv = asCsvModel("SummaryModelCsv", "summary", summaryRows)
else:
summaryCsv = ""
if generateSinks:
sinkRows = runQuery("sink models", "CaptureSinkModels.ql")
sinkCsv = asCsvModel("SinkModelCsv", "sinks", sinkRows)
else:
sinkCsv = ""
if generateSources:
sourceRows = runQuery("source models", "CaptureSourceModels.ql")
sourceCsv = asCsvModel("SourceModelCsv", "sources", sourceRows)
else:
sourceCsv = ""
qllTemplate = """
/** Definitions of taint steps in the {0} framework */
import java
private import semmle.code.java.dataflow.ExternalFlow
{1}
{2}
{3}
"""
qllContents = qllTemplate.format(shortname, sinkCsv, sourceCsv, summaryCsv)
with open(frameworkTarget, "w") as frameworkQll:
frameworkQll.write(qllContents)
cmd = ['codeql', 'query', 'format', '--in-place', frameworkTarget]
ret = subprocess.call(cmd)
if ret != 0:
print("Failed to format query. Failed command was: " + shlex.join(cmd))
sys.exit(1)
print("")
print("CSV model written to " + frameworkTarget)

View File

@@ -0,0 +1,173 @@
import java
private import semmle.code.java.dataflow.ExternalFlow
private import semmle.code.java.dataflow.internal.ContainerFlow
private import semmle.code.java.dataflow.internal.DataFlowImplCommon
private import semmle.code.java.dataflow.DataFlow
private import semmle.code.java.dataflow.internal.DataFlowPrivate
Method superImpl(Method m) {
result = m.getAnOverride() and
not exists(result.getAnOverride()) and
not m instanceof ToStringMethod
}
class TargetAPI extends Callable {
TargetAPI() {
this.isPublic() and
this.fromSource() and
(
this.getDeclaringType().isPublic() or
superImpl(this).getDeclaringType().isPublic()
) and
isRelevantForModels(this)
}
}
private string isExtensible(RefType ref) {
if ref.isFinal() then result = "false" else result = "true"
}
predicate isRelevantForModels(Callable api) {
not isInTestFile(api.getCompilationUnit().getFile()) and
not isJdkInternal(api.getCompilationUnit())
}
private predicate isInTestFile(File file) {
file.getAbsolutePath().matches("%src/test/%") or
file.getAbsolutePath().matches("%/guava-tests/%") or
file.getAbsolutePath().matches("%/guava-testlib/%")
}
private predicate isJdkInternal(CompilationUnit cu) {
cu.getPackage().getName().matches("org.graalvm%") or
cu.getPackage().getName().matches("com.sun%") or
cu.getPackage().getName().matches("javax.swing%") or
cu.getPackage().getName().matches("java.awt%") or
cu.getPackage().getName().matches("sun%") or
cu.getPackage().getName().matches("jdk.%") or
cu.getPackage().getName().matches("java2d.%") or
cu.getPackage().getName().matches("build.tools.%") or
cu.getPackage().getName().matches("propertiesparser.%") or
cu.getPackage().getName().matches("org.jcp.%") or
cu.getPackage().getName().matches("org.w3c.%") or
cu.getPackage().getName().matches("org.ietf.jgss.%") or
cu.getPackage().getName().matches("org.xml.sax%") or
cu.getPackage().getName() = "compileproperties" or
cu.getPackage().getName() = "netscape.javascript" or
cu.getPackage().getName() = ""
}
bindingset[input, output]
string asTaintModel(TargetAPI api, string input, string output) {
result = asSummaryModel(api, input, output, "taint")
}
bindingset[input, output]
string asValueModel(TargetAPI api, string input, string output) {
result = asSummaryModel(api, input, output, "value")
}
bindingset[input, output, kind]
string asSummaryModel(TargetAPI api, string input, string output, string kind) {
result =
asPartialModel(api) + input + ";" //
+ output + ";" //
+ kind
}
bindingset[input, kind]
string asSinkModel(TargetAPI api, string input, string kind) {
result = asPartialModel(api) + input + ";" + kind
}
bindingset[output, kind]
string asSourceModel(TargetAPI api, string output, string kind) {
result = asPartialModel(api) + output + ";" + kind
}
/**
* Computes the first 6 columns for CSV rows.
*/
private string asPartialModel(TargetAPI api) {
result =
typeAsSummaryModel(api) + ";" //
+ isExtensible(bestTypeForModel(api)) + ";" //
+ api.getName() + ";" //
+ paramsString(api) + ";" //
+ /* ext + */ ";" //
}
/**
* Returns the appropriate type name for the model. Either the type
* declaring the method or the supertype introducing the method.
*/
private string typeAsSummaryModel(TargetAPI api) { result = typeAsModel(bestTypeForModel(api)) }
private RefType bestTypeForModel(TargetAPI api) {
if exists(superImpl(api))
then superImpl(api).fromSource() and result = superImpl(api).getDeclaringType()
else result = api.getDeclaringType()
}
private string typeAsModel(RefType type) {
result = type.getCompilationUnit().getPackage().getName() + ";" + type.nestedName()
}
predicate isRelevantType(Type t) {
not t instanceof TypeClass and
not t instanceof EnumType and
not t instanceof PrimitiveType and
not t instanceof BoxedType and
not t.(RefType).getAnAncestor().hasQualifiedName("java.lang", "Number") and
not t.(RefType).getAnAncestor().hasQualifiedName("java.nio.charset", "Charset") and
(
not t.(Array).getElementType() instanceof PrimitiveType or
isPrimitiveTypeUsedForBulkData(t.(Array).getElementType())
) and
(
not t.(Array).getElementType() instanceof BoxedType or
isPrimitiveTypeUsedForBulkData(t.(Array).getElementType())
) and
(
not t.(CollectionType).getElementType() instanceof BoxedType or
isPrimitiveTypeUsedForBulkData(t.(CollectionType).getElementType())
)
}
predicate isRelevantTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
exists(DataFlow::Content f |
readStep(node1, f, node2) and
if f instanceof DataFlow::FieldContent
then isRelevantType(f.(DataFlow::FieldContent).getField().getType())
else any()
)
or
exists(DataFlow::Content f | storeStep(node1, f, node2) |
f instanceof DataFlow::ArrayContent or
f instanceof DataFlow::CollectionContent or
f instanceof DataFlow::MapKeyContent or
f instanceof DataFlow::MapValueContent
)
}
string returnNodeAsOutput(TargetAPI api, ReturnNodeExt node) {
if node.getKind() instanceof ValueReturnKind
then result = "ReturnValue"
else
result = parameterAccess(api.getParameter(node.getKind().(ParamUpdateReturnKind).getPosition()))
}
string parameterAccess(Parameter p) {
if
p.getType() instanceof Array and
not isPrimitiveTypeUsedForBulkData(p.getType().(Array).getElementType())
then result = "ArrayElement of Argument[" + p.getPosition() + "]"
else
if p.getType() instanceof ContainerType
then result = "Element of Argument[" + p.getPosition() + "]"
else result = "Argument[" + p.getPosition() + "]"
}
predicate isPrimitiveTypeUsedForBulkData(Type t) {
t.getName().regexpMatch("byte|char|Byte|Character")
}

View File

@@ -151,15 +151,7 @@ public class A {
forEach(new Object[] {source(16)}, x -> sink(x)); // $ flow=16 forEach(new Object[] {source(16)}, x -> sink(x)); // $ flow=16
// Spurious flow from 17 is reasonable as it would likely forEach(new Object[2][], xs -> { sink(xs[0]); xs[0] = source(17); });
// also occur if the lambda body was inlined in a for loop.
// It occurs from the combination of being able to observe
// the side-effect of the callback on the other argument and
// being able to chain summaries that update/read arguments,
// e.g. fluent apis.
// Spurious flow from 18 is due to not matching call targets
// in a return-from-call-to-enter-call flow sequence.
forEach(new Object[2][], xs -> { sink(xs[0]); xs[0] = source(17); }); // $ SPURIOUS: flow=17 flow=18
Object[][] xss = new Object[][] { { null } }; Object[][] xss = new Object[][] { { null } };
forEach(xss, x -> {x[0] = source(18);}); forEach(xss, x -> {x[0] = source(18);});

View File

@@ -9,5 +9,8 @@ public class CharSeq {
CharSequence seqFromSeq = seq.subSequence(0, 1); CharSequence seqFromSeq = seq.subSequence(0, 1);
sink(seqFromSeq); sink(seqFromSeq);
String stringFromSeq = seq.toString();
sink(stringFromSeq);
} }
} }

View File

@@ -43,6 +43,7 @@
| B.java:15:21:15:27 | taint(...) | B.java:157:10:157:46 | toFile(...) | | B.java:15:21:15:27 | taint(...) | B.java:157:10:157:46 | toFile(...) |
| CharSeq.java:7:26:7:32 | taint(...) | CharSeq.java:8:12:8:14 | seq | | CharSeq.java:7:26:7:32 | taint(...) | CharSeq.java:8:12:8:14 | seq |
| CharSeq.java:7:26:7:32 | taint(...) | CharSeq.java:11:12:11:21 | seqFromSeq | | CharSeq.java:7:26:7:32 | taint(...) | CharSeq.java:11:12:11:21 | seqFromSeq |
| CharSeq.java:7:26:7:32 | taint(...) | CharSeq.java:14:12:14:24 | stringFromSeq |
| MethodFlow.java:7:22:7:28 | taint(...) | MethodFlow.java:8:10:8:16 | tainted | | MethodFlow.java:7:22:7:28 | taint(...) | MethodFlow.java:8:10:8:16 | tainted |
| MethodFlow.java:9:31:9:37 | taint(...) | MethodFlow.java:10:10:10:17 | tainted2 | | MethodFlow.java:9:31:9:37 | taint(...) | MethodFlow.java:10:10:10:17 | tainted2 |
| MethodFlow.java:11:35:11:41 | taint(...) | MethodFlow.java:12:10:12:17 | tainted3 | | MethodFlow.java:11:35:11:41 | taint(...) | MethodFlow.java:12:10:12:17 | tainted3 |

View File

@@ -436,7 +436,7 @@ public class Test {
sink(y); // $ hasValueFlow=reduce_3 hasValueFlow=reduce_4 hasValueFlow=reduce_5 sink(y); // $ hasValueFlow=reduce_3 hasValueFlow=reduce_4 hasValueFlow=reduce_5
return source("reduce_5"); return source("reduce_5");
}); });
sink(out); // $ hasValueFlow=reduce_4 hasValueFlow=reduce_5 SPURIOUS: hasValueFlow=reduce_3 sink(out); // $ hasValueFlow=reduce_4 hasValueFlow=reduce_5
} }
{ {
// "java.util.stream;Stream;true;reduce;(Object,BiFunction,BinaryOperator);;Argument[0];ReturnValue;value" // "java.util.stream;Stream;true;reduce;(Object,BiFunction,BinaryOperator);;Argument[0];ReturnValue;value"

View File

@@ -3,4 +3,3 @@
| ConstructedOverrides.java:17:7:17:9 | Sub | usedGeneric(U, String) | Super.class:0:0:0:0 | Super<String> | usedGeneric(U, String) | | ConstructedOverrides.java:17:7:17:9 | Sub | usedGeneric(U, String) | Super.class:0:0:0:0 | Super<String> | usedGeneric(U, String) |
| ConstructedOverrides.java:23:7:23:10 | Sub2 | unusedGeneric(V, String) | Super.class:0:0:0:0 | Super<String> | unusedGeneric(U, String) | | ConstructedOverrides.java:23:7:23:10 | Sub2 | unusedGeneric(V, String) | Super.class:0:0:0:0 | Super<String> | unusedGeneric(U, String) |
| ConstructedOverrides.java:23:7:23:10 | Sub2 | usedGeneric(V, String) | ConstructedOverrides.java:17:7:17:9 | Sub | usedGeneric(U, String) | | ConstructedOverrides.java:23:7:23:10 | Sub2 | usedGeneric(V, String) | ConstructedOverrides.java:17:7:17:9 | Sub | usedGeneric(U, String) |
| ConstructedOverrides.java:23:7:23:10 | Sub2 | usedGeneric(V, String) | Super.class:0:0:0:0 | Super<String> | usedGeneric(U, String) |

View File

@@ -0,0 +1,4 @@
| p;PrivateFlowViaPublicInterface$SPI;true;openStream;();;Argument[-1];create-file |
| p;Sinks;true;copyFileToDirectory;(Path,Path,CopyOption[]);;Argument[1];create-file |
| p;Sinks;true;readUrl;(URL,Charset);;Argument[0];open-url |
| p;Sources;true;readUrl;(URL);;Argument[0];open-url |

View File

@@ -0,0 +1 @@
utils/model-generator/CaptureSinkModels.ql

View File

@@ -0,0 +1,4 @@
| p;Sources;true;readUrl;(URL);;ReturnValue;remote |
| p;Sources;true;socketStream;();;ReturnValue;remote |
| p;Sources;true;sourceToParameter;(InputStream[],List);;ArrayElement of Argument[0];remote |
| p;Sources;true;sourceToParameter;(InputStream[],List);;Element of Argument[1];remote |

View File

@@ -0,0 +1 @@
utils/model-generator/CaptureSourceModels.ql

View File

@@ -0,0 +1,47 @@
| p;Factory;false;create;(String);;Argument[0];ReturnValue;taint |
| p;Factory;false;create;(String,int);;Argument[0];ReturnValue;taint |
| p;Factory;false;getValue;();;Argument[-1];ReturnValue;taint |
| p;FinalClass;false;returnsInput;(String);;Argument[0];ReturnValue;taint |
| p;FluentAPI;false;returnsThis;(String);;Argument[-1];ReturnValue;value |
| p;ImmutablePojo;false;ImmutablePojo;(String,int);;Argument[0];Argument[-1];taint |
| p;ImmutablePojo;false;getValue;();;Argument[-1];ReturnValue;taint |
| p;ImmutablePojo;false;or;(String);;Argument[-1];ReturnValue;taint |
| p;ImmutablePojo;false;or;(String);;Argument[0];ReturnValue;taint |
| p;InnerClasses$CaptureMe;true;yesCm;(String);;Argument[0];ReturnValue;taint |
| p;InnerClasses;true;yes;(String);;Argument[0];ReturnValue;taint |
| p;InnerHolder;false;append;(String);;Argument[0];Argument[-1];taint |
| p;InnerHolder;false;explicitSetContext;(String);;Argument[0];Argument[-1];taint |
| p;InnerHolder;false;getValue;();;Argument[-1];ReturnValue;taint |
| p;InnerHolder;false;setContext;(String);;Argument[0];Argument[-1];taint |
| p;Joiner;false;Joiner;(CharSequence);;Argument[0];Argument[-1];taint |
| p;Joiner;false;Joiner;(CharSequence,CharSequence,CharSequence);;Argument[0];Argument[-1];taint |
| p;Joiner;false;Joiner;(CharSequence,CharSequence,CharSequence);;Argument[1];Argument[-1];taint |
| p;Joiner;false;Joiner;(CharSequence,CharSequence,CharSequence);;Argument[2];Argument[-1];taint |
| p;Joiner;false;add;(CharSequence);;Argument[-1];ReturnValue;value |
| p;Joiner;false;merge;(Joiner);;Argument[-1];ReturnValue;value |
| p;Joiner;false;setEmptyValue;(CharSequence);;Argument[-1];ReturnValue;value |
| p;Joiner;false;setEmptyValue;(CharSequence);;Argument[0];Argument[-1];taint |
| p;Joiner;false;setEmptyValue;(CharSequence);;Argument[0];ReturnValue;taint |
| p;Joiner;false;toString;();;Argument[-1];ReturnValue;taint |
| p;MultipleImpls$Strat2;true;getValue;();;Argument[-1];ReturnValue;taint |
| p;MultipleImpls$Strategy;true;doSomething;(String);;Argument[0];Argument[-1];taint |
| p;MultipleImpls$Strategy;true;doSomething;(String);;Argument[0];ReturnValue;taint |
| p;ParamFlow;true;addTo;(String,List);;Argument[0];Element of Argument[1];taint |
| p;ParamFlow;true;returnArrayElement;(String[]);;ArrayElement of Argument[0];ReturnValue;taint |
| p;ParamFlow;true;returnCollectionElement;(List);;Element of Argument[0];ReturnValue;taint |
| p;ParamFlow;true;returnIterableElement;(Iterable);;Element of Argument[0];ReturnValue;taint |
| p;ParamFlow;true;returnIteratorElement;(Iterator);;Element of Argument[0];ReturnValue;taint |
| p;ParamFlow;true;returnMultipleParameters;(String,String);;Argument[0];ReturnValue;taint |
| p;ParamFlow;true;returnMultipleParameters;(String,String);;Argument[1];ReturnValue;taint |
| p;ParamFlow;true;returnVarArgElement;(String[]);;ArrayElement of Argument[0];ReturnValue;taint |
| p;ParamFlow;true;returnsInput;(String);;Argument[0];ReturnValue;taint |
| p;ParamFlow;true;writeChunked;(byte[],OutputStream);;Argument[0];Argument[1];taint |
| p;ParamFlow;true;writeChunked;(char[],OutputStream);;Argument[0];Argument[1];taint |
| p;Pojo;false;fillIn;(List);;Argument[-1];Element of Argument[0];taint |
| p;Pojo;false;getBoxedBytes;();;Argument[-1];ReturnValue;taint |
| p;Pojo;false;getBoxedChars;();;Argument[-1];ReturnValue;taint |
| p;Pojo;false;getByteArray;();;Argument[-1];ReturnValue;taint |
| p;Pojo;false;getCharArray;();;Argument[-1];ReturnValue;taint |
| p;Pojo;false;getValue;();;Argument[-1];ReturnValue;taint |
| p;Pojo;false;setValue;(String);;Argument[0];Argument[-1];taint |
| p;PrivateFlowViaPublicInterface;true;createAnSPI;(File);;Argument[0];ReturnValue;taint |

View File

@@ -0,0 +1 @@
utils/model-generator/CaptureSummaryModels.ql

View File

@@ -0,0 +1,13 @@
package p;
import java.io.File;
import java.io.FileFilter;
public abstract class AbstractImplOfExternalSPI implements FileFilter {
@Override
public boolean accept(File pathname) {
return false;
}
}

View File

@@ -0,0 +1,30 @@
package p;
public final class Factory {
private String value;
private int intValue;
public static Factory create(String value, int foo) {
return new Factory(value, foo);
}
public static Factory create(String value) {
return new Factory(value, 0);
}
private Factory(String value, int intValue) {
this.value = value;
this.intValue = intValue;
}
public String getValue() {
return value;
}
public int getIntValue() {
return intValue;
}
}

View File

@@ -0,0 +1,15 @@
package p;
public final class FinalClass {
private static final String C = "constant";
public String returnsInput(String input) {
return input;
}
public String returnsConstant() {
return C;
}
}

View File

@@ -0,0 +1,15 @@
package p;
public final class FluentAPI {
public FluentAPI returnsThis(String input) {
return this;
}
public class Inner {
public FluentAPI notThis(String input) {
return FluentAPI.this;
}
}
}

View File

@@ -0,0 +1,26 @@
package p;
public final class ImmutablePojo {
private final String value;
private final long x;
public ImmutablePojo(String value, int x) {
this.value = value;
this.x = x;
}
public String getValue() {
return value;
}
public long getX() {
return x;
}
public String or(String defaultValue) {
return value != null ? value : defaultValue;
}
}

View File

@@ -0,0 +1,19 @@
package p;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
public class ImplOfExternalSPI extends AbstractImplOfExternalSPI {
@Override
public boolean accept(File pathname) {
try {
Files.createFile(pathname.toPath());
} catch (IOException e) {
e.printStackTrace();
}
return false;
}
}

View File

@@ -0,0 +1,21 @@
package p;
public class InnerClasses {
class IgnoreMe {
public String no(String input) {
return input;
}
}
public class CaptureMe {
public String yesCm(String input) {
return input;
}
}
public String yes(String input) {
return input;
}
}

View File

@@ -0,0 +1,37 @@
package p;
public final class InnerHolder {
private class Context {
private String value;
Context(String value) {
this.value = value;
}
public String getValue() {
return value;
}
}
private Context context = null;
private StringBuilder sb = new StringBuilder();
public void setContext(String value) {
context = new Context(value);
}
public void explicitSetContext(String value) {
this.context = new Context(value);
}
public void append(String value) {
sb.append(value);
}
public String getValue() {
return context.getValue();
}
}

View File

@@ -0,0 +1,118 @@
package p;
import java.util.Arrays;
import java.util.Objects;
public final class Joiner {
private final String prefix;
private final String delimiter;
private final String suffix;
private String[] elts;
private int size;
private int len;
private String emptyValue;
public Joiner(CharSequence delimiter) {
this(delimiter, "", "");
}
public Joiner(CharSequence delimiter,
CharSequence prefix,
CharSequence suffix) {
Objects.requireNonNull(prefix, "The prefix must not be null");
Objects.requireNonNull(delimiter, "The delimiter must not be null");
Objects.requireNonNull(suffix, "The suffix must not be null");
this.prefix = prefix.toString();
this.delimiter = delimiter.toString();
this.suffix = suffix.toString();
checkAddLength(0, 0);
}
public Joiner setEmptyValue(CharSequence emptyValue) {
this.emptyValue = Objects.requireNonNull(emptyValue,
"The empty value must not be null").toString();
return this;
}
private static int getChars(String s, char[] chars, int start) {
int len = s.length();
s.getChars(0, len, chars, start);
return len;
}
@Override
public String toString() {
final String[] elts = this.elts;
if (elts == null && emptyValue != null) {
return emptyValue;
}
final int size = this.size;
final int addLen = prefix.length() + suffix.length();
if (addLen == 0) {
compactElts();
return size == 0 ? "" : elts[0];
}
final String delimiter = this.delimiter;
final char[] chars = new char[len + addLen];
int k = getChars(prefix, chars, 0);
if (size > 0) {
k += getChars(elts[0], chars, k);
for (int i = 1; i < size; i++) {
k += getChars(delimiter, chars, k);
k += getChars(elts[i], chars, k);
}
}
k += getChars(suffix, chars, k);
return new String(chars);
}
public Joiner add(CharSequence newElement) {
final String elt = String.valueOf(newElement);
if (elts == null) {
elts = new String[8];
} else {
if (size == elts.length)
elts = Arrays.copyOf(elts, 2 * size);
len = checkAddLength(len, delimiter.length());
}
len = checkAddLength(len, elt.length());
elts[size++] = elt;
return this;
}
private int checkAddLength(int oldLen, int inc) {
long newLen = (long)oldLen + (long)inc;
long tmpLen = newLen + (long)prefix.length() + (long)suffix.length();
if (tmpLen != (int)tmpLen) {
throw new OutOfMemoryError("Requested array size exceeds VM limit");
}
return (int)newLen;
}
public Joiner merge(Joiner other) {
Objects.requireNonNull(other);
if (other.elts == null) {
return this;
}
other.compactElts();
return add(other.elts[0]);
}
private void compactElts() {
if (size > 1) {
final char[] chars = new char[len];
int i = 1, k = getChars(elts[0], chars, 0);
do {
k += getChars(delimiter, chars, k);
k += getChars(elts[i], chars, k);
elts[i] = null;
} while (++i < size);
size = 1;
elts[0] = new String(chars);
}
}
public int length() {
return (size == 0 && emptyValue != null) ? emptyValue.length() :
len + prefix.length() + suffix.length();
}
}

View File

@@ -0,0 +1,38 @@
package p;
import java.util.concurrent.Callable;
public class MultipleImpls {
public static interface Strategy {
String doSomething(String value);
}
public static class Strat1 implements Strategy {
public String doSomething(String value) {
return value;
}
}
// implements in different library should not count as impl
public static class Strat3 implements Callable<String> {
@Override
public String call() throws Exception {
return null;
}
}
public static class Strat2 implements Strategy {
private String foo;
public String doSomething(String value) {
this.foo = value;
return "none";
}
public String getValue() {
return this.foo;
}
}
}

View File

@@ -0,0 +1,64 @@
package p;
import java.util.Iterator;
import java.util.List;
import java.io.IOException;
import java.io.OutputStream;
public class ParamFlow {
public String returnsInput(String input) {
return input;
}
public int ignorePrimitiveReturnValue(String input) {
return input.length();
}
public String returnMultipleParameters(String one, String two) {
if (System.currentTimeMillis() > 100) {
return two;
}
return one;
}
public String returnArrayElement(String[] input) {
return input[0];
}
public String returnVarArgElement(String... input) {
return input[0];
}
public String returnCollectionElement(List<String> input) {
return input.get(0);
}
public String returnIteratorElement(Iterator<String> input) {
return input.next();
}
public String returnIterableElement(Iterable<String> input) {
return input.iterator().next();
}
public Class<?> mapType(Class<?> input) {
return input;
}
public void writeChunked(byte[] data, OutputStream output)
throws IOException {
output.write(data, 0, data.length);
}
public void writeChunked(char[] data, OutputStream output)
throws IOException {
output.write(String.valueOf(data).getBytes(), 0, data.length);
}
public void addTo(String data, List<String> target) {
target.add(data);
}
}

View File

@@ -0,0 +1,98 @@
package p;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
public final class Pojo {
private class Holder {
private String value;
Holder(String value) {
this.value = value;
}
int length() {
return value.length();
}
}
private String value;
private int intValue = 2;
private byte[] byteArray = new byte[] {1, 2, 3} ;
private float[] floatArray = new float[] {1, 2, 3} ;
private char[] charArray = new char[] {'a', 'b', 'c'} ;
private List<Character> charList = Arrays.asList('a', 'b', 'c');
private Byte[] byteObjectArray = new Byte[] { 1, 2, 3 };
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public int doNotSetValue(String value) {
Holder h = new Holder(value);
return h.length();
}
public int getIntValue() {
return intValue;
}
public Integer getBoxedValue() {
return Integer.valueOf(intValue);
}
public int[] getPrimitiveArray() {
return new int[] { intValue };
}
public char[] getCharArray() {
return charArray;
}
public byte[] getByteArray() {
return byteArray;
}
public float[] getFloatArray() {
return floatArray;
}
public Integer[] getBoxedArray() {
return new Integer[] { Integer.valueOf(intValue) };
}
public Collection<Integer> getBoxedCollection() {
return List.of(Integer.valueOf(intValue));
}
public List<Character> getBoxedChars() {
return charList;
}
public Byte[] getBoxedBytes() {
return byteObjectArray;
}
public BigInteger getBigInt() {
return BigInteger.valueOf(intValue);
}
public BigDecimal getBigDecimal() {
return new BigDecimal(value);
}
public void fillIn(List<String> target) {
target.add(value);
}
}

View File

@@ -0,0 +1,61 @@
package p;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
public class PrivateFlowViaPublicInterface {
static class RandomPojo {
public File someFile = new File("someFile");
}
public static interface SPI {
OutputStream openStream() throws IOException;
default OutputStream openStreamNone() throws IOException {
return null;
};
}
private static final class PrivateImplWithSink implements SPI {
private File file;
public PrivateImplWithSink(File file) {
this.file = file;
}
@Override
public OutputStream openStream() throws IOException {
return new FileOutputStream(file);
}
}
private static final class PrivateImplWithRandomField implements SPI {
public PrivateImplWithRandomField(File file) {
}
@Override
public OutputStream openStream() throws IOException {
return null;
}
@Override
public OutputStream openStreamNone() throws IOException {
return new FileOutputStream(new RandomPojo().someFile);
}
}
public static SPI createAnSPI(File file) {
return new PrivateImplWithSink(file);
}
public static SPI createAnSPIWithoutTrackingFile(File file) {
return new PrivateImplWithRandomField(file);
}
}

View File

@@ -0,0 +1,24 @@
package p;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.file.CopyOption;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
public class Sinks {
public Path copyFileToDirectory(final Path sourceFile, final Path targetFile, final CopyOption... copyOptions) throws IOException {
return Files.copy(sourceFile, targetFile, copyOptions);
}
public String readUrl(final URL url, Charset encoding) throws IOException {
try (InputStream in = url.openStream()) {
byte[] bytes = in.readAllBytes();
return new String(bytes, encoding);
}
}
}

View File

@@ -0,0 +1,17 @@
package p;
enum SomeEnum {
FOO("input");
private String input;
private SomeEnum(String input) {
this.input = input;
}
public String getValue() {
return input;
}
}

View File

@@ -0,0 +1,28 @@
package p;
import java.io.IOException;
import java.io.InputStream;
import java.net.ServerSocket;
import java.net.URL;
import java.util.function.Consumer;
import java.util.List;
public class Sources {
public InputStream readUrl(final URL url) throws IOException {
return url.openConnection().getInputStream();
}
public InputStream socketStream() throws IOException {
ServerSocket socket = new ServerSocket(123);
return socket.accept().getInputStream();
}
public void sourceToParameter(InputStream[] streams, List<InputStream> otherStreams) throws IOException {
ServerSocket socket = new ServerSocket(123);
streams[0] = socket.accept().getInputStream();
otherStreams.add(socket.accept().getInputStream());
}
}

View File

@@ -0,0 +1,4 @@
lgtm,codescanning
* A new query, `js/bad-tag-filter`, has been added to the query suite,
highlighting regular expressions that only match a subset of the HTML tags
it is supposed to match.

View File

@@ -54,7 +54,7 @@ DatabaseFeatures::Entity getRepresentativeEntityForEndpoint(DataFlow::Node endpo
// Use the largest entity smaller than the AST node limit, resolving ties using the entity that // Use the largest entity smaller than the AST node limit, resolving ties using the entity that
// appears first in the source archive. // appears first in the source archive.
result = result =
rank[1](DatabaseFeatures::Entity entity, int numAstNodes, Location l | min(DatabaseFeatures::Entity entity, int numAstNodes, Location l |
entity = EndpointToEntity::getAnEntityForEndpoint(endpoint) and entity = EndpointToEntity::getAnEntityForEndpoint(endpoint) and
numAstNodes = getNumAstNodesInEntity(entity) and numAstNodes = getNumAstNodesInEntity(entity) and
numAstNodes <= getMaxNumAstNodes() and numAstNodes <= getMaxNumAstNodes() and
@@ -68,7 +68,7 @@ DatabaseFeatures::Entity getRepresentativeEntityForEndpoint(DataFlow::Node endpo
// Use the smallest entity, resolving ties using the entity that // Use the smallest entity, resolving ties using the entity that
// appears first in the source archive. // appears first in the source archive.
result = result =
rank[1](DatabaseFeatures::Entity entity, int numAstNodes, Location l | min(DatabaseFeatures::Entity entity, int numAstNodes, Location l |
entity = EndpointToEntity::getAnEntityForEndpoint(endpoint) and entity = EndpointToEntity::getAnEntityForEndpoint(endpoint) and
numAstNodes = getNumAstNodesInEntity(entity) and numAstNodes = getNumAstNodesInEntity(entity) and
l = entity.getLocation() l = entity.getLocation()

View File

@@ -207,7 +207,9 @@ private predicate isAmbientTopLevel(TopLevel tl) {
*/ */
class TopLevel extends @toplevel, StmtContainer { class TopLevel extends @toplevel, StmtContainer {
/** Holds if this toplevel is minified. */ /** Holds if this toplevel is minified. */
cached
predicate isMinified() { predicate isMinified() {
Stages::Ast::ref() and
// file name contains 'min' (not as part of a longer word) // file name contains 'min' (not as part of a longer word)
getFile().getBaseName().regexpMatch(".*[^-._]*[-._]min([-._].*)?\\.\\w+") getFile().getBaseName().regexpMatch(".*[^-._]*[-._]min([-._].*)?\\.\\w+")
or or

View File

@@ -359,35 +359,6 @@ module DOM {
call.getNumArgument() = 1 and call.getNumArgument() = 1 and
unique(InferredType t | t = getArgumentTypeFromJQueryMethodGet(call)) = TTNumber() unique(InferredType t | t = getArgumentTypeFromJQueryMethodGet(call)) = TTNumber()
) )
or
// A `this` node from a callback given to a `$().each(callback)` call.
// purposely not using JQuery::MethodCall to avoid `jquery.each()`.
exists(DataFlow::CallNode eachCall | eachCall = JQuery::objectRef().getAMethodCall("each") |
this = DataFlow::thisNode(eachCall.getCallback(0).getFunction()) or
this = eachCall.getABoundCallbackParameter(0, 1)
)
or
// A read of an array-element from a JQuery object. E.g. `$("#foo")[0]`
exists(DataFlow::PropRead read |
read = this and read = JQuery::objectRef().getAPropertyRead()
|
unique(InferredType t | t = read.getPropertyNameExpr().analyze().getAType()) = TTNumber()
)
or
// A receiver node of an event handler on a DOM node
exists(DataFlow::SourceNode domNode, DataFlow::FunctionNode eventHandler |
// NOTE: we do not use `getABoundFunctionValue()`, since bound functions tend to have
// a different receiver anyway
eventHandler = domNode.getAPropertySource(any(string n | n.matches("on%")))
or
eventHandler =
domNode.getAMethodCall("addEventListener").getArgument(1).getAFunctionValue()
|
domNode = domValueRef() and
this = eventHandler.getReceiver()
)
or
this = DataFlow::thisNode(any(EventHandlerCode evt))
} }
} }
} }
@@ -421,11 +392,6 @@ module DOM {
or or
t.start() and t.start() and
result = domValueRef().getAMethodCall(["item", "namedItem"]) result = domValueRef().getAMethodCall(["item", "namedItem"])
or
t.startInProp("target") and
result = domEventSource()
or
exists(DataFlow::TypeTracker t2 | result = domValueRef(t2).track(t2, t))
} }
/** Gets a data flow node that may refer to a value from the DOM. */ /** Gets a data flow node that may refer to a value from the DOM. */

View File

@@ -141,6 +141,19 @@ private DataFlow::Node getAValueExportedByPackage() {
result = unique( | | call.getCalleeNode().getAFunctionValue()).getAReturn() result = unique( | | call.getCalleeNode().getAFunctionValue()).getAReturn()
) )
or or
// the exported value is a function that returns another import.
// ```JavaScript
// module.exports = function foo() {
// return require("./other-module.js");
// }
// ```
exists(DataFlow::FunctionNode func, Module mod |
func = getAValueExportedByPackage().getABoundFunctionValue(_)
|
mod = func.getAReturn().getALocalSource().getEnclosingExpr().(Import).getImportedModule() and
result = getAnExportFromModule(mod)
)
or
// ***** // *****
// Common styles of transforming exported objects. // Common styles of transforming exported objects.
// ***** // *****

View File

@@ -185,12 +185,12 @@ module Promises {
/** /**
* Gets the pseudo-field used to describe resolved values in a promise. * Gets the pseudo-field used to describe resolved values in a promise.
*/ */
string valueProp() { result = "$PromiseResolveField$" } string valueProp() { none() }
/** /**
* Gets the pseudo-field used to describe rejected values in a promise. * Gets the pseudo-field used to describe rejected values in a promise.
*/ */
string errorProp() { result = "$PromiseRejectField$" } string errorProp() { none() }
} }
/** /**

View File

@@ -7,6 +7,7 @@
import javascript import javascript
private import semmle.javascript.dataflow.InferredTypes private import semmle.javascript.dataflow.InferredTypes
private import semmle.javascript.internal.CachedStages
/** /**
* An element containing a regular expression term, that is, either * An element containing a regular expression term, that is, either
@@ -955,7 +956,9 @@ private predicate isUsedAsNonMatchObject(DataFlow::MethodCallNode call) {
/** /**
* Holds if `source` may be interpreted as a regular expression. * Holds if `source` may be interpreted as a regular expression.
*/ */
cached
predicate isInterpretedAsRegExp(DataFlow::Node source) { predicate isInterpretedAsRegExp(DataFlow::Node source) {
Stages::Taint::ref() and
source.analyze().getAType() = TTString() and source.analyze().getAType() = TTString() and
( (
// The first argument to an invocation of `RegExp` (with or without `new`). // The first argument to an invocation of `RegExp` (with or without `new`).

View File

@@ -777,10 +777,10 @@ private class AdditionalFlowStepAsSharedStep extends SharedFlowStep {
*/ */
module PseudoProperties { module PseudoProperties {
bindingset[s] bindingset[s]
private string pseudoProperty(string s) { result = "$" + s + "$" } private string pseudoProperty(string s) { none() }
bindingset[s, v] bindingset[s, v]
private string pseudoProperty(string s, string v) { result = "$" + s + "|" + v + "$" } private string pseudoProperty(string s, string v) { none() }
/** /**
* Gets a pseudo-property for the location of elements in a `Set` * Gets a pseudo-property for the location of elements in a `Set`

View File

@@ -136,7 +136,7 @@ module Angular2 {
/** Gets a reference to a `DomSanitizer` object. */ /** Gets a reference to a `DomSanitizer` object. */
DataFlow::SourceNode domSanitizer() { DataFlow::SourceNode domSanitizer() {
result.hasUnderlyingType(["@angular/platform-browser", "@angular/core"], "DomSanitizer") result.hasUnderlyingType("@angular/platform-browser", "DomSanitizer")
} }
/** A value that is about to be promoted to a trusted HTML or CSS value. */ /** A value that is about to be promoted to a trusted HTML or CSS value. */

View File

@@ -864,28 +864,6 @@ module Express {
override string getCredentialsKind() { result = kind } override string getCredentialsKind() { result = kind }
} }
/** A call to `response.sendFile`, considered as a file system access. */
private class ResponseSendFileAsFileSystemAccess extends FileSystemReadAccess,
DataFlow::MethodCallNode {
ResponseSendFileAsFileSystemAccess() {
exists(string name | name = "sendFile" or name = "sendfile" |
calls(any(ResponseExpr res).flow(), name)
)
}
override DataFlow::Node getADataNode() { none() }
override DataFlow::Node getAPathArgument() { result = getArgument(0) }
override DataFlow::Node getRootPathArgument() {
result = this.(DataFlow::CallNode).getOptionArgument(1, "root")
}
override predicate isUpwardNavigationRejected(DataFlow::Node argument) {
argument = getAPathArgument()
}
}
/** /**
* A function that flows to a route setup. * A function that flows to a route setup.
*/ */

View File

@@ -4,23 +4,6 @@
import javascript import javascript
/**
* A call that can produce a file name.
*/
abstract private class FileNameProducer extends DataFlow::Node {
/**
* Gets a file name produced by this producer.
*/
abstract DataFlow::Node getAFileName();
}
/**
* A node that contains a file name, and is produced by a `ProducesFileNames`.
*/
private class ProducedFileName extends FileNameSource {
ProducedFileName() { this = any(FileNameProducer producer).getAFileName() }
}
/** /**
* A file name from the `walk-sync` library. * A file name from the `walk-sync` library.
*/ */
@@ -143,338 +126,3 @@ private DataFlow::Node fastGlobFileNameSource(DataFlow::TypeTracker t) {
private class FastGlobFileNameSource extends FileNameSource { private class FastGlobFileNameSource extends FileNameSource {
FastGlobFileNameSource() { this = fastGlobFileNameSource(DataFlow::TypeTracker::end()) } FastGlobFileNameSource() { this = fastGlobFileNameSource(DataFlow::TypeTracker::end()) }
} }
/**
* Classes and predicates for modelling the `fstream` library (https://www.npmjs.com/package/fstream).
*/
private module FStream {
/**
* Gets a reference to a method in the `fstream` library.
*/
private DataFlow::SourceNode getAnFStreamProperty(boolean writer) {
exists(DataFlow::SourceNode mod, string readOrWrite, string subMod |
mod = DataFlow::moduleImport("fstream") and
(
readOrWrite = "Reader" and writer = false
or
readOrWrite = "Writer" and writer = true
) and
(subMod = "File" or subMod = "Dir" or subMod = "Link" or subMod = "Proxy")
|
result = mod.getAPropertyRead(readOrWrite) or
result = mod.getAPropertyRead(readOrWrite).getAPropertyRead(subMod) or
result = mod.getAPropertyRead(subMod).getAPropertyRead(readOrWrite)
)
}
/**
* An invocation of a method defined in the `fstream` library.
*/
private class FStream extends FileSystemAccess, DataFlow::InvokeNode {
boolean writer;
FStream() { this = getAnFStreamProperty(writer).getAnInvocation() }
override DataFlow::Node getAPathArgument() {
result = getOptionArgument(0, "path")
or
not exists(getOptionArgument(0, "path")) and
result = getArgument(0)
}
}
/**
* An invocation of an `fstream` method that writes to a file.
*/
private class FStreamWriter extends FileSystemWriteAccess, FStream {
FStreamWriter() { writer = true }
override DataFlow::Node getADataNode() { none() }
}
/**
* An invocation of an `fstream` method that reads a file.
*/
private class FStreamReader extends FileSystemReadAccess, FStream {
FStreamReader() { writer = false }
override DataFlow::Node getADataNode() { none() }
}
}
/**
* A call to the library `write-file-atomic`.
*/
private class WriteFileAtomic extends FileSystemWriteAccess, DataFlow::CallNode {
WriteFileAtomic() {
this = DataFlow::moduleImport("write-file-atomic").getACall()
or
this = DataFlow::moduleMember("write-file-atomic", "sync").getACall()
}
override DataFlow::Node getAPathArgument() { result = getArgument(0) }
override DataFlow::Node getADataNode() { result = getArgument(1) }
}
/**
* A call to the library `recursive-readdir`.
*/
private class RecursiveReadDir extends FileSystemAccess, FileNameProducer, DataFlow::CallNode {
RecursiveReadDir() { this = DataFlow::moduleImport("recursive-readdir").getACall() }
override DataFlow::Node getAPathArgument() { result = getArgument(0) }
override DataFlow::Node getAFileName() { result = trackFileSource(DataFlow::TypeTracker::end()) }
private DataFlow::SourceNode trackFileSource(DataFlow::TypeTracker t) {
t.start() and result = getCallback([1 .. 2]).getParameter(1)
or
t.startInPromise() and not exists(getCallback([1 .. 2])) and result = this
or
// Tracking out of a promise
exists(DataFlow::TypeTracker t2 |
result = PromiseTypeTracking::promiseStep(trackFileSource(t2), t, t2)
)
}
}
/**
* Classes and predicates for modelling the `jsonfile` library (https://www.npmjs.com/package/jsonfile).
*/
private module JSONFile {
/**
* A reader for JSON files.
*/
class JSONFileReader extends FileSystemReadAccess, DataFlow::CallNode {
JSONFileReader() {
this =
DataFlow::moduleMember("jsonfile", any(string s | s = "readFile" or s = "readFileSync"))
.getACall()
}
override DataFlow::Node getAPathArgument() { result = getArgument(0) }
override DataFlow::Node getADataNode() { result = trackRead(DataFlow::TypeTracker::end()) }
private DataFlow::SourceNode trackRead(DataFlow::TypeTracker t) {
this.getCalleeName() = "readFile" and
(
t.start() and result = getCallback([1 .. 2]).getParameter(1)
or
t.startInPromise() and not exists(getCallback([1 .. 2])) and result = this
)
or
t.start() and
this.getCalleeName() = "readFileSync" and
result = this
or
// Tracking out of a promise
exists(DataFlow::TypeTracker t2 |
result = PromiseTypeTracking::promiseStep(trackRead(t2), t, t2)
)
}
}
/**
* A writer for JSON files.
*/
class JSONFileWriter extends FileSystemWriteAccess, DataFlow::CallNode {
JSONFileWriter() {
this =
DataFlow::moduleMember("jsonfile", any(string s | s = "writeFile" or s = "writeFileSync"))
.getACall()
}
override DataFlow::Node getAPathArgument() { result = getArgument(0) }
override DataFlow::Node getADataNode() { result = getArgument(1) }
}
}
/**
* A call to the library `load-json-file`.
*/
private class LoadJsonFile extends FileSystemReadAccess, DataFlow::CallNode {
LoadJsonFile() {
this = DataFlow::moduleImport("load-json-file").getACall()
or
this = DataFlow::moduleMember("load-json-file", "sync").getACall()
}
override DataFlow::Node getAPathArgument() { result = getArgument(0) }
override DataFlow::Node getADataNode() { result = trackRead(DataFlow::TypeTracker::end()) }
private DataFlow::SourceNode trackRead(DataFlow::TypeTracker t) {
this.getCalleeName() = "sync" and t.start() and result = this
or
not this.getCalleeName() = "sync" and t.startInPromise() and result = this
or
// Tracking out of a promise
exists(DataFlow::TypeTracker t2 |
result = PromiseTypeTracking::promiseStep(trackRead(t2), t, t2)
)
}
}
/**
* A call to the library `write-json-file`.
*/
private class WriteJsonFile extends FileSystemWriteAccess, DataFlow::CallNode {
WriteJsonFile() {
this = DataFlow::moduleImport("write-json-file").getACall()
or
this = DataFlow::moduleMember("write-json-file", "sync").getACall()
}
override DataFlow::Node getAPathArgument() { result = getArgument(0) }
override DataFlow::Node getADataNode() { result = getArgument(1) }
}
/**
* A call to the library `walkdir`.
*/
private class WalkDir extends FileNameProducer, FileSystemAccess, DataFlow::CallNode {
WalkDir() {
this = DataFlow::moduleImport("walkdir").getACall()
or
this = DataFlow::moduleMember("walkdir", "sync").getACall()
or
this = DataFlow::moduleMember("walkdir", "async").getACall()
}
override DataFlow::Node getAPathArgument() { result = getArgument(0) }
override DataFlow::Node getAFileName() { result = trackFileSource(DataFlow::TypeTracker::end()) }
private DataFlow::SourceNode trackFileSource(DataFlow::TypeTracker t) {
not this.getCalleeName() = any(string s | s = "sync" or s = "async") and
t.start() and
(
result = getCallback(getNumArgument() - 1).getParameter(0)
or
result = getAMethodCall(EventEmitter::on()).getCallback(1).getParameter(0)
)
or
t.start() and this.getCalleeName() = "sync" and result = this
or
t.startInPromise() and this.getCalleeName() = "async" and result = this
or
// Tracking out of a promise
exists(DataFlow::TypeTracker t2 |
result = PromiseTypeTracking::promiseStep(trackFileSource(t2), t, t2)
)
}
}
/**
* A call to the library `globule`.
*/
private class Globule extends FileNameProducer, FileSystemAccess, DataFlow::CallNode {
Globule() {
this = DataFlow::moduleMember("globule", "find").getACall()
or
this = DataFlow::moduleMember("globule", "match").getACall()
or
this = DataFlow::moduleMember("globule", "isMatch").getACall()
or
this = DataFlow::moduleMember("globule", "mapping").getACall()
or
this = DataFlow::moduleMember("globule", "findMapping").getACall()
}
override DataFlow::Node getAPathArgument() {
(this.getCalleeName() = "match" or this.getCalleeName() = "isMatch") and
result = getArgument(1)
or
this.getCalleeName() = "mapping" and
(
result = getAnArgument() and not exists(result.getALocalSource().getAPropertyWrite("src"))
or
result = getAnArgument().getALocalSource().getAPropertyWrite("src").getRhs()
)
}
override DataFlow::Node getAFileName() {
result = this and
(
this.getCalleeName() = "find" or
this.getCalleeName() = "match" or
this.getCalleeName() = "findMapping" or
this.getCalleeName() = "mapping"
)
}
}
/**
* A file system access made by a NodeJS library.
* This class models multiple NodeJS libraries that access files.
*/
private class LibraryAccess extends FileSystemAccess, DataFlow::InvokeNode {
int pathArgument; // The index of the path argument.
LibraryAccess() {
pathArgument = 0 and
(
this = DataFlow::moduleImport("path-exists").getACall()
or
this = DataFlow::moduleImport("rimraf").getACall()
or
this = DataFlow::moduleImport("readdirp").getACall()
or
this = DataFlow::moduleImport("walker").getACall()
or
this =
DataFlow::moduleMember("node-dir",
any(string s |
s = ["readFiles", "readFilesStream", "files", "promiseFiles", "subdirs", "paths"]
)).getACall()
)
or
pathArgument = 0 and
this =
DataFlow::moduleMember("vinyl-fs", any(string s | s = "src" or s = "dest" or s = "symlink"))
.getACall()
or
pathArgument = [0 .. 1] and
(
this = DataFlow::moduleImport("ncp").getACall() or
this = DataFlow::moduleMember("ncp", "ncp").getACall()
)
}
override DataFlow::Node getAPathArgument() { result = getArgument(pathArgument) }
}
/**
* A call to the library [`chokidar`](https://www.npmjs.com/package/chokidar), where a call to `on` receives file names.
*/
class Chokidar extends FileNameProducer, FileSystemAccess, API::CallNode {
Chokidar() { this = API::moduleImport("chokidar").getMember("watch").getACall() }
override DataFlow::Node getAPathArgument() { result = getArgument(0) }
override DataFlow::Node getAFileName() {
exists(DataFlow::CallNode onCall, int pathIndex |
onCall = getAChainedMethodCall("on") and
if onCall.getArgument(0).mayHaveStringValue("all") then pathIndex = 1 else pathIndex = 0
|
result = onCall.getCallback(1).getParameter(pathIndex)
)
}
}
/**
* A call to the [`mkdirp`](https://www.npmjs.com/package/mkdirp) library.
*/
private class Mkdirp extends FileSystemAccess, API::CallNode {
Mkdirp() {
this = API::moduleImport("mkdirp").getACall()
or
this = API::moduleImport("mkdirp").getMember("sync").getACall()
}
override DataFlow::Node getAPathArgument() { result = getArgument(0) }
}

View File

@@ -6,146 +6,120 @@ import javascript
module NoSQL { module NoSQL {
/** An expression that is interpreted as a NoSQL query. */ /** An expression that is interpreted as a NoSQL query. */
abstract class Query extends Expr { abstract class Query extends Expr { }
/** Gets an expression that is interpreted as a code operator in this query. */
DataFlow::Node getACodeOperator() { none() }
}
}
/**
* Gets a value that has been assigned to the "$where" property of an object that flows to `queryArg`.
*/
private DataFlow::Node getADollarWhereProperty(API::Node queryArg) {
result = queryArg.getMember("$where").getARhs()
} }
/** /**
* Provides classes modeling the MongoDB library. * Provides classes modeling the MongoDB library.
*/ */
private module MongoDB { private module MongoDB {
/**
* Gets an import of MongoDB.
*/
DataFlow::ModuleImportNode mongodb() { result.getPath() = "mongodb" }
/** /**
* Gets an access to `mongodb.MongoClient`. * Gets an access to `mongodb.MongoClient`.
*/ */
private API::Node getAMongoClient() { private DataFlow::SourceNode getAMongoClient(DataFlow::TypeTracker t) {
result = API::moduleImport("mongodb").getMember("MongoClient") t.start() and
result = mongodb().getAPropertyRead("MongoClient")
or or
result = getAMongoDbCallback().getParameter(1) and exists(DataFlow::TypeTracker t2 | result = getAMongoClient(t2).track(t2, t))
not result.getAnImmediateUse().(DataFlow::ParameterNode).getName() = "db" // mongodb v2 provides a `Db` here
}
/** Gets an API-graph node that refers to a `connect` callback. */
private API::Node getAMongoDbCallback() {
result = getAMongoClient().getMember("connect").getLastParameter()
} }
/** /**
* Gets an API-graph node that may refer to a MongoDB database connection. * Gets an access to `mongodb.MongoClient`.
*/ */
private API::Node getAMongoDb() { DataFlow::SourceNode getAMongoClient() { result = getAMongoClient(DataFlow::TypeTracker::end()) }
result = getAMongoClient().getMember("db").getReturn()
/** Gets a data flow node that leads to a `connect` callback. */
private DataFlow::SourceNode getAMongoDbCallback(DataFlow::TypeBackTracker t) {
t.start() and
result = getAMongoClient().getAMemberCall("connect").getArgument(1).getALocalSource()
or or
result = getAMongoDbCallback().getParameter(1) and exists(DataFlow::TypeBackTracker t2 | result = getAMongoDbCallback(t2).backtrack(t2, t))
not result.getAnImmediateUse().(DataFlow::ParameterNode).getName() = "client" // mongodb v3 provides a `Mongoclient` here }
/** Gets a data flow node that leads to a `connect` callback. */
private DataFlow::FunctionNode getAMongoDbCallback() {
result = getAMongoDbCallback(DataFlow::TypeBackTracker::end())
}
/**
* Gets an expression that may refer to a MongoDB database connection.
*/
private DataFlow::SourceNode getAMongoDb(DataFlow::TypeTracker t) {
t.start() and
result = getAMongoDbCallback().getParameter(1)
or
exists(DataFlow::TypeTracker t2 | result = getAMongoDb(t2).track(t2, t))
}
/**
* Gets an expression that may refer to a MongoDB database connection.
*/
DataFlow::SourceNode getAMongoDb() { result = getAMongoDb(DataFlow::TypeTracker::end()) }
/**
* A data flow node that may hold a MongoDB collection.
*/
abstract class Collection extends DataFlow::SourceNode { }
/**
* A collection resulting from calling `Db.collection(...)`.
*/
private class CollectionFromDb extends Collection {
CollectionFromDb() {
this = getAMongoDb().getAMethodCall("collection")
or
this = getAMongoDb().getAMethodCall("collection").getCallback(1).getParameter(0)
}
}
/**
* A collection based on the type `mongodb.Collection`.
*
* Note that this also covers `mongoose` models since they are subtypes
* of `mongodb.Collection`.
*/
private class CollectionFromType extends Collection {
CollectionFromType() { hasUnderlyingType("mongodb", "Collection") }
} }
/** Gets a data flow node referring to a MongoDB collection. */ /** Gets a data flow node referring to a MongoDB collection. */
private API::Node getACollection() { private DataFlow::SourceNode getACollection(DataFlow::TypeTracker t) {
// A collection resulting from calling `Db.collection(...)`. t.start() and
exists(API::Node collection | collection = getAMongoDb().getMember("collection").getReturn() | result instanceof Collection
result = collection
or
result = collection.getParameter(1).getParameter(0)
)
or or
// note that this also covers `mongoose` models since they are subtypes of `mongodb.Collection` exists(DataFlow::TypeTracker t2 | result = getACollection(t2).track(t2, t))
result = API::Node::ofType("mongodb", "Collection")
} }
/** Gets a data flow node referring to a MongoDB collection. */
DataFlow::SourceNode getACollection() { result = getACollection(DataFlow::TypeTracker::end()) }
/** A call to a MongoDB query method. */ /** A call to a MongoDB query method. */
private class QueryCall extends DatabaseAccess, API::CallNode { private class QueryCall extends DatabaseAccess, DataFlow::MethodCallNode {
int queryArgIdx; int queryArgIdx;
QueryCall() { QueryCall() {
exists(string method | exists(string m | this = getACollection().getAMethodCall(m) |
CollectionMethodSignatures::interpretsArgumentAsQuery(method, queryArgIdx) and m = "count" and queryArgIdx = 0
this = getACollection().getMember(method).getACall() or
m = "distinct" and queryArgIdx = 1
or
m = "find" and queryArgIdx = 0
) )
} }
override DataFlow::Node getAQueryArgument() { result = getArgument(queryArgIdx) } override DataFlow::Node getAQueryArgument() { result = getArgument(queryArgIdx) }
DataFlow::Node getACodeOperator() {
result = getADollarWhereProperty(getParameter(queryArgIdx))
}
} }
/** /**
* An expression that is interpreted as a MongoDB query. * An expression that is interpreted as a MongoDB query.
*/ */
class Query extends NoSQL::Query { class Query extends NoSQL::Query {
QueryCall qc; Query() { this = any(QueryCall qc).getAQueryArgument().asExpr() }
Query() { this = qc.getAQueryArgument().asExpr() }
override DataFlow::Node getACodeOperator() { result = qc.getACodeOperator() }
}
/**
* Provides signatures for the Collection methods.
*/
module CollectionMethodSignatures {
/**
* Holds if Collection method `name` interprets parameter `n` as a query.
*/
predicate interpretsArgumentAsQuery(string name, int n) {
// FilterQuery
(
name = "aggregate" and n = 0
or
name = "count" and n = 0
or
name = "countDocuments" and n = 0
or
name = "deleteMany" and n = 0
or
name = "deleteOne" and n = 0
or
name = "distinct" and n = 1
or
name = "find" and n = 0
or
name = "findOne" and n = 0
or
name = "findOneAndDelete" and n = 0
or
name = "findOneAndRemove" and n = 0
or
name = "findOneAndReplace" and n = 0
or
name = "findOneAndUpdate" and n = 0
or
name = "remove" and n = 0
or
name = "replaceOne" and n = 0
or
name = "update" and n = 0
or
name = "updateMany" and n = 0
or
name = "updateOne" and n = 0
)
or
// UpdateQuery
(
name = "findOneAndUpdate" and n = 1
or
name = "update" and n = 1
or
name = "updateMany" and n = 1
or
name = "updateOne" and n = 1
)
}
} }
} }
@@ -156,345 +130,20 @@ private module Mongoose {
/** /**
* Gets an import of Mongoose. * Gets an import of Mongoose.
*/ */
API::Node getAMongooseInstance() { result = API::moduleImport("mongoose") } DataFlow::ModuleImportNode getAMongooseInstance() { result.getPath() = "mongoose" }
/** /**
* Gets a reference to `mongoose.createConnection`. * Gets a call to `mongoose.createConnection`.
*/ */
API::Node createConnection() { result = getAMongooseInstance().getMember("createConnection") } DataFlow::CallNode createConnection() {
result = getAMongooseInstance().getAMemberCall("createConnection")
/**
* A Mongoose function.
*/
abstract private class MongooseFunction extends API::Node {
/**
* Gets the API-graph node for the result from this function (if the function returns a `Query`).
*/
abstract API::Node getQueryReturn();
/**
* Holds if this function returns a `Query` that evaluates to one or
* more Documents (`asArray` is false if it evaluates to a single
* Document).
*/
abstract predicate returnsDocumentQuery(boolean asArray);
/**
* Gets an argument that this function interprets as a query.
*/
abstract API::Node getQueryArgument();
} }
/** /**
* Provides classes modeling the Mongoose Model class * A Mongoose collection object.
*/ */
module Model { class Model extends MongoDB::Collection {
private class ModelFunction extends MongooseFunction { Model() { this = getAMongooseInstance().getAMemberCall("model") }
string methodName;
ModelFunction() { this = getModelObject().getMember(methodName) }
override API::Node getQueryReturn() {
MethodSignatures::returnsQuery(methodName) and result = this.getReturn()
}
override predicate returnsDocumentQuery(boolean asArray) {
MethodSignatures::returnsDocumentQuery(methodName, asArray)
}
override API::Node getQueryArgument() {
exists(int n |
MethodSignatures::interpretsArgumentAsQuery(methodName, n) and
result = this.getParameter(n)
)
}
}
/**
* Gets a API-graph node referring to a Mongoose Model object.
*/
private API::Node getModelObject() {
result = getAMongooseInstance().getMember("model").getReturn()
or
exists(API::Node conn | conn = createConnection().getReturn() |
result = conn.getMember("model").getReturn() or
result = conn.getMember("models").getAMember()
)
or
result = API::Node::ofType("mongoose", "Model")
}
/**
* Provides signatures for the Model methods.
*/
module MethodSignatures {
/**
* Holds if Model method `name` interprets parameter `n` as a query.
*/
predicate interpretsArgumentAsQuery(string name, int n) {
// implement lots of the MongoDB collection interface
MongoDB::CollectionMethodSignatures::interpretsArgumentAsQuery(name, n)
or
name = "find" + ["ById", "One"] + "AndUpdate" and n = 1
or
name in ["delete" + ["Many", "One"], "geoSearch", "remove", "replaceOne", "where"] and
n = 0
or
name in [
"find" + ["", "ById", "One"],
"find" + ["ById", "One"] + "And" + ["Delete", "Remove", "Update"],
"update" + ["", "Many", "One"]
] and
n = 0
}
/**
* Holds if Model method `name` returns a Query.
*/
predicate returnsQuery(string name) {
name =
[
"$where", "count", "findOne", "findOneAndDelete", "findOneAndRemove",
"findOneAndReplace", "findOneAndUpdate", "geosearch", "remove", "replaceOne", "update",
"updateMany", "countDocuments", "updateOne", "where", "deleteMany", "deleteOne", "find",
"findById", "findByIdAndDelete", "findByIdAndRemove", "findByIdAndUpdate"
]
}
/**
* Holds if Document method `name` returns a query that results in
* one or more documents, the documents are wrapped in an array
* if `asArray` is true.
*/
predicate returnsDocumentQuery(string name, boolean asArray) {
asArray = false and name = "findOne"
or
asArray = true and name = "find"
}
}
}
/**
* Provides classes modeling the Mongoose Query class
*/
module Query {
private class QueryFunction extends MongooseFunction {
string methodName;
QueryFunction() { this = getAMongooseQuery().getMember(methodName) }
override API::Node getQueryReturn() {
MethodSignatures::returnsQuery(methodName) and result = this.getReturn()
}
override predicate returnsDocumentQuery(boolean asArray) {
MethodSignatures::returnsDocumentQuery(methodName, asArray)
}
override API::Node getQueryArgument() {
exists(int n |
MethodSignatures::interpretsArgumentAsQuery(methodName, n) and
result = this.getParameter(n)
)
}
}
private class NewQueryFunction extends MongooseFunction {
NewQueryFunction() { this = getAMongooseInstance().getMember("Query") }
override API::Node getQueryReturn() { result = this.getInstance() }
override predicate returnsDocumentQuery(boolean asArray) { none() }
override API::Node getQueryArgument() { result = this.getParameter(2) }
}
/**
* Gets a data flow node referring to a Mongoose query object.
*/
API::Node getAMongooseQuery() {
result = any(MongooseFunction f).getQueryReturn()
or
result = API::Node::ofType("mongoose", "Query")
or
result =
getAMongooseQuery()
.getMember(any(string name | MethodSignatures::returnsQuery(name)))
.getReturn()
}
/**
* Provides signatures for the Query methods.
*/
module MethodSignatures {
/**
* Holds if Query method `name` interprets parameter `n` as a query.
*/
predicate interpretsArgumentAsQuery(string name, int n) {
n = 0 and
name =
[
"and", "count", "findOneAndReplace", "findOneAndUpdate", "merge", "nor", "or", "remove",
"replaceOne", "setQuery", "setUpdate", "update", "countDocuments", "updateMany",
"updateOne", "where", "deleteMany", "deleteOne", "elemMatch", "find", "findOne",
"findOneAndDelete", "findOneAndRemove"
]
or
n = 1 and
name = ["distinct", "findOneAndUpdate", "update", "updateMany", "updateOne"]
}
/**
* Holds if Query method `name` returns a Query.
*/
predicate returnsQuery(string name) {
name =
[
"$where", "J", "comment", "count", "countDocuments", "distinct", "elemMatch", "equals",
"error", "estimatedDocumentCount", "exists", "explain", "all", "find", "findById",
"findOne", "findOneAndRemove", "findOneAndUpdate", "geometry", "get", "gt", "gte",
"hint", "and", "in", "intersects", "lean", "limit", "lt", "lte", "map", "map",
"maxDistance", "maxTimeMS", "batchsize", "maxscan", "mod", "ne", "near", "nearSphere",
"nin", "or", "orFail", "polygon", "populate", "box", "read", "readConcern", "regexp",
"remove", "select", "session", "set", "setOptions", "setQuery", "setUpdate", "center",
"size", "skip", "slaveOk", "slice", "snapshot", "sort", "update", "w", "where",
"within", "centerSphere", "wtimeout", "circle", "collation"
]
}
/**
* Holds if Query method `name` returns a query that results in
* one or more documents, the documents are wrapped in an array
* if `asArray` is true.
*/
predicate returnsDocumentQuery(string name, boolean asArray) {
asArray = false and name = "findOne"
or
asArray = true and name = "find"
}
}
}
/**
* Provides classes modeling the Mongoose Document class
*/
module Document {
private class DocumentFunction extends MongooseFunction {
string methodName;
DocumentFunction() { this = getAMongooseDocument().getMember(methodName) }
override API::Node getQueryReturn() {
MethodSignatures::returnsQuery(methodName) and result = this.getReturn()
}
override predicate returnsDocumentQuery(boolean asArray) {
MethodSignatures::returnsDocumentQuery(methodName, asArray)
}
override API::Node getQueryArgument() {
exists(int n |
MethodSignatures::interpretsArgumentAsQuery(methodName, n) and
result = this.getParameter(n)
)
}
}
/**
* A Mongoose Document that is retrieved from the backing database.
*/
class RetrievedDocument extends API::Node {
RetrievedDocument() {
exists(boolean asArray, API::Node param |
exists(MongooseFunction func |
func.returnsDocumentQuery(asArray) and
param = func.getLastParameter().getParameter(1)
)
or
exists(API::Node f |
f = Query::getAMongooseQuery().getMember("then") and
param = f.getParameter(0).getParameter(0)
or
f = Query::getAMongooseQuery().getMember("exec") and
param = f.getParameter(0).getParameter(1)
|
exists(DataFlow::MethodCallNode pred |
// limitation: look at the previous method call
Query::MethodSignatures::returnsDocumentQuery(pred.getMethodName(), asArray) and
pred.getAMethodCall() = f.getACall()
)
)
|
asArray = false and this = param
or
asArray = true and
// limitation: look for direct accesses
this = param.getUnknownMember()
)
}
}
/**
* Gets a data flow node referring to a Mongoose Document object.
*/
private API::Node getAMongooseDocument() {
result instanceof RetrievedDocument
or
result = API::Node::ofType("mongoose", "Document")
or
result =
getAMongooseDocument()
.getMember(any(string name | MethodSignatures::returnsDocument(name)))
.getReturn()
}
private module MethodSignatures {
/**
* Holds if Document method `name` returns a Query.
*/
predicate returnsQuery(string name) {
// Documents are subtypes of Models
Model::MethodSignatures::returnsQuery(name) or
name = "replaceOne" or
name = "update" or
name = "updateOne"
}
/**
* Holds if Document method `name` interprets parameter `n` as a query.
*/
predicate interpretsArgumentAsQuery(string name, int n) {
// Documents are subtypes of Models
Model::MethodSignatures::interpretsArgumentAsQuery(name, n)
or
n = 0 and
(
name = "replaceOne" or
name = "update" or
name = "updateOne"
)
}
/**
* Holds if Document method `name` returns a query that results in
* one or more documents, the documents are wrapped in an array
* if `asArray` is true.
*/
predicate returnsDocumentQuery(string name, boolean asArray) {
// Documents are subtypes of Models
Model::MethodSignatures::returnsDocumentQuery(name, asArray)
}
/**
* Holds if Document method `name` returns a Document.
*/
predicate returnsDocument(string name) {
name = "depopulate" or
name = "init" or
name = "populate" or
name = "overwrite"
}
}
} }
/** /**
@@ -504,9 +153,7 @@ private module Mongoose {
string kind; string kind;
Credentials() { Credentials() {
exists(string prop | exists(string prop | this = createConnection().getOptionArgument(3, prop).asExpr() |
this = createConnection().getParameter(3).getMember(prop).getARhs().asExpr()
|
prop = "user" and kind = "user name" prop = "user" and kind = "user name"
or or
prop = "pass" and kind = "password" prop = "pass" and kind = "password"
@@ -515,222 +162,4 @@ private module Mongoose {
override string getCredentialsKind() { result = kind } override string getCredentialsKind() { result = kind }
} }
/**
* An expression that is interpreted as a (part of a) MongoDB query.
*/
class MongoDBQueryPart extends NoSQL::Query {
MongooseFunction f;
MongoDBQueryPart() { this = f.getQueryArgument().getARhs().asExpr() }
override DataFlow::Node getACodeOperator() {
result = getADollarWhereProperty(f.getQueryArgument())
}
}
/**
* An evaluation of a MongoDB query.
*/
class ShorthandQueryEvaluation extends DatabaseAccess, DataFlow::InvokeNode {
MongooseFunction f;
ShorthandQueryEvaluation() {
this = f.getACall() and
// shorthand for execution: provide a callback
exists(f.getQueryReturn()) and
exists(this.getCallback(this.getNumArgument() - 1))
}
override DataFlow::Node getAQueryArgument() {
// NB: the complete information is not easily accessible for deeply chained calls
f.getQueryArgument().getARhs() = result
}
}
class ExplicitQueryEvaluation extends DatabaseAccess {
ExplicitQueryEvaluation() {
// explicit execution using a Query method call
Query::getAMongooseQuery().getMember(["exec", "then", "catch"]).getACall() = this
}
override DataFlow::Node getAQueryArgument() {
// NB: the complete information is not easily accessible for deeply chained calls
none()
}
}
}
/**
* Provides classes modeling the Minimongo library.
*/
private module Minimongo {
/**
* Provides signatures for the Collection methods.
*/
module CollectionMethodSignatures {
/**
* Holds if Collection method `name` interprets parameter `n` as a query.
*/
predicate interpretsArgumentAsQuery(string m, int queryArgIdx) {
// implements most of the MongoDB interface
MongoDB::CollectionMethodSignatures::interpretsArgumentAsQuery(m, queryArgIdx)
}
}
/** A call to a Minimongo query method. */
private class QueryCall extends DatabaseAccess, API::CallNode {
int queryArgIdx;
QueryCall() {
exists(string m |
this =
API::moduleImport("minimongo")
.getAMember()
.getReturn()
.getAMember()
.getMember(m)
.getACall() and
CollectionMethodSignatures::interpretsArgumentAsQuery(m, queryArgIdx)
)
}
override DataFlow::Node getAQueryArgument() { result = getArgument(queryArgIdx) }
DataFlow::Node getACodeOperator() {
result = getADollarWhereProperty(getParameter(queryArgIdx))
}
}
/**
* An expression that is interpreted as a Minimongo query.
*/
class Query extends NoSQL::Query {
QueryCall qc;
Query() { this = qc.getAQueryArgument().asExpr() }
override DataFlow::Node getACodeOperator() { result = qc.getACodeOperator() }
}
}
/**
* Provides classes modeling the MarsDB library.
*/
private module MarsDB {
/** A call to a MarsDB query method. */
private class QueryCall extends DatabaseAccess, API::CallNode {
int queryArgIdx;
QueryCall() {
exists(string m |
this =
API::moduleImport("marsdb").getMember("Collection").getInstance().getMember(m).getACall() and
// implements parts of the Minimongo interface
Minimongo::CollectionMethodSignatures::interpretsArgumentAsQuery(m, queryArgIdx)
)
}
override DataFlow::Node getAQueryArgument() { result = getArgument(queryArgIdx) }
DataFlow::Node getACodeOperator() {
result = getADollarWhereProperty(getParameter(queryArgIdx))
}
}
/**
* An expression that is interpreted as a MarsDB query.
*/
class Query extends NoSQL::Query {
QueryCall qc;
Query() { this = qc.getAQueryArgument().asExpr() }
override DataFlow::Node getACodeOperator() { result = qc.getACodeOperator() }
}
}
/**
* Provides classes modeling the `Node Redis` library.
*
* Redis is an in-memory key-value store and not a database,
* but `Node Redis` can be exploited similarly to a NoSQL database by giving a method an array as argument instead of a string.
* As an example the below two invocations of `client.set` are equivalent:
*
* ```
* const redis = require("redis");
* const client = redis.createClient();
* client.set("key", "value");
* client.set(["key", "value"]);
* ```
*
* ioredis is a very similar library. However, ioredis does not support array arguments in the same way, and is therefore not vulnerable to the same kind of type confusion.
*/
private module Redis {
/**
* Gets a `Node Redis` client.
*/
private API::Node client() {
result = API::moduleImport("redis").getMember("createClient").getReturn()
or
result = API::moduleImport("redis").getMember("RedisClient").getInstance()
or
result = client().getMember("duplicate").getReturn()
or
result = client().getMember("duplicate").getLastParameter().getParameter(1)
}
/**
* Gets a (possibly chained) reference to a batch operation object.
* These have the same API as a redis client, except the calls are chained, and the sequence is terminated with a `.exec` call.
*/
private API::Node multi() {
result = client().getMember(["multi", "batch"]).getReturn()
or
result = multi().getAMember().getReturn()
}
/**
* Gets a `Node Redis` client instance. Either a client created using `createClient()`, or a batch operation object.
*/
private API::Node redis() { result = [client(), multi()] }
/**
* Provides signatures for the query methods from Node Redis.
*/
module QuerySignatures {
/**
* Holds if `method` interprets parameter `argIndex` as a key, and a later parameter determines a value/field.
* Thereby the method is vulnerable if parameter `argIndex` is unexpectedly an array instead of a string, as an attacker can control arguments to Redis that the attacker was not supposed to control.
*
* Only setters and similar methods are included.
* For getter-like methods it is not generally possible to gain access "outside" of where you are supposed to have access,
* it is at most possible to get a Redis call to return more results than expected (e.g. by adding more members to [`geohash`](https://redis.io/commands/geohash)).
*/
predicate argumentIsAmbiguousKey(string method, int argIndex) {
method =
[
"set", "publish", "append", "bitfield", "decrby", "getset", "hincrby", "hincrbyfloat",
"hset", "hsetnx", "incrby", "incrbyfloat", "linsert", "lpush", "lpushx", "lset", "ltrim",
"rename", "renamenx", "rpushx", "setbit", "setex", "smove", "zincrby", "zinterstore",
"hdel", "lpush", "pfadd", "rpush", "sadd", "sdiffstore", "srem"
] and
argIndex = 0
or
method = ["bitop", "hmset", "mset", "msetnx", "geoadd"] and
argIndex in [0 .. any(DataFlow::InvokeNode invk).getNumArgument() - 1]
}
}
/**
* An expression that is interpreted as a key in a Node Redis call.
*/
class RedisKeyArgument extends NoSQL::Query {
RedisKeyArgument() {
exists(string method, int argIndex |
QuerySignatures::argumentIsAmbiguousKey(method, argIndex) and
this = redis().getMember(method).getParameter(argIndex).getARhs().asExpr()
)
}
}
} }

View File

@@ -448,56 +448,11 @@ module NodeJSLib {
*/ */
module FS { module FS {
/** /**
* A member `member` from module `fs` or its drop-in replacements `graceful-fs`, `fs-extra`, `original-fs`. * A member `member` from module `fs`.
*/ */
DataFlow::SourceNode moduleMember(string member) { DataFlow::SourceNode moduleMember(string member) {
result = fsModule(DataFlow::TypeTracker::end()).getAPropertyRead(member) exists(string moduleName | moduleName = ["fs"] |
} result = DataFlow::moduleMember(moduleName, member)
private DataFlow::SourceNode fsModule(DataFlow::TypeTracker t) {
exists(string moduleName |
moduleName = ["mz/fs", "original-fs", "fs-extra", "graceful-fs", "fs"]
|
result = DataFlow::moduleImport(moduleName)
or
// extra support for flexible names
result.asExpr().(Require).getArgument(0).mayHaveStringValue(moduleName)
) and
t.start()
or
t.start() and
result = DataFlow::moduleMember("fs", "promises")
or
exists(DataFlow::TypeTracker t2, DataFlow::SourceNode pred | pred = fsModule(t2) |
result = pred.track(t2, t)
or
t.continue() = t2 and
exists(Promisify::PromisifyAllCall promisifyAllCall |
result = promisifyAllCall and
pred.flowsTo(promisifyAllCall.getArgument(0))
)
or
// const fs = require('fs');
// let fs_copy = methods.reduce((obj, method) => {
// obj[method] = fs[method];
// return obj;
// }, {});
t.continue() = t2 and
exists(
DataFlow::MethodCallNode call, DataFlow::ParameterNode obj, DataFlow::SourceNode method
|
call.getMethodName() = "reduce" and
result = call and
obj = call.getABoundCallbackParameter(0, 0) and
obj.flowsTo(any(DataFlow::FunctionNode f).getAReturn()) and
exists(DataFlow::PropWrite write, DataFlow::PropRead read |
write = obj.getAPropertyWrite() and
method.flowsToExpr(write.getPropertyNameExpr()) and
method.flowsToExpr(read.getPropertyNameExpr()) and
read.getBase().getALocalSource() = fsModule(t2) and
write.getRhs() = maybePromisified(read)
)
)
) )
} }
} }
@@ -508,7 +463,7 @@ module NodeJSLib {
private class NodeJSFileSystemAccess extends FileSystemAccess, DataFlow::CallNode { private class NodeJSFileSystemAccess extends FileSystemAccess, DataFlow::CallNode {
string methodName; string methodName;
NodeJSFileSystemAccess() { this = maybePromisified(FS::moduleMember(methodName)).getACall() } NodeJSFileSystemAccess() { this = FS::moduleMember(methodName).getACall() }
/** /**
* Gets the name of the called method. * Gets the name of the called method.

View File

@@ -28,54 +28,38 @@ module SQL {
* Provides classes modelling the (API compatible) `mysql` and `mysql2` packages. * Provides classes modelling the (API compatible) `mysql` and `mysql2` packages.
*/ */
private module MySql { private module MySql {
private string moduleName() { result = ["mysql", "mysql2", "mysql2/promise"] } private DataFlow::SourceNode mysql() { result = DataFlow::moduleImport(["mysql", "mysql2"]) }
/** Gets the package name `mysql` or `mysql2`. */ private DataFlow::CallNode createPool() { result = mysql().getAMemberCall("createPool") }
API::Node mysql() { result = API::moduleImport(moduleName()) }
/** Gets a reference to `mysql.createConnection`. */ /** Gets a reference to a MySQL pool. */
API::Node createConnection() { private DataFlow::SourceNode pool(DataFlow::TypeTracker t) {
result = mysql().getMember(["createConnection", "createConnectionPromise"]) t.start() and
result = createPool()
} }
/** Gets a reference to `mysql.createPool`. */ /** Gets a reference to a MySQL pool. */
API::Node createPool() { result = mysql().getMember(["createPool", "createPoolCluster"]) } private DataFlow::SourceNode pool() { result = pool(DataFlow::TypeTracker::end()) }
/** Gets a node that contains a MySQL pool created using `mysql.createPool()`. */ /** Gets a call to `mysql.createConnection`. */
API::Node pool() { DataFlow::CallNode createConnection() { result = mysql().getAMemberCall("createConnection") }
result = createPool().getReturn()
or
result = pool().getMember("on").getReturn()
or
result = API::Node::ofType(moduleName(), ["Pool", "PoolCluster"])
}
/** Gets a data flow node that contains a freshly created MySQL connection instance. */ /** Gets a reference to a MySQL connection instance. */
API::Node connection() { private DataFlow::SourceNode connection(DataFlow::TypeTracker t) {
result = createConnection().getReturn() t.start() and
or (
result = createConnection().getReturn().getPromised() result = createConnection()
or or
result = pool().getMember("getConnection").getParameter(0).getParameter(1) result = pool().getAMethodCall("getConnection").getABoundCallbackParameter(0, 1)
or
result = pool().getMember("getConnection").getPromised()
or
exists(API::CallNode call |
call = pool().getMember("on").getACall() and
call.getArgument(0).getStringValue() = ["connection", "acquire", "release"] and
result = call.getParameter(1).getParameter(0)
) )
or
result = API::Node::ofType(moduleName(), ["Connection", "PoolConnection"])
} }
/** Gets a reference to a MySQL connection instance. */
DataFlow::SourceNode connection() { result = connection(DataFlow::TypeTracker::end()) }
/** A call to the MySql `query` method. */ /** A call to the MySql `query` method. */
private class QueryCall extends DatabaseAccess, DataFlow::MethodCallNode { private class QueryCall extends DatabaseAccess, DataFlow::MethodCallNode {
QueryCall() { QueryCall() { this = [pool(), connection()].getAMethodCall("query") }
exists(API::Node recv | recv = pool() or recv = connection() |
this = recv.getMember(["query", "execute"]).getACall()
)
}
override DataFlow::Node getAQueryArgument() { result = getArgument(0) } override DataFlow::Node getAQueryArgument() { result = getArgument(0) }
} }
@@ -88,7 +72,7 @@ private module MySql {
/** A call to the `escape` or `escapeId` method that performs SQL sanitization. */ /** A call to the `escape` or `escapeId` method that performs SQL sanitization. */
class EscapingSanitizer extends SQL::SqlSanitizer, MethodCallExpr { class EscapingSanitizer extends SQL::SqlSanitizer, MethodCallExpr {
EscapingSanitizer() { EscapingSanitizer() {
this = [mysql(), pool(), connection()].getMember(["escape", "escapeId"]).getACall().asExpr() and this = [mysql(), pool(), connection()].getAMethodCall(["escape", "escapeId"]).asExpr() and
input = this.getArgument(0) and input = this.getArgument(0) and
output = this output = this
} }
@@ -99,9 +83,8 @@ private module MySql {
string kind; string kind;
Credentials() { Credentials() {
exists(API::Node callee, string prop | exists(string prop |
callee in [createConnection(), createPool()] and this = [createConnection(), createPool()].getOptionArgument(0, prop).asExpr() and
this = callee.getParameter(0).getMember(prop).getARhs().asExpr() and
( (
prop = "user" and kind = "user name" prop = "user" and kind = "user name"
or or
@@ -118,61 +101,23 @@ private module MySql {
* Provides classes modelling the PostgreSQL packages, such as `pg` and `pg-promise`. * Provides classes modelling the PostgreSQL packages, such as `pg` and `pg-promise`.
*/ */
private module Postgres { private module Postgres {
API::Node pg() { /** Gets an expression that constructs a new connection pool. */
result = API::moduleImport("pg") DataFlow::InvokeNode newPool() {
or
result = pgpMain().getMember("pg")
}
/** Gets a reference to the `Client` constructor in the `pg` package, for example `require('pg').Client`. */
API::Node newClient() { result = pg().getMember("Client") }
/** Gets a freshly created Postgres client instance. */
API::Node client() {
result = newClient().getInstance()
or
// pool.connect(function(err, client) { ... })
result = pool().getMember("connect").getParameter(0).getParameter(1)
or
// await pool.connect()
result = pool().getMember("connect").getReturn().getPromised()
or
result = pgpConnection().getMember("client")
or
exists(API::CallNode call |
call = pool().getMember("on").getACall() and
call.getArgument(0).getStringValue() = ["connect", "acquire"] and
result = call.getParameter(1).getParameter(0)
)
or
result = client().getMember("on").getReturn()
or
result = API::Node::ofType("pg", ["Client", "PoolClient"])
}
/** Gets a constructor that when invoked constructs a new connection pool. */
API::Node newPool() {
// new require('pg').Pool() // new require('pg').Pool()
result = pg().getMember("Pool") result = DataFlow::moduleImport("pg").getAConstructorInvocation("Pool")
or or
// new require('pg-pool') // new require('pg-pool')
result = API::moduleImport("pg-pool") result = DataFlow::moduleImport("pg-pool").getAnInstantiation()
} }
/** Gets an API node that refers to a connection pool. */ /** Gets a creation of a Postgres client. */
API::Node pool() { DataFlow::InvokeNode newClient() {
result = newPool().getInstance() result = DataFlow::moduleImport("pg").getAConstructorInvocation("Client")
or
result = pgpDatabase().getMember("$pool")
or
result = pool().getMember("on").getReturn()
or
result = API::Node::ofType("pg", "Pool")
} }
/** A call to the Postgres `query` method. */ /** A call to the Postgres `query` method. */
private class QueryCall extends DatabaseAccess, DataFlow::MethodCallNode { private class QueryCall extends DatabaseAccess, DataFlow::MethodCallNode {
QueryCall() { this = [client(), pool()].getMember("query").getACall() } QueryCall() { this = [newClient(), newPool()].getAMethodCall("query") }
override DataFlow::Node getAQueryArgument() { result = getArgument(0) } override DataFlow::Node getAQueryArgument() { result = getArgument(0) }
} }
@@ -191,11 +136,7 @@ private module Postgres {
string kind; string kind;
Credentials() { Credentials() {
exists(string prop | exists(string prop | this = [newClient(), newPool()].getOptionArgument(0, prop).asExpr() |
this = [newClient(), newPool()].getParameter(0).getMember(prop).getARhs().asExpr()
or
this = pgPromise().getParameter(0).getMember(prop).getARhs().asExpr()
|
prop = "user" and kind = "user name" prop = "user" and kind = "user name"
or or
prop = "password" and kind = prop prop = "password" and kind = prop
@@ -335,35 +276,30 @@ private module Postgres {
*/ */
private module Sqlite { private module Sqlite {
/** Gets a reference to the `sqlite3` module. */ /** Gets a reference to the `sqlite3` module. */
API::Node sqlite() { DataFlow::SourceNode sqlite() {
result = API::moduleImport("sqlite3") result = DataFlow::moduleImport("sqlite3")
or or
result = sqlite().getMember("verbose").getReturn() result = sqlite().getAMemberCall("verbose")
} }
/** Gets an expression that constructs or returns a Sqlite database instance. */ /** Gets an expression that constructs a Sqlite database instance. */
API::Node database() { DataFlow::SourceNode newDb() {
// new require('sqlite3').Database() // new require('sqlite3').Database()
result = sqlite().getMember("Database").getInstance() result = sqlite().getAConstructorInvocation("Database")
or
// chained call
result = getAChainingQueryCall()
or
result = API::Node::ofType("sqlite3", "Database")
} }
/** A call to a query method on a Sqlite database instance that returns the same instance. */ /** Gets a data flow node referring to a Sqlite database instance. */
private API::Node getAChainingQueryCall() { private DataFlow::SourceNode db(DataFlow::TypeTracker t) {
result = database().getMember(["all", "each", "exec", "get", "run"]).getReturn() t.start() and
result = newDb()
} }
/** Gets a data flow node referring to a Sqlite database instance. */
DataFlow::SourceNode db() { result = db(DataFlow::TypeTracker::end()) }
/** A call to a Sqlite query method. */ /** A call to a Sqlite query method. */
private class QueryCall extends DatabaseAccess, DataFlow::MethodCallNode { private class QueryCall extends DatabaseAccess, DataFlow::MethodCallNode {
QueryCall() { QueryCall() { this = db().getAMethodCall(["all", "each", "exec", "get", "prepare", "run"]) }
this = getAChainingQueryCall().getAnImmediateUse()
or
this = database().getMember("prepare").getACall()
}
override DataFlow::Node getAQueryArgument() { result = getArgument(0) } override DataFlow::Node getAQueryArgument() { result = getArgument(0) }
} }
@@ -373,276 +309,3 @@ private module Sqlite {
QueryString() { this = any(QueryCall qc).getAQueryArgument().asExpr() } QueryString() { this = any(QueryCall qc).getAQueryArgument().asExpr() }
} }
} }
/**
* Provides classes modelling the `mssql` package.
*/
private module MsSql {
/** Gets a reference to the `mssql` module. */
API::Node mssql() { result = API::moduleImport("mssql") }
/** Gets a node referring to an instance of the given class. */
API::Node mssqlClass(string name) {
result = mssql().getMember(name).getInstance()
or
result = API::Node::ofType("mssql", name)
}
/** Gets an API node referring to a Request object. */
API::Node request() {
result = mssqlClass("Request")
or
result = request().getMember(["input", "replaceInput", "output", "replaceOutput"]).getReturn()
or
result = [transaction(), pool()].getMember("request").getReturn()
}
/** Gets an API node referring to a Transaction object. */
API::Node transaction() {
result = mssqlClass("Transaction")
or
result = pool().getMember("transaction").getReturn()
}
/** Gets a API node referring to a ConnectionPool object. */
API::Node pool() { result = mssqlClass("ConnectionPool") }
/** A tagged template evaluated as a query. */
private class QueryTemplateExpr extends DatabaseAccess, DataFlow::ValueNode {
override TaggedTemplateExpr astNode;
QueryTemplateExpr() {
mssql().getMember("query").getAUse() = DataFlow::valueNode(astNode.getTag())
}
override DataFlow::Node getAQueryArgument() {
result = DataFlow::valueNode(astNode.getTemplate().getAnElement())
}
}
/** A call to a MsSql query method. */
private class QueryCall extends DatabaseAccess, DataFlow::MethodCallNode {
QueryCall() { this = [mssql(), request()].getMember(["query", "batch"]).getACall() }
override DataFlow::Node getAQueryArgument() { result = getArgument(0) }
}
/** An expression that is passed to a method that interprets it as SQL. */
class QueryString extends SQL::SqlString {
QueryString() {
exists(DatabaseAccess dba | dba instanceof QueryTemplateExpr or dba instanceof QueryCall |
this = dba.getAQueryArgument().asExpr()
)
}
}
/** An element of a query template, which is automatically sanitized. */
class QueryTemplateSanitizer extends SQL::SqlSanitizer {
QueryTemplateSanitizer() {
this = any(QueryTemplateExpr qte).getAQueryArgument().asExpr() and
input = this and
output = this
}
}
/** An expression that is passed as user name or password when creating a client or a pool. */
class Credentials extends CredentialsExpr {
string kind;
Credentials() {
exists(API::Node callee, string prop |
(
callee = mssql().getMember("connect")
or
callee = mssql().getMember("ConnectionPool")
) and
this = callee.getParameter(0).getMember(prop).getARhs().asExpr() and
(
prop = "user" and kind = "user name"
or
prop = "password" and kind = prop
)
)
}
override string getCredentialsKind() { result = kind }
}
}
/**
* Provides classes modelling the `sequelize` package.
*/
private module Sequelize {
/** Gets an import of the `sequelize` module or one that re-exports it. */
API::Node sequelize() { result = API::moduleImport(["sequelize", "sequelize-typescript"]) }
/** Gets an expression that creates an instance of the `Sequelize` class. */
API::Node instance() {
result = [sequelize(), sequelize().getMember("Sequelize")].getInstance()
or
result = API::Node::ofType(["sequelize", "sequelize-typescript"], ["Sequelize", "default"])
}
/** A call to `Sequelize.query`. */
private class QueryCall extends DatabaseAccess, DataFlow::MethodCallNode {
QueryCall() { this = instance().getMember("query").getACall() }
override DataFlow::Node getAQueryArgument() {
result = getArgument(0)
or
result = getOptionArgument(0, "query")
}
}
/** An expression that is passed to `Sequelize.query` method and hence interpreted as SQL. */
class QueryString extends SQL::SqlString {
QueryString() {
this = any(QueryCall qc).getAQueryArgument().asExpr()
or
this = sequelize().getMember(["literal", "asIs"]).getParameter(0).getARhs().asExpr()
}
}
/**
* An expression that is passed as user name or password when creating an instance of the
* `Sequelize` class.
*/
class Credentials extends CredentialsExpr {
string kind;
Credentials() {
exists(NewExpr ne, string prop |
ne = sequelize().getAnInstantiation().asExpr() and
(
this = ne.getArgument(1) and prop = "username"
or
this = ne.getArgument(2) and prop = "password"
or
ne.hasOptionArgument(ne.getNumArgument() - 1, prop, this)
) and
(
prop = "username" and kind = "user name"
or
prop = "password" and kind = prop
)
)
}
override string getCredentialsKind() { result = kind }
}
}
/**
* Provides classes modelling the Google Cloud Spanner library.
*/
private module Spanner {
/**
* Gets a node that refers to the `Spanner` class
*/
API::Node spanner() {
// older versions
result = API::moduleImport("@google-cloud/spanner")
or
// newer versions
result = API::moduleImport("@google-cloud/spanner").getMember("Spanner")
}
/**
* Gets a node that refers to an instance of the `Database` class.
*/
API::Node database() {
result =
spanner().getReturn().getMember("instance").getReturn().getMember("database").getReturn()
or
result = API::Node::ofType("@google-cloud/spanner", "Database")
}
/**
* Gets a node that refers to an instance of the `v1.SpannerClient` class.
*/
API::Node v1SpannerClient() {
result = spanner().getMember("v1").getMember("SpannerClient").getInstance()
or
result = API::Node::ofType("@google-cloud/spanner", "v1.SpannerClient")
}
/**
* Gets a node that refers to a transaction object.
*/
API::Node transaction() {
result =
database()
.getMember(["runTransaction", "runTransactionAsync"])
.getParameter([0, 1])
.getParameter(1)
or
result = API::Node::ofType("@google-cloud/spanner", "Transaction")
}
/** Gets an API node referring to a `BatchTransaction` object. */
API::Node batchTransaction() {
result = database().getMember("batchTransaction").getReturn()
or
result = database().getMember("createBatchTransaction").getReturn().getPromised()
or
result = API::Node::ofType("@google-cloud/spanner", "BatchTransaction")
}
/**
* A call to a Spanner method that executes a SQL query.
*/
abstract class SqlExecution extends DatabaseAccess, DataFlow::InvokeNode { }
/**
* A SQL execution that takes the input directly in the first argument or in the `sql` option.
*/
class SqlExecutionDirect extends SqlExecution {
SqlExecutionDirect() {
this = database().getMember(["run", "runPartitionedUpdate", "runStream"]).getACall()
or
this = transaction().getMember(["run", "runStream", "runUpdate"]).getACall()
or
this = batchTransaction().getMember("createQueryPartitions").getACall()
}
override DataFlow::Node getAQueryArgument() {
result = getArgument(0)
or
result = getOptionArgument(0, "sql")
}
}
/**
* A SQL execution that takes an array of SQL strings or { sql: string } objects.
*/
class SqlExecutionBatch extends SqlExecution, API::CallNode {
SqlExecutionBatch() { this = transaction().getMember("batchUpdate").getACall() }
override DataFlow::Node getAQueryArgument() {
// just use the whole array as the query argument, as arrays becomes tainted if one of the elements
// are tainted
result = getArgument(0)
or
result = getParameter(0).getUnknownMember().getMember("sql").getARhs()
}
}
/**
* A SQL execution that only takes the input in the `sql` option, and do not accept query strings
* directly.
*/
class SqlExecutionWithOption extends SqlExecution {
SqlExecutionWithOption() {
this = v1SpannerClient().getMember(["executeSql", "executeStreamingSql"]).getACall()
}
override DataFlow::Node getAQueryArgument() { result = getOptionArgument(0, "sql") }
}
/**
* An expression that is interpreted as a SQL string.
*/
class QueryString extends SQL::SqlString {
QueryString() { this = any(SqlExecution se).getAQueryArgument().asExpr() }
}
}

View File

@@ -36,25 +36,7 @@ module ParseTorrent {
* An access to user-controlled torrent information. * An access to user-controlled torrent information.
*/ */
class UserControlledTorrentInfo extends RemoteFlowSource { class UserControlledTorrentInfo extends RemoteFlowSource {
UserControlledTorrentInfo() { UserControlledTorrentInfo() { none() }
exists(DataFlow::SourceNode ref, DataFlow::PropRead read |
ref = parsedTorrentRef() and
read = ref.getAPropertyRead() and
this = read
|
exists(string prop |
not (
prop = "private" or
prop = "infoHash" or
prop = "length"
// "pieceLength" and "lastPieceLength" are not guaranteed to be numbers as of commit ae3ad15d
) and
read.getPropertyName() = prop
)
or
not exists(read.getPropertyName())
)
}
override string getSourceType() { result = "torrent information" } override string getSourceType() { result = "torrent information" }
} }

View File

@@ -484,8 +484,6 @@ module JQuery {
private DataFlow::SourceNode dollar(DataFlow::TypeTracker t) { private DataFlow::SourceNode dollar(DataFlow::TypeTracker t) {
t.start() and t.start() and
result = dollarSource() result = dollarSource()
or
exists(DataFlow::TypeTracker t2 | result = dollar(t2).track(t2, t))
} }
/** /**
@@ -519,14 +517,6 @@ module JQuery {
} }
} }
/**
* A `this` node in a JQuery plugin function, which is a JQuery object.
*/
private class JQueryPluginThisObject extends Range {
JQueryPluginThisObject() {
this = DataFlow::thisNode(any(JQueryPluginMethod method).getFunction())
}
}
} }
/** A source of jQuery objects from the AST-based `JQueryObject` class. */ /** A source of jQuery objects from the AST-based `JQueryObject` class. */

View File

@@ -260,6 +260,8 @@ module Stages {
exists(RemoteFlowSource r) exists(RemoteFlowSource r)
or or
exists(Exports::getALibraryInputParameter()) exists(Exports::getALibraryInputParameter())
or
any(RegExpTerm t).isUsedAsRegExp()
} }
} }
} }

View File

@@ -0,0 +1,306 @@
/**
* Provides precicates for reasoning about bad tag filter vulnerabilities.
*/
import performance.ReDoSUtil
/**
* A module for determining if a regexp matches a given string,
* and reasoning about which capture groups are filled by a given string.
*/
private module RegexpMatching {
/**
* A class to test whether a regular expression matches a string.
* Override this class and extend `test`/`testWithGroups` to configure which strings should be tested for acceptance by this regular expression.
* The result can afterwards be read from the `matches` predicate.
*
* Strings in the `testWithGroups` predicate are also tested for which capture groups are filled by the given string.
* The result is available in the `fillCaptureGroup` predicate.
*/
abstract class MatchedRegExp extends RegExpTerm {
MatchedRegExp() { this.isRootTerm() }
/**
* Holds if it should be tested whether this regular expression matches `str`.
*
* If `ignorePrefix` is true, then a regexp without a start anchor will be treated as if it had a start anchor.
* E.g. a regular expression `/foo$/` will match any string that ends with "foo",
* but if `ignorePrefix` is true, it will only match "foo".
*/
predicate test(string str, boolean ignorePrefix) {
none() // maybe overriden in subclasses
}
/**
* Same as `test(..)`, but where the `fillsCaptureGroup` afterwards tells which capture groups were filled by the given string.
*/
predicate testWithGroups(string str, boolean ignorePrefix) {
none() // maybe overriden in subclasses
}
/**
* Holds if this RegExp matches `str`, where `str` is either in the `test` or `testWithGroups` predicate.
*/
final predicate matches(string str) {
exists(State state | state = getAState(this, str.length() - 1, str, _) |
epsilonSucc*(state) = Accept(_)
)
}
/**
* Holds if matching `str` may fill capture group number `g`.
* Only holds if `str` is in the `testWithGroups` predicate.
*/
final predicate fillsCaptureGroup(string str, int g) {
exists(State s |
s = getAStateThatReachesAccept(this, _, str, _) and
g = group(s.getRepr())
)
}
}
/**
* Gets a state the regular expression `reg` can be in after matching the `i`th char in `str`.
* The regular expression is modelled as a non-determistic finite automaton,
* the regular expression can therefore be in multiple states after matching a character.
*
* It's a forward search to all possible states, and there is thus no guarantee that the state is on a path to an accepting state.
*/
private State getAState(MatchedRegExp reg, int i, string str, boolean ignorePrefix) {
// start state, the -1 position before any chars have been matched
i = -1 and
(
reg.test(str, ignorePrefix)
or
reg.testWithGroups(str, ignorePrefix)
) and
result.getRepr().getRootTerm() = reg and
isStartState(result)
or
// recursive case
result = getAStateAfterMatching(reg, _, str, i, _, ignorePrefix)
}
/**
* Gets the next state after the `prev` state from `reg`.
* `prev` is the state after matching `fromIndex` chars in `str`,
* and the result is the state after matching `toIndex` chars in `str`.
*
* This predicate is used as a step relation in the forwards search (`getAState`),
* and also as a step relation in the later backwards search (`getAStateThatReachesAccept`).
*/
private State getAStateAfterMatching(
MatchedRegExp reg, State prev, string str, int toIndex, int fromIndex, boolean ignorePrefix
) {
// the basic recursive case - outlined into a noopt helper to make performance work out.
result = getAStateAfterMatchingAux(reg, prev, str, toIndex, fromIndex, ignorePrefix)
or
// we can skip past word boundaries if the next char is a non-word char.
fromIndex = toIndex and
prev.getRepr() instanceof RegExpWordBoundary and
prev = getAState(reg, toIndex, str, ignorePrefix) and
after(prev.getRepr()) = result and
str.charAt(toIndex + 1).regexpMatch("\\W") // \W matches any non-word char.
}
pragma[noopt]
private State getAStateAfterMatchingAux(
MatchedRegExp reg, State prev, string str, int toIndex, int fromIndex, boolean ignorePrefix
) {
prev = getAState(reg, fromIndex, str, ignorePrefix) and
fromIndex = toIndex - 1 and
exists(string char | char = str.charAt(toIndex) | specializedDeltaClosed(prev, char, result)) and
not discardedPrefixStep(prev, result, ignorePrefix)
}
/** Holds if a step from `prev` to `next` should be discarded when the `ignorePrefix` flag is set. */
private predicate discardedPrefixStep(State prev, State next, boolean ignorePrefix) {
prev = mkMatch(any(RegExpRoot r)) and
ignorePrefix = true and
next = prev
}
// The `deltaClosed` relation specialized to the chars that exists in strings tested by a `MatchedRegExp`.
private predicate specializedDeltaClosed(State prev, string char, State next) {
deltaClosed(prev, specializedGetAnInputSymbolMatching(char), next)
}
// The `getAnInputSymbolMatching` relation specialized to the chars that exists in strings tested by a `MatchedRegExp`.
pragma[noinline]
private InputSymbol specializedGetAnInputSymbolMatching(string char) {
exists(string s, MatchedRegExp r |
r.test(s, _)
or
r.testWithGroups(s, _)
|
char = s.charAt(_)
) and
result = getAnInputSymbolMatching(char)
}
/**
* Gets the `i`th state on a path to the accepting state when `reg` matches `str`.
* Starts with an accepting state as found by `getAState` and searches backwards
* to the start state through the reachable states (as found by `getAState`).
*
* This predicate holds the invariant that the result state can be reached with `i` steps from a start state,
* and an accepting state can be found after (`str.length() - 1 - i`) steps from the result.
* The result state is therefore always on a valid path where `reg` accepts `str`.
*
* This predicate is only used to find which capture groups a regular expression has filled,
* and thus the search is only performed for the strings in the `testWithGroups(..)` predicate.
*/
private State getAStateThatReachesAccept(
MatchedRegExp reg, int i, string str, boolean ignorePrefix
) {
// base case, reaches an accepting state from the last state in `getAState(..)`
reg.testWithGroups(str, ignorePrefix) and
i = str.length() - 1 and
result = getAState(reg, i, str, ignorePrefix) and
epsilonSucc*(result) = Accept(_)
or
// recursive case. `next` is the next state to be matched after matching `prev`.
// this predicate is doing a backwards search, so `prev` is the result we are looking for.
exists(State next, State prev, int fromIndex, int toIndex |
next = getAStateThatReachesAccept(reg, toIndex, str, ignorePrefix) and
next = getAStateAfterMatching(reg, prev, str, toIndex, fromIndex, ignorePrefix) and
i = fromIndex and
result = prev
)
}
/** Gets the capture group number that `term` belongs to. */
private int group(RegExpTerm term) {
exists(RegExpGroup grp | grp.getNumber() = result | term.getParent*() = grp)
}
}
/** A class to test whether a regular expression matches certain HTML tags. */
class HTMLMatchingRegExp extends RegexpMatching::MatchedRegExp {
HTMLMatchingRegExp() {
// the regexp must mention "<" and ">" explicitly.
forall(string angleBracket | angleBracket = ["<", ">"] |
any(RegExpConstant term | term.getValue().matches("%" + angleBracket + "%")).getRootTerm() =
this
)
}
override predicate testWithGroups(string str, boolean ignorePrefix) {
ignorePrefix = true and
str = ["<!-- foo -->", "<!-- foo --!>", "<!- foo ->", "<foo>", "<script>"]
}
override predicate test(string str, boolean ignorePrefix) {
ignorePrefix = true and
str =
[
"<!-- foo -->", "<!- foo ->", "<!-- foo --!>", "<!-- foo\n -->", "<script>foo</script>",
"<script \n>foo</script>", "<script >foo\n</script>", "<foo ></foo>", "<foo>",
"<foo src=\"foo\"></foo>", "<script>", "<script src=\"foo\"></script>",
"<script src='foo'></script>", "<SCRIPT>foo</SCRIPT>", "<script\tsrc=\"foo\"/>",
"<script\tsrc='foo'></script>", "<sCrIpT>foo</ScRiPt>", "<script src=\"foo\">foo</script >",
"<script src=\"foo\">foo</script foo=\"bar\">", "<script src=\"foo\">foo</script\t\n bar>"
]
}
}
/**
* Holds if `regexp` matches some HTML tags, but misses some HTML tags that it should match.
*
* When adding a new case to this predicate, make sure the test string used in `matches(..)` calls are present in `HTMLMatchingRegExp::test` / `HTMLMatchingRegExp::testWithGroups`.
*/
predicate isBadRegexpFilter(HTMLMatchingRegExp regexp, string msg) {
// CVE-2021-33829 - matching both "<!-- foo -->" and "<!-- foo --!>", but in different capture groups
regexp.matches("<!-- foo -->") and
regexp.matches("<!-- foo --!>") and
exists(int a, int b | a != b |
regexp.fillsCaptureGroup("<!-- foo -->", a) and
// <!-- foo --> might be ambigously parsed (matching both capture groups), and that is ok here.
regexp.fillsCaptureGroup("<!-- foo --!>", b) and
not regexp.fillsCaptureGroup("<!-- foo --!>", a) and
msg =
"Comments ending with --> are matched differently from comments ending with --!>. The first is matched with capture group "
+ a + " and comments ending with --!> are matched with capture group " +
strictconcat(int i | regexp.fillsCaptureGroup("<!-- foo --!>", i) | i.toString(), ", ") +
"."
)
or
// CVE-2020-17480 - matching "<!-- foo -->" and other tags, but not "<!-- foo --!>".
exists(int group, int other |
group != other and
regexp.fillsCaptureGroup("<!-- foo -->", group) and
regexp.fillsCaptureGroup("<foo>", other) and
not regexp.matches("<!-- foo --!>") and
not regexp.fillsCaptureGroup("<!-- foo -->", any(int i | i != group)) and
not regexp.fillsCaptureGroup("<!- foo ->", group) and
not regexp.fillsCaptureGroup("<foo>", group) and
not regexp.fillsCaptureGroup("<script>", group) and
msg =
"This regular expression only parses --> (capture group " + group +
") and not --!> as a HTML comment end tag."
)
or
regexp.matches("<!-- foo -->") and
not regexp.matches("<!-- foo\n -->") and
not regexp.matches("<!- foo ->") and
not regexp.matches("<foo>") and
not regexp.matches("<script>") and
msg = "This regular expression does not match comments containing newlines."
or
regexp.matches("<script>foo</script>") and
regexp.matches("<script src=\"foo\"></script>") and
not regexp.matches("<foo ></foo>") and
(
not regexp.matches("<script \n>foo</script>") and
msg = "This regular expression matches <script></script>, but not <script \\n></script>"
or
not regexp.matches("<script >foo\n</script>") and
msg = "This regular expression matches <script>...</script>, but not <script >...\\n</script>"
)
or
regexp.matches("<script>foo</script>") and
regexp.matches("<script src=\"foo\"></script>") and
not regexp.matches("<script src='foo'></script>") and
not regexp.matches("<foo>") and
msg = "This regular expression does not match script tags where the attribute uses single-quotes."
or
regexp.matches("<script>foo</script>") and
regexp.matches("<script src='foo'></script>") and
not regexp.matches("<script src=\"foo\"></script>") and
not regexp.matches("<foo>") and
msg = "This regular expression does not match script tags where the attribute uses double-quotes."
or
regexp.matches("<script>foo</script>") and
regexp.matches("<script src='foo'></script>") and
not regexp.matches("<script\tsrc='foo'></script>") and
not regexp.matches("<foo>") and
not regexp.matches("<foo src=\"foo\"></foo>") and
msg = "This regular expression does not match script tags where tabs are used between attributes."
or
regexp.matches("<script>foo</script>") and
not RegExpFlags::isIgnoreCase(regexp) and
not regexp.matches("<foo>") and
not regexp.matches("<foo ></foo>") and
(
not regexp.matches("<SCRIPT>foo</SCRIPT>") and
msg = "This regular expression does not match upper case <SCRIPT> tags."
or
not regexp.matches("<sCrIpT>foo</ScRiPt>") and
regexp.matches("<SCRIPT>foo</SCRIPT>") and
msg = "This regular expression does not match mixed case <sCrIpT> tags."
)
or
regexp.matches("<script src=\"foo\"></script>") and
not regexp.matches("<foo>") and
not regexp.matches("<foo ></foo>") and
(
not regexp.matches("<script src=\"foo\">foo</script >") and
msg = "This regular expression does not match script end tags like </script >."
or
not regexp.matches("<script src=\"foo\">foo</script foo=\"bar\">") and
msg = "This regular expression does not match script end tags like </script foo=\"bar\">."
or
not regexp.matches("<script src=\"foo\">foo</script\t\n bar>") and
msg = "This regular expression does not match script end tags like </script\\t\\n bar>."
)
}

View File

@@ -172,13 +172,6 @@ module CodeInjection {
or or
callName = "setImmediate" and index = 0 callName = "setImmediate" and index = 0
) )
or
exists(DataFlow::GlobalVarRefNode wasm, string methodName |
wasm.getName() = "WebAssembly" and c = wasm.getAMemberCall(methodName)
|
methodName = "compile" or
methodName = "compileStreaming"
)
| |
this = c.getArgument(index) this = c.getArgument(index)
) )
@@ -196,9 +189,6 @@ module CodeInjection {
exists(ReactNative::WebViewElement webView | exists(ReactNative::WebViewElement webView |
// `injectedJavaScript` property of React Native `WebView` // `injectedJavaScript` property of React Native `WebView`
this = webView.getAPropertyWrite("injectedJavaScript").getRhs() this = webView.getAPropertyWrite("injectedJavaScript").getRhs()
or
// argument to `injectJavascript` method of React Native `WebView`
this = webView.getAMethodCall("injectJavaScript").getArgument(0)
) )
} }
} }
@@ -229,14 +219,8 @@ module CodeInjection {
} }
/** /**
* A code operator of a NoSQL query as a code injection sink. * The first argument to `Module.prototype._compile` from the Node.js built-in module `module`,
*/ * considered as a code-injection sink.
class NoSQLCodeInjectionSink extends Sink {
NoSQLCodeInjectionSink() { any(NoSQL::Query q).getACodeOperator() = this }
}
/**
* The first argument to `Module.prototype._compile`, considered as a code-injection sink.
*/ */
class ModuleCompileSink extends Sink { class ModuleCompileSink extends Sink {
ModuleCompileSink() { ModuleCompileSink() {
@@ -259,16 +243,6 @@ module CodeInjection {
} }
} }
/**
* A value interpreted as as template by the `pug` library.
*/
class PugTemplateSink extends TemplateSink {
PugTemplateSink() {
this =
DataFlow::moduleImport(["pug", "jade"]).getAMemberCall(["compile", "render"]).getArgument(0)
}
}
/** /**
* A value interpreted as a template by the `handlebars` library. * A value interpreted as a template by the `handlebars` library.
*/ */
@@ -287,40 +261,6 @@ module CodeInjection {
} }
} }
/**
* A value interpreted as a template by the `hogan.js` library.
*/
class HoganTemplateSink extends TemplateSink {
HoganTemplateSink() {
this = DataFlow::moduleMember("hogan.js", "compile").getACall().getArgument(0)
}
}
/**
* A value interpreted as a template by the `eta` library.
*/
class EtaTemplateSink extends TemplateSink {
EtaTemplateSink() { this = DataFlow::moduleMember("eta", "render").getACall().getArgument(0) }
}
/**
* A value interpreted as a template by the `squirrelly` library.
*/
class SquirrelTemplateSink extends TemplateSink {
SquirrelTemplateSink() {
this = DataFlow::moduleMember("squirrelly", "render").getACall().getArgument(0)
}
}
/**
* A value interpreted as a template by the `whiskers` library.
*/
class WhiskersTemplateSink extends TemplateSink {
WhiskersTemplateSink() {
this = DataFlow::moduleMember("whiskers", "render").getACall().getArgument(0)
}
}
/** /**
* A value interpreted as a template by the `dot` library. * A value interpreted as a template by the `dot` library.
*/ */

View File

@@ -55,7 +55,7 @@ module TaintedPath {
* There are currently four flow labels, representing the different combinations of * There are currently four flow labels, representing the different combinations of
* normalization and absoluteness. * normalization and absoluteness.
*/ */
abstract class PosixPath extends DataFlow::FlowLabel { class PosixPath extends DataFlow::FlowLabel {
Normalization normalization; Normalization normalization;
Relativeness relativeness; Relativeness relativeness;
@@ -113,7 +113,7 @@ module TaintedPath {
/** /**
* A flow label representing an array of path elements that may include "..". * A flow label representing an array of path elements that may include "..".
*/ */
abstract class SplitPath extends DataFlow::FlowLabel { class SplitPath extends DataFlow::FlowLabel {
SplitPath() { this = "splitPath" } SplitPath() { this = "splitPath" }
} }
} }
@@ -218,12 +218,12 @@ module TaintedPath {
output = this output = this
or or
// non-global replace or replace of something other than /\.\./g, /[/]/g, or /[\.]/g. // non-global replace or replace of something other than /\.\./g, /[/]/g, or /[\.]/g.
this instanceof StringReplaceCall and this.getCalleeName() = "replace" and
input = getReceiver() and input = getReceiver() and
output = this and output = this and
not exists(RegExpLiteral literal, RegExpTerm term | not exists(RegExpLiteral literal, RegExpTerm term |
this.(StringReplaceCall).getRegExp().asExpr() = literal and getArgument(0).getALocalSource().asExpr() = literal and
this.(StringReplaceCall).isGlobal() and literal.isGlobal() and
literal.getRoot() = term literal.getRoot() = term
| |
term.getAMatchedString() = "/" or term.getAMatchedString() = "/" or
@@ -247,15 +247,16 @@ module TaintedPath {
/** /**
* A call that removes all instances of "../" in the prefix of the string. * A call that removes all instances of "../" in the prefix of the string.
*/ */
class DotDotSlashPrefixRemovingReplace extends StringReplaceCall { class DotDotSlashPrefixRemovingReplace extends DataFlow::CallNode {
DataFlow::Node input; DataFlow::Node input;
DataFlow::Node output; DataFlow::Node output;
DotDotSlashPrefixRemovingReplace() { DotDotSlashPrefixRemovingReplace() {
this.getCalleeName() = "replace" and
input = getReceiver() and input = getReceiver() and
output = this and output = this and
exists(RegExpLiteral literal, RegExpTerm term | exists(RegExpLiteral literal, RegExpTerm term |
getRegExp().asExpr() = literal and getArgument(0).getALocalSource().asExpr() = literal and
(term instanceof RegExpStar or term instanceof RegExpPlus) and (term instanceof RegExpStar or term instanceof RegExpPlus) and
term.getChild(0) = getADotDotSlashMatcher() term.getChild(0) = getADotDotSlashMatcher()
| |
@@ -297,16 +298,17 @@ module TaintedPath {
/** /**
* A call that removes all "." or ".." from a path, without also removing all forward slashes. * A call that removes all "." or ".." from a path, without also removing all forward slashes.
*/ */
class DotRemovingReplaceCall extends StringReplaceCall { class DotRemovingReplaceCall extends DataFlow::CallNode {
DataFlow::Node input; DataFlow::Node input;
DataFlow::Node output; DataFlow::Node output;
DotRemovingReplaceCall() { DotRemovingReplaceCall() {
this.getCalleeName() = "replace" and
input = getReceiver() and input = getReceiver() and
output = this and output = this and
isGlobal() and
exists(RegExpLiteral literal, RegExpTerm term | exists(RegExpLiteral literal, RegExpTerm term |
getRegExp().asExpr() = literal and getArgument(0).getALocalSource().asExpr() = literal and
literal.isGlobal() and
literal.getRoot() = term and literal.getRoot() = term and
not term.getAMatchedString() = "/" not term.getAMatchedString() = "/"
| |
@@ -606,8 +608,6 @@ module TaintedPath {
( (
this = fileSystemAccess.getAPathArgument() and this = fileSystemAccess.getAPathArgument() and
not exists(fileSystemAccess.getRootPathArgument()) not exists(fileSystemAccess.getRootPathArgument())
or
this = fileSystemAccess.getRootPathArgument()
) and ) and
not this = any(ResolvingPathCall call).getInput() not this = any(ResolvingPathCall call).getInput()
} }
@@ -648,74 +648,6 @@ module TaintedPath {
AngularJSTemplateUrlSink() { this = any(AngularJS::CustomDirective d).getMember("templateUrl") } AngularJSTemplateUrlSink() { this = any(AngularJS::CustomDirective d).getMember("templateUrl") }
} }
/**
* The path argument of a [send](https://www.npmjs.com/package/send) call, viewed as a sink.
*/
class SendPathSink extends Sink, DataFlow::ValueNode {
SendPathSink() { this = DataFlow::moduleImport("send").getACall().getArgument(1) }
}
/**
* A path argument given to a `Page` in puppeteer, specifying where a pdf/screenshot should be saved.
*/
private class PuppeteerPath extends TaintedPath::Sink {
PuppeteerPath() {
this =
Puppeteer::page()
.getMember(["pdf", "screenshot"])
.getParameter(0)
.getMember("path")
.getARhs()
}
}
/**
* An argument given to the `prettier` library specifying the location of a config file.
*/
private class PrettierFileSink extends TaintedPath::Sink {
PrettierFileSink() {
this =
API::moduleImport("prettier")
.getMember(["resolveConfig", "resolveConfigFile", "getFileInfo"])
.getACall()
.getArgument(0)
or
this =
API::moduleImport("prettier")
.getMember("resolveConfig")
.getACall()
.getParameter(1)
.getMember("config")
.getARhs()
}
}
/**
* The `cwd` option for the `read-pkg` library.
*/
private class ReadPkgCwdSink extends TaintedPath::Sink {
ReadPkgCwdSink() {
this =
API::moduleImport("read-pkg")
.getMember(["readPackageAsync", "readPackageSync"])
.getParameter(0)
.getMember("cwd")
.getARhs()
}
}
/**
* The `cwd` option to a shell execution.
*/
private class ShellCwdSink extends TaintedPath::Sink {
ShellCwdSink() {
exists(SystemCommandExecution sys, API::Node opts |
opts.getARhs() = sys.getOptionsArg() and // assuming that an API::Node exists here.
this = opts.getMember("cwd").getARhs()
)
}
}
/** /**
* Holds if there is a step `src -> dst` mapping `srclabel` to `dstlabel` relevant for path traversal vulnerabilities. * Holds if there is a step `src -> dst` mapping `srclabel` to `dstlabel` relevant for path traversal vulnerabilities.
*/ */

View File

@@ -183,17 +183,6 @@ module DomBasedXss {
this = any(Typeahead::TypeaheadSuggestionFunction f).getAReturn() this = any(Typeahead::TypeaheadSuggestionFunction f).getAReturn()
or or
this = any(Handlebars::SafeString s).getAnArgument() this = any(Handlebars::SafeString s).getAnArgument()
or
this = any(JQuery::MethodCall call | call.getMethodName() = "jGrowl").getArgument(0)
or
// A construction of a JSDOM object (server side DOM), where scripts are allowed.
exists(DataFlow::NewNode instance |
instance = API::moduleImport("jsdom").getMember("JSDOM").getInstance().getAnImmediateUse() and
this = instance.getArgument(0) and
instance.getOptionArgument(1, "runScripts").mayHaveStringValue("dangerously")
)
or
MooTools::interpretsNodeAsHtml(this)
} }
} }

View File

@@ -542,7 +542,7 @@ private State before(RegExpTerm t) { result = Match(t, 0) }
/** /**
* Gets a state the NFA may be in after matching `t`. * Gets a state the NFA may be in after matching `t`.
*/ */
private State after(RegExpTerm t) { State after(RegExpTerm t) {
exists(RegExpAlt alt | t = alt.getAChild() | result = after(alt)) exists(RegExpAlt alt | t = alt.getAChild() | result = after(alt))
or or
exists(RegExpSequence seq, int i | t = seq.getChild(i) | exists(RegExpSequence seq, int i | t = seq.getChild(i) |
@@ -671,7 +671,7 @@ RegExpRoot getRoot(RegExpTerm term) {
/** /**
* A state in the NFA. * A state in the NFA.
*/ */
private newtype TState = newtype TState =
/** /**
* A state representing that the NFA is about to match a term. * A state representing that the NFA is about to match a term.
* `i` is used to index into multi-char literals. * `i` is used to index into multi-char literals.
@@ -801,29 +801,26 @@ InputSymbol getAnInputSymbolMatching(string char) {
result = Any() result = Any()
} }
/**
* Holds if `state` is a start state.
*/
predicate isStartState(State state) {
state = mkMatch(any(RegExpRoot r))
or
exists(RegExpCaret car | state = after(car))
}
/** /**
* Predicates for constructing a prefix string that leads to a given state. * Predicates for constructing a prefix string that leads to a given state.
*/ */
private module PrefixConstruction { private module PrefixConstruction {
/**
* Holds if `state` starts the string matched by the regular expression.
*/
private predicate isStartState(State state) {
state instanceof StateInPumpableRegexp and
(
state = Match(any(RegExpRoot r), _)
or
exists(RegExpCaret car | state = after(car))
)
}
/** /**
* Holds if `state` is the textually last start state for the regular expression. * Holds if `state` is the textually last start state for the regular expression.
*/ */
private predicate lastStartState(State state) { private predicate lastStartState(State state) {
exists(RegExpRoot root | exists(RegExpRoot root |
state = state =
max(State s, Location l | max(StateInPumpableRegexp s, Location l |
isStartState(s) and getRoot(s.getRepr()) = root and l = s.getRepr().getLocation() isStartState(s) and getRoot(s.getRepr()) = root and l = s.getRepr().getLocation()
| |
s s

View File

@@ -20,12 +20,7 @@ module RegExpFlags {
/** /**
* Holds if `root` has the `i` flag for case-insensitive matching. * Holds if `root` has the `i` flag for case-insensitive matching.
*/ */
predicate isIgnoreCase(RegExpTerm root) { predicate isIgnoreCase(RegExpTerm root) { RegExp::isIgnoreCase(getFlags(root)) }
root.isRootTerm() and
exists(DataFlow::RegExpCreationNode node | node.getRoot() = root |
RegExp::isIgnoreCase(node.getFlags())
)
}
/** /**
* Gets the flags for `root`, or the empty string if `root` has no flags. * Gets the flags for `root`, or the empty string if `root` has no flags.
@@ -38,15 +33,14 @@ module RegExpFlags {
not exists(node.getFlags()) and not exists(node.getFlags()) and
result = "" result = ""
) )
or
exists(RegExpPatternSource source | source.getRegExpTerm() = root |
result = source.getARegExpObject().(DataFlow::RegExpCreationNode).getFlags()
)
} }
/** /**
* Holds if `root` has the `s` flag for multi-line matching. * Holds if `root` has the `s` flag for multi-line matching.
*/ */
predicate isDotAll(RegExpTerm root) { predicate isDotAll(RegExpTerm root) { RegExp::isDotAll(getFlags(root)) }
root.isRootTerm() and
exists(DataFlow::RegExpCreationNode node | node.getRoot() = root |
RegExp::isDotAll(node.getFlags())
)
}
} }

View File

@@ -0,0 +1,54 @@
<!DOCTYPE qhelp PUBLIC
"-//Semmle//qhelp//EN"
"qhelp.dtd">
<qhelp>
<overview>
<p>
It is possible to match some single HTML tags using regular expressions (parsing general HTML using
regular expressions is impossible). However, if the regular expression is not written well it might
be possible to circumvent it, which can lead to cross-site scripting or other security issues.
</p>
<p>
Some of these mistakes are caused by browsers having very forgiving HTML parsers, and
will often render invalid HTML containing syntax errors.
Regular expressions that attempt to match HTML should also recognize tags containing such syntax errors.
</p>
</overview>
<recommendation>
<p>
Use a well-tested sanitization or parser library if at all possible. These libraries are much more
likely to handle corner cases correctly than a custom implementation.
</p>
</recommendation>
<example>
<p>
The following example attempts to filters out all <code>&lt;script&gt;</code> tags.
</p>
<sample src="examples/BadTagFilter.js" />
<p>
The above sanitizer does not filter out all <code>&lt;script&gt;</code> tags.
Browsers will not only accept <code>&lt;/script&gt;</code> as script end tags, but also tags such as <code>&lt;/script foo="bar"&gt;</code> even though it is a parser error.
This means that an attack string such as <code>&lt;script&gt;alert(1)&lt;/script foo="bar"&gt;</code> will not be filtered by
the function, and <code>alert(1)</code> will be executed by a browser if the string is rendered as HTML.
</p>
<p>
Other corner cases include that HTML comments can end with <code>--!&gt;</code>,
and that HTML tag names can contain upper case characters.
</p>
</example>
<references>
<li>Securitum: <a href="https://research.securitum.com/the-curious-case-of-copy-paste/">The Curious Case of Copy &amp; Paste</a>.</li>
<li>stackoverflow.com: <a href="https://stackoverflow.com/questions/1732348/regex-match-open-tags-except-xhtml-self-contained-tags#answer-1732454">You can't parse [X]HTML with regex</a>.</li>
<li>HTML Standard: <a href="https://html.spec.whatwg.org/multipage/parsing.html#comment-end-bang-state">Comment end bang state</a>.</li>
<li>stackoverflow.com: <a href="https://stackoverflow.com/questions/25559999/why-arent-browsers-strict-about-html">Why aren't browsers strict about HTML?</a>.</li>
</references>
</qhelp>

View File

@@ -0,0 +1,19 @@
/**
* @name Bad HTML filtering regexp
* @description Matching HTML tags using regular expressions is hard to do right, and can easily lead to security issues.
* @kind problem
* @problem.severity warning
* @security-severity 7.8
* @precision high
* @id js/bad-tag-filter
* @tags correctness
* security
* external/cwe/cwe-116
* external/cwe/cwe-020
*/
import semmle.javascript.security.BadTagFilterQuery
from HTMLMatchingRegExp regexp, string msg
where msg = min(string m | isBadRegexpFilter(regexp, m) | m order by m.length(), m) // there might be multiple, we arbitrarily pick the shortest one
select regexp, msg

View File

@@ -0,0 +1,8 @@
function filterScript(html) {
var scriptRegex = /<script\b[^>]*>([\s\S]*?)<\/script>/gi;
var match;
while ((match = scriptRegex.exec(html)) !== null) {
html = html.replace(match[0], match[1]);
}
return html;
}

View File

@@ -28,6 +28,7 @@
| jsonschema.js:15:23:15:29 | (a?a?)* | Strings with many repetitions of 'a' can start matching anywhere after the start of the preceeding (a?a?)*b | | jsonschema.js:15:23:15:29 | (a?a?)* | Strings with many repetitions of 'a' can start matching anywhere after the start of the preceeding (a?a?)*b |
| jsonschema.js:20:18:20:24 | (a?a?)* | Strings with many repetitions of 'a' can start matching anywhere after the start of the preceeding (a?a?)*b | | jsonschema.js:20:18:20:24 | (a?a?)* | Strings with many repetitions of 'a' can start matching anywhere after the start of the preceeding (a?a?)*b |
| lib/closure.js:4:6:4:7 | u* | Strings with many repetitions of 'u' can start matching anywhere after the start of the preceeding u*o | | lib/closure.js:4:6:4:7 | u* | Strings with many repetitions of 'u' can start matching anywhere after the start of the preceeding u*o |
| lib/indirect.js:2:6:2:7 | k* | Strings with many repetitions of 'k' can start matching anywhere after the start of the preceeding k*h |
| lib/lib.js:1:15:1:16 | a* | Strings with many repetitions of 'a' can start matching anywhere after the start of the preceeding a*b | | lib/lib.js:1:15:1:16 | a* | Strings with many repetitions of 'a' can start matching anywhere after the start of the preceeding a*b |
| lib/lib.js:8:3:8:4 | f* | Strings with many repetitions of 'f' can start matching anywhere after the start of the preceeding f*g | | lib/lib.js:8:3:8:4 | f* | Strings with many repetitions of 'f' can start matching anywhere after the start of the preceeding f*g |
| lib/moduleLib/moduleLib.js:2:3:2:4 | a* | Strings with many repetitions of 'a' can start matching anywhere after the start of the preceeding a*b | | lib/moduleLib/moduleLib.js:2:3:2:4 | a* | Strings with many repetitions of 'a' can start matching anywhere after the start of the preceeding a*b |

View File

@@ -3,6 +3,10 @@ nodes
| lib/closure.js:3:21:3:21 | x | | lib/closure.js:3:21:3:21 | x |
| lib/closure.js:4:16:4:16 | x | | lib/closure.js:4:16:4:16 | x |
| lib/closure.js:4:16:4:16 | x | | lib/closure.js:4:16:4:16 | x |
| lib/indirect.js:1:32:1:32 | x |
| lib/indirect.js:1:32:1:32 | x |
| lib/indirect.js:2:16:2:16 | x |
| lib/indirect.js:2:16:2:16 | x |
| lib/lib.js:3:28:3:31 | name | | lib/lib.js:3:28:3:31 | name |
| lib/lib.js:3:28:3:31 | name | | lib/lib.js:3:28:3:31 | name |
| lib/lib.js:4:14:4:17 | name | | lib/lib.js:4:14:4:17 | name |
@@ -170,6 +174,10 @@ edges
| lib/closure.js:3:21:3:21 | x | lib/closure.js:4:16:4:16 | x | | lib/closure.js:3:21:3:21 | x | lib/closure.js:4:16:4:16 | x |
| lib/closure.js:3:21:3:21 | x | lib/closure.js:4:16:4:16 | x | | lib/closure.js:3:21:3:21 | x | lib/closure.js:4:16:4:16 | x |
| lib/closure.js:3:21:3:21 | x | lib/closure.js:4:16:4:16 | x | | lib/closure.js:3:21:3:21 | x | lib/closure.js:4:16:4:16 | x |
| lib/indirect.js:1:32:1:32 | x | lib/indirect.js:2:16:2:16 | x |
| lib/indirect.js:1:32:1:32 | x | lib/indirect.js:2:16:2:16 | x |
| lib/indirect.js:1:32:1:32 | x | lib/indirect.js:2:16:2:16 | x |
| lib/indirect.js:1:32:1:32 | x | lib/indirect.js:2:16:2:16 | x |
| lib/lib.js:3:28:3:31 | name | lib/lib.js:4:14:4:17 | name | | lib/lib.js:3:28:3:31 | name | lib/lib.js:4:14:4:17 | name |
| lib/lib.js:3:28:3:31 | name | lib/lib.js:4:14:4:17 | name | | lib/lib.js:3:28:3:31 | name | lib/lib.js:4:14:4:17 | name |
| lib/lib.js:3:28:3:31 | name | lib/lib.js:4:14:4:17 | name | | lib/lib.js:3:28:3:31 | name | lib/lib.js:4:14:4:17 | name |
@@ -329,6 +337,7 @@ edges
| polynomial-redos.js:123:13:123:20 | replaced | polynomial-redos.js:123:3:123:20 | result | | polynomial-redos.js:123:13:123:20 | replaced | polynomial-redos.js:123:3:123:20 | result |
#select #select
| lib/closure.js:4:5:4:17 | /u*o/.test(x) | lib/closure.js:3:21:3:21 | x | lib/closure.js:4:16:4:16 | x | This $@ that depends on $@ may run slow on strings with many repetitions of 'u'. | lib/closure.js:4:6:4:7 | u* | regular expression | lib/closure.js:3:21:3:21 | x | library input | | lib/closure.js:4:5:4:17 | /u*o/.test(x) | lib/closure.js:3:21:3:21 | x | lib/closure.js:4:16:4:16 | x | This $@ that depends on $@ may run slow on strings with many repetitions of 'u'. | lib/closure.js:4:6:4:7 | u* | regular expression | lib/closure.js:3:21:3:21 | x | library input |
| lib/indirect.js:2:5:2:17 | /k*h/.test(x) | lib/indirect.js:1:32:1:32 | x | lib/indirect.js:2:16:2:16 | x | This $@ that depends on $@ may run slow on strings with many repetitions of 'k'. | lib/indirect.js:2:6:2:7 | k* | regular expression | lib/indirect.js:1:32:1:32 | x | library input |
| lib/lib.js:4:2:4:18 | regexp.test(name) | lib/lib.js:3:28:3:31 | name | lib/lib.js:4:14:4:17 | name | This $@ that depends on $@ may run slow on strings with many repetitions of 'a'. | lib/lib.js:1:15:1:16 | a* | regular expression | lib/lib.js:3:28:3:31 | name | library input | | lib/lib.js:4:2:4:18 | regexp.test(name) | lib/lib.js:3:28:3:31 | name | lib/lib.js:4:14:4:17 | name | This $@ that depends on $@ may run slow on strings with many repetitions of 'a'. | lib/lib.js:1:15:1:16 | a* | regular expression | lib/lib.js:3:28:3:31 | name | library input |
| lib/lib.js:8:2:8:17 | /f*g/.test(name) | lib/lib.js:7:19:7:22 | name | lib/lib.js:8:13:8:16 | name | This $@ that depends on $@ may run slow on strings with many repetitions of 'f'. | lib/lib.js:8:3:8:4 | f* | regular expression | lib/lib.js:7:19:7:22 | name | library input | | lib/lib.js:8:2:8:17 | /f*g/.test(name) | lib/lib.js:7:19:7:22 | name | lib/lib.js:8:13:8:16 | name | This $@ that depends on $@ may run slow on strings with many repetitions of 'f'. | lib/lib.js:8:3:8:4 | f* | regular expression | lib/lib.js:7:19:7:22 | name | library input |
| lib/moduleLib/moduleLib.js:2:2:2:17 | /a*b/.test(name) | lib/moduleLib/moduleLib.js:1:28:1:31 | name | lib/moduleLib/moduleLib.js:2:13:2:16 | name | This $@ that depends on $@ may run slow on strings with many repetitions of 'a'. | lib/moduleLib/moduleLib.js:2:3:2:4 | a* | regular expression | lib/moduleLib/moduleLib.js:1:28:1:31 | name | library input | | lib/moduleLib/moduleLib.js:2:2:2:17 | /a*b/.test(name) | lib/moduleLib/moduleLib.js:1:28:1:31 | name | lib/moduleLib/moduleLib.js:2:13:2:16 | name | This $@ that depends on $@ may run slow on strings with many repetitions of 'a'. | lib/moduleLib/moduleLib.js:2:3:2:4 | a* | regular expression | lib/moduleLib/moduleLib.js:1:28:1:31 | name | library input |

View File

@@ -0,0 +1,3 @@
module.exports.foo = function (x) {
/k*h/.test(x); // NOT OK
}

View File

@@ -12,4 +12,8 @@ if (typeof define !== 'undefined' && define.amd) { // AMD
define([], function () {return bar}); define([], function () {return bar});
} }
module.exports.closure = require("./closure") module.exports.closure = require("./closure")
module.exports.func = function (conf) {
return require("./indirect")
}

View File

@@ -0,0 +1,17 @@
| tst.js:2:6:2:29 | <script.*?>.*?<\\/script> | This regular expression does not match script end tags like </script >. |
| tst.js:3:6:3:29 | <script.*?>.*?<\\/script> | This regular expression does not match script end tags like </script >. |
| tst.js:7:6:7:16 | <!--.*--!?> | This regular expression does not match comments containing newlines. |
| tst.js:8:6:8:39 | <script.*?>(.\|\\s)*?<\\/script[^>]*> | This regular expression matches <script></script>, but not <script \\n></script> |
| tst.js:9:6:9:37 | <script[^>]*?>.*?<\\/script[^>]*> | This regular expression matches <script>...</script>, but not <script >...\\n</script> |
| tst.js:10:6:10:44 | <script(\\s\|\\w\|=\|")*?>.*?<\\/script[^>]*> | This regular expression does not match script tags where the attribute uses single-quotes. |
| tst.js:11:6:11:44 | <script(\\s\|\\w\|=\|')*?>.*?<\\/script[^>]*> | This regular expression does not match script tags where the attribute uses double-quotes. |
| tst.js:12:6:12:48 | <script( \|\\n\|\\w\|=\|'\|")*?>.*?<\\/script[^>]*> | This regular expression does not match script tags where tabs are used between attributes. |
| tst.js:13:6:13:34 | <script.*?>.*?<\\/script[^>]*> | This regular expression does not match upper case <SCRIPT> tags. |
| tst.js:14:6:14:52 | <(script\|SCRIPT).*?>.*?<\\/(script\|SCRIPT)[^>]*> | This regular expression does not match mixed case <sCrIpT> tags. |
| tst.js:15:6:15:39 | <script[^>]*?>[\\s\\S]*?<\\/script.*> | This regular expression does not match script end tags like </script\\t\\n bar>. |
| tst.js:17:6:17:40 | <script\\b[^>]*>([\\s\\S]*?)<\\/script> | This regular expression does not match script end tags like </script >. |
| tst.js:18:6:18:48 | <(?:!--([\\S\|\\s]*?)-->)\|([^\\/\\s>]+)[\\S\\s]*?> | Comments ending with --> are matched differently from comments ending with --!>. The first is matched with capture group 1 and comments ending with --!> are matched with capture group 2. |
| tst.js:19:6:19:147 | <(?:(?:\\/([^>]+)>)\|(?:!--([\\S\|\\s]*?)-->)\|(?:([^\\/\\s>]+)((?:\\s+[\\w\\-:.]+(?:\\s*=\\s*?(?:(?:"[^"]*")\|(?:'[^']*')\|[^\\s"'\\/>]+))?)*)[\\S\\s]*?(\\/?)>)) | Comments ending with --> are matched differently from comments ending with --!>. The first is matched with capture group 2 and comments ending with --!> are matched with capture group 3, 4. |
| tst.js:20:3:20:57 | (<[a-z\\/!$]("[^"]*"\|'[^']*'\|[^'">])*>\|<!(--.*?--\\s*)+>) | Comments ending with --> are matched differently from comments ending with --!>. The first is matched with capture group 3 and comments ending with --!> are matched with capture group 1. |
| tst.js:21:6:21:249 | <(?:(?:!--([\\w\\W]*?)-->)\|(?:!\\[CDATA\\[([\\w\\W]*?)\\]\\]>)\|(?:!DOCTYPE([\\w\\W]*?)>)\|(?:\\?([^\\s\\/<>]+) ?([\\w\\W]*?)[?/]>)\|(?:\\/([A-Za-z][A-Za-z0-9\\-_\\:\\.]*)>)\|(?:([A-Za-z][A-Za-z0-9\\-_\\:\\.]*)((?:\\s+[^"'>]+(?:(?:"[^"]*")\|(?:'[^']*')\|[^>]*))*\|\\/\|\\s+)>)) | This regular expression only parses --> (capture group 1) and not --!> as a HTML comment end tag. |
| tst.js:22:6:22:33 | <!--([\\w\\W]*?)-->\|<([^>]*?)> | Comments ending with --> are matched differently from comments ending with --!>. The first is matched with capture group 1 and comments ending with --!> are matched with capture group 2. |

View File

@@ -0,0 +1 @@
Security/CWE-116/BadTagFilter.ql

View File

@@ -0,0 +1,28 @@
var filters = [
/<script.*?>.*?<\/script>/i, // NOT OK - doesn't match newlines or `</script >`
/<script.*?>.*?<\/script>/is, // NOT OK - doesn't match `</script >`
/<script.*?>.*?<\/script[^>]*>/is, // OK
/<!--.*-->/is, // OK - we don't care regexps that only match comments
/<!--.*--!?>/is, // OK
/<!--.*--!?>/i, // NOT OK, does not match newlines
/<script.*?>(.|\s)*?<\/script[^>]*>/i, // NOT OK - doesn't match inside the script tag
/<script[^>]*?>.*?<\/script[^>]*>/i, // NOT OK - doesn't match newlines inside the content
/<script(\s|\w|=|")*?>.*?<\/script[^>]*>/is, // NOT OK - does not match single quotes for attribute values
/<script(\s|\w|=|')*?>.*?<\/script[^>]*>/is, // NOT OK - does not match double quotes for attribute values
/<script( |\n|\w|=|'|")*?>.*?<\/script[^>]*>/is, // NOT OK - does not match tabs between attributes
/<script.*?>.*?<\/script[^>]*>/s, // NOT OK - does not match uppercase SCRIPT tags
/<(script|SCRIPT).*?>.*?<\/(script|SCRIPT)[^>]*>/s, // NOT OK - does not match mixed case script tags
/<script[^>]*?>[\s\S]*?<\/script.*>/i, // NOT OK - doesn't match newlines in the end tag
/<script[^>]*?>[\s\S]*?<\/script[^>]*?>/i, // OK
/<script\b[^>]*>([\s\S]*?)<\/script>/gi, // NOT OK - too strict matching on the end tag
/<(?:!--([\S|\s]*?)-->)|([^\/\s>]+)[\S\s]*?>/, // NOT OK - doesn't match comments with the right capture groups
/<(?:(?:\/([^>]+)>)|(?:!--([\S|\s]*?)-->)|(?:([^\/\s>]+)((?:\s+[\w\-:.]+(?:\s*=\s*?(?:(?:"[^"]*")|(?:'[^']*')|[^\s"'\/>]+))?)*)[\S\s]*?(\/?)>))/, // NOT OK - capture groups
/(<[a-z\/!$]("[^"]*"|'[^']*'|[^'">])*>|<!(--.*?--\s*)+>)/gi, // NOT OK - capture groups
/<(?:(?:!--([\w\W]*?)-->)|(?:!\[CDATA\[([\w\W]*?)\]\]>)|(?:!DOCTYPE([\w\W]*?)>)|(?:\?([^\s\/<>]+) ?([\w\W]*?)[?/]>)|(?:\/([A-Za-z][A-Za-z0-9\-_\:\.]*)>)|(?:([A-Za-z][A-Za-z0-9\-_\:\.]*)((?:\s+[^"'>]+(?:(?:"[^"]*")|(?:'[^']*')|[^>]*))*|\/|\s+)>))/g, // NOT OK - capture groups
/<!--([\w\W]*?)-->|<([^>]*?)>/g, // NOT OK - capture groups
]
doFilters(filters)
var strip = '<script([^>]*)>([\\S\\s]*?)<\/script([^>]*)>'; // OK - it's used with the ignorecase flag
new RegExp(strip, 'gi');

View File

@@ -0,0 +1,4 @@
lgtm,codescanning
* A new query, `py/bad-tag-filter`, has been added to the query suite,
highlighting regular expressions that only match a subset of the HTML tags
it is supposed to match.

View File

@@ -467,9 +467,10 @@ class RegExpEscape extends RegExpNormalChar {
or or
this.getUnescaped() = "t" and result = "\t" this.getUnescaped() = "t" and result = "\t"
or or
// TODO: Find a way to include a formfeed character this.getUnescaped() = "f" and result = 12.toUnicode()
// this.getUnescaped() = "f" and result = " " or
// or this.getUnescaped() = "v" and result = 11.toUnicode()
or
this.isUnicode() and this.isUnicode() and
result = this.getUnicode() result = this.getUnicode()
} }
@@ -480,7 +481,7 @@ class RegExpEscape extends RegExpNormalChar {
override string getPrimaryQLClass() { result = "RegExpEscape" } override string getPrimaryQLClass() { result = "RegExpEscape" }
/** Gets the part of the term following the escape character. That is e.g. "w" if the term is "\w". */ /** Gets the part of the term following the escape character. That is e.g. "w" if the term is "\w". */
private string getUnescaped() { result = this.getText().suffix(1) } string getUnescaped() { result = this.getText().suffix(1) }
/** /**
* Gets the text for this escape. That is e.g. "\w". * Gets the text for this escape. That is e.g. "\w".
@@ -535,6 +536,13 @@ private int toHex(string hex) {
result = 15 and hex = ["f", "F"] result = 15 and hex = ["f", "F"]
} }
/**
* A word boundary, that is, a regular expression term of the form `\b`.
*/
class RegExpWordBoundary extends RegExpEscape {
RegExpWordBoundary() { this.getUnescaped() = "b" }
}
/** /**
* A character class escape in a regular expression. * A character class escape in a regular expression.
* That is, an escaped charachter that denotes multiple characters. * That is, an escaped charachter that denotes multiple characters.

View File

@@ -454,6 +454,7 @@ abstract class RegexString extends Expr {
/** Gets the number of the group in start,end */ /** Gets the number of the group in start,end */
int getGroupNumber(int start, int end) { int getGroupNumber(int start, int end) {
this.group(start, end) and this.group(start, end) and
not this.non_capturing_group_start(start, _) and
result = result =
count(int i | this.group(i, _) and i < start and not this.non_capturing_group_start(i, _)) + 1 count(int i | this.group(i, _) and i < start and not this.non_capturing_group_start(i, _)) + 1
} }

View File

@@ -0,0 +1,306 @@
/**
* Provides precicates for reasoning about bad tag filter vulnerabilities.
*/
import performance.ReDoSUtil
/**
* A module for determining if a regexp matches a given string,
* and reasoning about which capture groups are filled by a given string.
*/
private module RegexpMatching {
/**
* A class to test whether a regular expression matches a string.
* Override this class and extend `test`/`testWithGroups` to configure which strings should be tested for acceptance by this regular expression.
* The result can afterwards be read from the `matches` predicate.
*
* Strings in the `testWithGroups` predicate are also tested for which capture groups are filled by the given string.
* The result is available in the `fillCaptureGroup` predicate.
*/
abstract class MatchedRegExp extends RegExpTerm {
MatchedRegExp() { this.isRootTerm() }
/**
* Holds if it should be tested whether this regular expression matches `str`.
*
* If `ignorePrefix` is true, then a regexp without a start anchor will be treated as if it had a start anchor.
* E.g. a regular expression `/foo$/` will match any string that ends with "foo",
* but if `ignorePrefix` is true, it will only match "foo".
*/
predicate test(string str, boolean ignorePrefix) {
none() // maybe overriden in subclasses
}
/**
* Same as `test(..)`, but where the `fillsCaptureGroup` afterwards tells which capture groups were filled by the given string.
*/
predicate testWithGroups(string str, boolean ignorePrefix) {
none() // maybe overriden in subclasses
}
/**
* Holds if this RegExp matches `str`, where `str` is either in the `test` or `testWithGroups` predicate.
*/
final predicate matches(string str) {
exists(State state | state = getAState(this, str.length() - 1, str, _) |
epsilonSucc*(state) = Accept(_)
)
}
/**
* Holds if matching `str` may fill capture group number `g`.
* Only holds if `str` is in the `testWithGroups` predicate.
*/
final predicate fillsCaptureGroup(string str, int g) {
exists(State s |
s = getAStateThatReachesAccept(this, _, str, _) and
g = group(s.getRepr())
)
}
}
/**
* Gets a state the regular expression `reg` can be in after matching the `i`th char in `str`.
* The regular expression is modelled as a non-determistic finite automaton,
* the regular expression can therefore be in multiple states after matching a character.
*
* It's a forward search to all possible states, and there is thus no guarantee that the state is on a path to an accepting state.
*/
private State getAState(MatchedRegExp reg, int i, string str, boolean ignorePrefix) {
// start state, the -1 position before any chars have been matched
i = -1 and
(
reg.test(str, ignorePrefix)
or
reg.testWithGroups(str, ignorePrefix)
) and
result.getRepr().getRootTerm() = reg and
isStartState(result)
or
// recursive case
result = getAStateAfterMatching(reg, _, str, i, _, ignorePrefix)
}
/**
* Gets the next state after the `prev` state from `reg`.
* `prev` is the state after matching `fromIndex` chars in `str`,
* and the result is the state after matching `toIndex` chars in `str`.
*
* This predicate is used as a step relation in the forwards search (`getAState`),
* and also as a step relation in the later backwards search (`getAStateThatReachesAccept`).
*/
private State getAStateAfterMatching(
MatchedRegExp reg, State prev, string str, int toIndex, int fromIndex, boolean ignorePrefix
) {
// the basic recursive case - outlined into a noopt helper to make performance work out.
result = getAStateAfterMatchingAux(reg, prev, str, toIndex, fromIndex, ignorePrefix)
or
// we can skip past word boundaries if the next char is a non-word char.
fromIndex = toIndex and
prev.getRepr() instanceof RegExpWordBoundary and
prev = getAState(reg, toIndex, str, ignorePrefix) and
after(prev.getRepr()) = result and
str.charAt(toIndex + 1).regexpMatch("\\W") // \W matches any non-word char.
}
pragma[noopt]
private State getAStateAfterMatchingAux(
MatchedRegExp reg, State prev, string str, int toIndex, int fromIndex, boolean ignorePrefix
) {
prev = getAState(reg, fromIndex, str, ignorePrefix) and
fromIndex = toIndex - 1 and
exists(string char | char = str.charAt(toIndex) | specializedDeltaClosed(prev, char, result)) and
not discardedPrefixStep(prev, result, ignorePrefix)
}
/** Holds if a step from `prev` to `next` should be discarded when the `ignorePrefix` flag is set. */
private predicate discardedPrefixStep(State prev, State next, boolean ignorePrefix) {
prev = mkMatch(any(RegExpRoot r)) and
ignorePrefix = true and
next = prev
}
// The `deltaClosed` relation specialized to the chars that exists in strings tested by a `MatchedRegExp`.
private predicate specializedDeltaClosed(State prev, string char, State next) {
deltaClosed(prev, specializedGetAnInputSymbolMatching(char), next)
}
// The `getAnInputSymbolMatching` relation specialized to the chars that exists in strings tested by a `MatchedRegExp`.
pragma[noinline]
private InputSymbol specializedGetAnInputSymbolMatching(string char) {
exists(string s, MatchedRegExp r |
r.test(s, _)
or
r.testWithGroups(s, _)
|
char = s.charAt(_)
) and
result = getAnInputSymbolMatching(char)
}
/**
* Gets the `i`th state on a path to the accepting state when `reg` matches `str`.
* Starts with an accepting state as found by `getAState` and searches backwards
* to the start state through the reachable states (as found by `getAState`).
*
* This predicate holds the invariant that the result state can be reached with `i` steps from a start state,
* and an accepting state can be found after (`str.length() - 1 - i`) steps from the result.
* The result state is therefore always on a valid path where `reg` accepts `str`.
*
* This predicate is only used to find which capture groups a regular expression has filled,
* and thus the search is only performed for the strings in the `testWithGroups(..)` predicate.
*/
private State getAStateThatReachesAccept(
MatchedRegExp reg, int i, string str, boolean ignorePrefix
) {
// base case, reaches an accepting state from the last state in `getAState(..)`
reg.testWithGroups(str, ignorePrefix) and
i = str.length() - 1 and
result = getAState(reg, i, str, ignorePrefix) and
epsilonSucc*(result) = Accept(_)
or
// recursive case. `next` is the next state to be matched after matching `prev`.
// this predicate is doing a backwards search, so `prev` is the result we are looking for.
exists(State next, State prev, int fromIndex, int toIndex |
next = getAStateThatReachesAccept(reg, toIndex, str, ignorePrefix) and
next = getAStateAfterMatching(reg, prev, str, toIndex, fromIndex, ignorePrefix) and
i = fromIndex and
result = prev
)
}
/** Gets the capture group number that `term` belongs to. */
private int group(RegExpTerm term) {
exists(RegExpGroup grp | grp.getNumber() = result | term.getParent*() = grp)
}
}
/** A class to test whether a regular expression matches certain HTML tags. */
class HTMLMatchingRegExp extends RegexpMatching::MatchedRegExp {
HTMLMatchingRegExp() {
// the regexp must mention "<" and ">" explicitly.
forall(string angleBracket | angleBracket = ["<", ">"] |
any(RegExpConstant term | term.getValue().matches("%" + angleBracket + "%")).getRootTerm() =
this
)
}
override predicate testWithGroups(string str, boolean ignorePrefix) {
ignorePrefix = true and
str = ["<!-- foo -->", "<!-- foo --!>", "<!- foo ->", "<foo>", "<script>"]
}
override predicate test(string str, boolean ignorePrefix) {
ignorePrefix = true and
str =
[
"<!-- foo -->", "<!- foo ->", "<!-- foo --!>", "<!-- foo\n -->", "<script>foo</script>",
"<script \n>foo</script>", "<script >foo\n</script>", "<foo ></foo>", "<foo>",
"<foo src=\"foo\"></foo>", "<script>", "<script src=\"foo\"></script>",
"<script src='foo'></script>", "<SCRIPT>foo</SCRIPT>", "<script\tsrc=\"foo\"/>",
"<script\tsrc='foo'></script>", "<sCrIpT>foo</ScRiPt>", "<script src=\"foo\">foo</script >",
"<script src=\"foo\">foo</script foo=\"bar\">", "<script src=\"foo\">foo</script\t\n bar>"
]
}
}
/**
* Holds if `regexp` matches some HTML tags, but misses some HTML tags that it should match.
*
* When adding a new case to this predicate, make sure the test string used in `matches(..)` calls are present in `HTMLMatchingRegExp::test` / `HTMLMatchingRegExp::testWithGroups`.
*/
predicate isBadRegexpFilter(HTMLMatchingRegExp regexp, string msg) {
// CVE-2021-33829 - matching both "<!-- foo -->" and "<!-- foo --!>", but in different capture groups
regexp.matches("<!-- foo -->") and
regexp.matches("<!-- foo --!>") and
exists(int a, int b | a != b |
regexp.fillsCaptureGroup("<!-- foo -->", a) and
// <!-- foo --> might be ambigously parsed (matching both capture groups), and that is ok here.
regexp.fillsCaptureGroup("<!-- foo --!>", b) and
not regexp.fillsCaptureGroup("<!-- foo --!>", a) and
msg =
"Comments ending with --> are matched differently from comments ending with --!>. The first is matched with capture group "
+ a + " and comments ending with --!> are matched with capture group " +
strictconcat(int i | regexp.fillsCaptureGroup("<!-- foo --!>", i) | i.toString(), ", ") +
"."
)
or
// CVE-2020-17480 - matching "<!-- foo -->" and other tags, but not "<!-- foo --!>".
exists(int group, int other |
group != other and
regexp.fillsCaptureGroup("<!-- foo -->", group) and
regexp.fillsCaptureGroup("<foo>", other) and
not regexp.matches("<!-- foo --!>") and
not regexp.fillsCaptureGroup("<!-- foo -->", any(int i | i != group)) and
not regexp.fillsCaptureGroup("<!- foo ->", group) and
not regexp.fillsCaptureGroup("<foo>", group) and
not regexp.fillsCaptureGroup("<script>", group) and
msg =
"This regular expression only parses --> (capture group " + group +
") and not --!> as a HTML comment end tag."
)
or
regexp.matches("<!-- foo -->") and
not regexp.matches("<!-- foo\n -->") and
not regexp.matches("<!- foo ->") and
not regexp.matches("<foo>") and
not regexp.matches("<script>") and
msg = "This regular expression does not match comments containing newlines."
or
regexp.matches("<script>foo</script>") and
regexp.matches("<script src=\"foo\"></script>") and
not regexp.matches("<foo ></foo>") and
(
not regexp.matches("<script \n>foo</script>") and
msg = "This regular expression matches <script></script>, but not <script \\n></script>"
or
not regexp.matches("<script >foo\n</script>") and
msg = "This regular expression matches <script>...</script>, but not <script >...\\n</script>"
)
or
regexp.matches("<script>foo</script>") and
regexp.matches("<script src=\"foo\"></script>") and
not regexp.matches("<script src='foo'></script>") and
not regexp.matches("<foo>") and
msg = "This regular expression does not match script tags where the attribute uses single-quotes."
or
regexp.matches("<script>foo</script>") and
regexp.matches("<script src='foo'></script>") and
not regexp.matches("<script src=\"foo\"></script>") and
not regexp.matches("<foo>") and
msg = "This regular expression does not match script tags where the attribute uses double-quotes."
or
regexp.matches("<script>foo</script>") and
regexp.matches("<script src='foo'></script>") and
not regexp.matches("<script\tsrc='foo'></script>") and
not regexp.matches("<foo>") and
not regexp.matches("<foo src=\"foo\"></foo>") and
msg = "This regular expression does not match script tags where tabs are used between attributes."
or
regexp.matches("<script>foo</script>") and
not RegExpFlags::isIgnoreCase(regexp) and
not regexp.matches("<foo>") and
not regexp.matches("<foo ></foo>") and
(
not regexp.matches("<SCRIPT>foo</SCRIPT>") and
msg = "This regular expression does not match upper case <SCRIPT> tags."
or
not regexp.matches("<sCrIpT>foo</ScRiPt>") and
regexp.matches("<SCRIPT>foo</SCRIPT>") and
msg = "This regular expression does not match mixed case <sCrIpT> tags."
)
or
regexp.matches("<script src=\"foo\"></script>") and
not regexp.matches("<foo>") and
not regexp.matches("<foo ></foo>") and
(
not regexp.matches("<script src=\"foo\">foo</script >") and
msg = "This regular expression does not match script end tags like </script >."
or
not regexp.matches("<script src=\"foo\">foo</script foo=\"bar\">") and
msg = "This regular expression does not match script end tags like </script foo=\"bar\">."
or
not regexp.matches("<script src=\"foo\">foo</script\t\n bar>") and
msg = "This regular expression does not match script end tags like </script\\t\\n bar>."
)
}

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