From f486c44b00c5759cea34b15bf372070016b0d5bc Mon Sep 17 00:00:00 2001
From: Rasmus Lerchedahl Petersen
Date: Wed, 2 Nov 2022 16:18:36 +0100
Subject: [PATCH 001/381] python: library for inline query tests similar to the
consistency queires used in js but based on the inline expectations framework
---
.../dataflow/TestUtil/DataflowQueryTest.qll | 28 +++++++++++++++++++
1 file changed, 28 insertions(+)
create mode 100644 python/ql/test/experimental/dataflow/TestUtil/DataflowQueryTest.qll
diff --git a/python/ql/test/experimental/dataflow/TestUtil/DataflowQueryTest.qll b/python/ql/test/experimental/dataflow/TestUtil/DataflowQueryTest.qll
new file mode 100644
index 00000000000..bb3a56160f3
--- /dev/null
+++ b/python/ql/test/experimental/dataflow/TestUtil/DataflowQueryTest.qll
@@ -0,0 +1,28 @@
+import python
+import experimental.dataflow.TestUtil.FlowTest
+private import semmle.python.dataflow.new.internal.PrintNode
+
+class DataFlowQueryTest extends FlowTest {
+ DataFlowQueryTest() { this = "DataFlowQueryTest" }
+
+ override string flowTag() { result = "flow" }
+
+ override predicate relevantFlow(DataFlow::Node source, DataFlow::Node sink) {
+ exists(DataFlow::Configuration cfg | cfg.hasFlow(source, sink))
+ }
+}
+
+query predicate missingAnnotationOnSink(Location location, string error, string element) {
+ error = "ERROR, you should add `# $ MISSING: flow` annotation" and
+ exists(DataFlow::Node sink |
+ exists(DataFlow::Configuration cfg | cfg.isSink(sink)) and
+ location = sink.getLocation() and
+ element = prettyExpr(sink.asExpr()) and
+ not any(DataFlow::Configuration config).hasFlow(_, sink) and
+ not exists(FalseNegativeExpectation missingResult |
+ missingResult.getTag() = "flow" and
+ missingResult.getLocation().getFile() = location.getFile() and
+ missingResult.getLocation().getStartLine() = location.getStartLine()
+ )
+ )
+}
From 0a7cfad04892cda48d0f34bccf68269165674947 Mon Sep 17 00:00:00 2001
From: Rasmus Lerchedahl Petersen
Date: Wed, 2 Nov 2022 16:21:59 +0100
Subject: [PATCH 002/381] python: inline query tests for command injection note
how the test file is partially annotated and those annotations can now be
expressed
In this particular test file, absolute line numbers
might have been better than relative ones.
We might remove line numbers altogether,
but should check more querries to see how it looks.
---
.../DataflowQueryTest.expected | 2 ++
.../DataflowQueryTest.ql | 3 +++
.../command_injection.py | 26 +++++++++----------
3 files changed, 18 insertions(+), 13 deletions(-)
create mode 100644 python/ql/test/query-tests/Security/CWE-078-CommandInjection/DataflowQueryTest.expected
create mode 100644 python/ql/test/query-tests/Security/CWE-078-CommandInjection/DataflowQueryTest.ql
diff --git a/python/ql/test/query-tests/Security/CWE-078-CommandInjection/DataflowQueryTest.expected b/python/ql/test/query-tests/Security/CWE-078-CommandInjection/DataflowQueryTest.expected
new file mode 100644
index 00000000000..3875da4e143
--- /dev/null
+++ b/python/ql/test/query-tests/Security/CWE-078-CommandInjection/DataflowQueryTest.expected
@@ -0,0 +1,2 @@
+missingAnnotationOnSink
+failures
diff --git a/python/ql/test/query-tests/Security/CWE-078-CommandInjection/DataflowQueryTest.ql b/python/ql/test/query-tests/Security/CWE-078-CommandInjection/DataflowQueryTest.ql
new file mode 100644
index 00000000000..c69cc5c7578
--- /dev/null
+++ b/python/ql/test/query-tests/Security/CWE-078-CommandInjection/DataflowQueryTest.ql
@@ -0,0 +1,3 @@
+import python
+import experimental.dataflow.TestUtil.DataflowQueryTest
+import semmle.python.security.dataflow.CommandInjectionQuery
diff --git a/python/ql/test/query-tests/Security/CWE-078-CommandInjection/command_injection.py b/python/ql/test/query-tests/Security/CWE-078-CommandInjection/command_injection.py
index 978a2bf986c..ef8cb221ea0 100644
--- a/python/ql/test/query-tests/Security/CWE-078-CommandInjection/command_injection.py
+++ b/python/ql/test/query-tests/Security/CWE-078-CommandInjection/command_injection.py
@@ -10,27 +10,27 @@ app = Flask(__name__)
def command_injection1():
files = request.args.get('files', '')
# Don't let files be `; rm -rf /`
- os.system("ls " + files)
+ os.system("ls " + files) # $flow="ImportMember, l:-8 -> BinaryExpr"
@app.route("/command2")
def command_injection2():
files = request.args.get('files', '')
# Don't let files be `; rm -rf /`
- subprocess.Popen("ls " + files, shell=True)
+ subprocess.Popen("ls " + files, shell=True) # $flow="ImportMember, l:-15 -> BinaryExpr"
@app.route("/command3")
def first_arg_injection():
cmd = request.args.get('cmd', '')
- subprocess.Popen([cmd, "param1"])
+ subprocess.Popen([cmd, "param1"]) # $flow="ImportMember, l:-21 -> cmd"
@app.route("/other_cases")
def others():
files = request.args.get('files', '')
# Don't let files be `; rm -rf /`
- os.popen("ls " + files)
+ os.popen("ls " + files) # $flow="ImportMember, l:-28 -> BinaryExpr"
@app.route("/multiple")
@@ -38,8 +38,8 @@ def multiple():
command = request.args.get('command', '')
# We should mark flow to both calls here, which conflicts with removing flow out of
# a sink due to use-use flow.
- os.system(command)
- os.system(command)
+ os.system(command) # $flow="ImportMember, l:-36 -> command"
+ os.system(command) # $flow="ImportMember, l:-37 -> command"
@app.route("/not-into-sink-impl")
@@ -52,11 +52,11 @@ def not_into_sink_impl():
subprocess.call implementation: https://github.com/python/cpython/blob/fa7ce080175f65d678a7d5756c94f82887fc9803/Lib/subprocess.py#L341
"""
command = request.args.get('command', '')
- os.system(command)
- os.popen(command)
- subprocess.call(command)
- subprocess.check_call(command)
- subprocess.run(command)
+ os.system(command) # $flow="ImportMember, l:-50 -> command"
+ os.popen(command) # $flow="ImportMember, l:-51 -> command"
+ subprocess.call(command) # $flow="ImportMember, l:-52 -> command"
+ subprocess.check_call(command) # $flow="ImportMember, l:-53 -> command"
+ subprocess.run(command) # $flow="ImportMember, l:-54 -> command"
@app.route("/path-exists-not-sanitizer")
@@ -70,11 +70,11 @@ def path_exists_not_sanitizer():
"""
path = request.args.get('path', '')
if os.path.exists(path):
- os.system("ls " + path) # NOT OK
+ os.system("ls " + path) # $flow="ImportMember, l:-68 -> BinaryExpr"
@app.route("/restricted-characters")
def restricted_characters():
path = request.args.get('path', '')
if re.match(r'^[a-zA-Z0-9_-]+$', path):
- os.system("ls " + path) # OK (TODO: Currently FP)
+ os.system("ls " + path) # $SPURIOUS: flow="ImportMember, l:-75 -> BinaryExpr"
From 5f6cb1684b012038ed64c219822def1addd48839 Mon Sep 17 00:00:00 2001
From: erik-krogh
Date: Mon, 17 Oct 2022 16:50:29 +0200
Subject: [PATCH 003/381] move the code-injection tests into a subfolder
---
.../security/cwe-094/{ => CodeInjection}/CodeInjection.expected | 0
.../security/cwe-094/{ => CodeInjection}/CodeInjection.qlref | 0
.../security/cwe-094/{ => CodeInjection}/CodeInjection.rb | 0
3 files changed, 0 insertions(+), 0 deletions(-)
rename ruby/ql/test/query-tests/security/cwe-094/{ => CodeInjection}/CodeInjection.expected (100%)
rename ruby/ql/test/query-tests/security/cwe-094/{ => CodeInjection}/CodeInjection.qlref (100%)
rename ruby/ql/test/query-tests/security/cwe-094/{ => CodeInjection}/CodeInjection.rb (100%)
diff --git a/ruby/ql/test/query-tests/security/cwe-094/CodeInjection.expected b/ruby/ql/test/query-tests/security/cwe-094/CodeInjection/CodeInjection.expected
similarity index 100%
rename from ruby/ql/test/query-tests/security/cwe-094/CodeInjection.expected
rename to ruby/ql/test/query-tests/security/cwe-094/CodeInjection/CodeInjection.expected
diff --git a/ruby/ql/test/query-tests/security/cwe-094/CodeInjection.qlref b/ruby/ql/test/query-tests/security/cwe-094/CodeInjection/CodeInjection.qlref
similarity index 100%
rename from ruby/ql/test/query-tests/security/cwe-094/CodeInjection.qlref
rename to ruby/ql/test/query-tests/security/cwe-094/CodeInjection/CodeInjection.qlref
diff --git a/ruby/ql/test/query-tests/security/cwe-094/CodeInjection.rb b/ruby/ql/test/query-tests/security/cwe-094/CodeInjection/CodeInjection.rb
similarity index 100%
rename from ruby/ql/test/query-tests/security/cwe-094/CodeInjection.rb
rename to ruby/ql/test/query-tests/security/cwe-094/CodeInjection/CodeInjection.rb
From f1668801d3ded16ac25f190e581904b21530cdee Mon Sep 17 00:00:00 2001
From: erik-krogh
Date: Mon, 17 Oct 2022 16:52:08 +0200
Subject: [PATCH 004/381] add a `rb/unsafe-code-construction` query
rebase
---
.../UnsafeCodeConstructionCustomizations.qll | 94 +++++++++++++++++++
.../security/UnsafeCodeConstructionQuery.qll | 33 +++++++
.../cwe-094/UnsafeCodeConstruction.qhelp | 55 +++++++++++
.../cwe-094/UnsafeCodeConstruction.ql | 23 +++++
.../examples/UnsafeCodeConstruction.rb | 10 ++
.../examples/UnsafeCodeConstructionSafe.rb | 11 +++
.../UnsafeCodeConstruction.expected | 16 ++++
.../UnsafeCodeConstruction.qlref | 1 +
.../UnsafeCodeConstruction/impl/unsafeCode.rb | 19 ++++
.../unsafe-code.gemspec | 5 +
10 files changed, 267 insertions(+)
create mode 100644 ruby/ql/lib/codeql/ruby/security/UnsafeCodeConstructionCustomizations.qll
create mode 100644 ruby/ql/lib/codeql/ruby/security/UnsafeCodeConstructionQuery.qll
create mode 100644 ruby/ql/src/queries/security/cwe-094/UnsafeCodeConstruction.qhelp
create mode 100644 ruby/ql/src/queries/security/cwe-094/UnsafeCodeConstruction.ql
create mode 100644 ruby/ql/src/queries/security/cwe-094/examples/UnsafeCodeConstruction.rb
create mode 100644 ruby/ql/src/queries/security/cwe-094/examples/UnsafeCodeConstructionSafe.rb
create mode 100644 ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/UnsafeCodeConstruction.expected
create mode 100644 ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/UnsafeCodeConstruction.qlref
create mode 100644 ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/impl/unsafeCode.rb
create mode 100644 ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/unsafe-code.gemspec
diff --git a/ruby/ql/lib/codeql/ruby/security/UnsafeCodeConstructionCustomizations.qll b/ruby/ql/lib/codeql/ruby/security/UnsafeCodeConstructionCustomizations.qll
new file mode 100644
index 00000000000..188bbb34cc9
--- /dev/null
+++ b/ruby/ql/lib/codeql/ruby/security/UnsafeCodeConstructionCustomizations.qll
@@ -0,0 +1,94 @@
+/**
+ * Provides default sources, sinks and sanitizers for reasoning about
+ * code constructed from library input vulnerabilities, as
+ * well as extension points for adding your own.
+ */
+
+private import codeql.ruby.DataFlow
+private import codeql.ruby.ApiGraphs
+private import codeql.ruby.frameworks.core.Gem::Gem as Gem
+private import codeql.ruby.AST as Ast
+private import codeql.ruby.Concepts as Concepts
+
+/**
+ * Module containing sources, sinks, and sanitizers for code constructed from library input.
+ */
+module UnsafeCodeConstruction {
+ /** A source for code constructed from library input vulnerabilities. */
+ abstract class Source extends DataFlow::Node { }
+
+ /** An input parameter to a gem seen as a source. */
+ private class LibraryInputAsSource extends Source instanceof DataFlow::ParameterNode {
+ LibraryInputAsSource() { this = Gem::getALibraryInput() }
+ }
+
+ /** A sink for code constructed from library input vulnerabilities. */
+ abstract class Sink extends DataFlow::Node {
+ /**
+ * Gets the node where the unsafe code is executed.
+ */
+ abstract DataFlow::Node getCodeSink();
+
+ /**
+ * Gets the type of sink.
+ */
+ string getSinkType() { result = "code construction" }
+ }
+
+ /** Gets a node that is eventually executed as code at `codeExec`. */
+ DataFlow::Node getANodeExecutedAsCode(Concepts::CodeExecution codeExec) {
+ result = getANodeExecutedAsCode(TypeTracker::TypeBackTracker::end(), codeExec)
+ }
+
+ import codeql.ruby.typetracking.TypeTracker as TypeTracker
+
+ /** Gets a node that is eventually executed as code at `codeExec`, type-tracked with `t`. */
+ private DataFlow::LocalSourceNode getANodeExecutedAsCode(
+ TypeTracker::TypeBackTracker t, Concepts::CodeExecution codeExec
+ ) {
+ t.start() and
+ result = codeExec.getCode().getALocalSource()
+ or
+ exists(TypeTracker::TypeBackTracker t2 |
+ result = getANodeExecutedAsCode(t2, codeExec).backtrack(t2, t)
+ )
+ }
+
+ /**
+ * A string constructed from a string-literal (e.g. `"foo #{sink}"`),
+ * where the resulting string ends up being executed as a code.
+ */
+ class StringFormatAsSink extends Sink {
+ Concepts::CodeExecution s;
+ Ast::StringLiteral lit;
+
+ StringFormatAsSink() {
+ any(DataFlow::Node n | n.asExpr().getExpr() = lit) = getANodeExecutedAsCode(s) and
+ this.asExpr().getExpr() = lit.getComponent(_)
+ }
+
+ override DataFlow::Node getCodeSink() { result = s }
+
+ override string getSinkType() { result = "string interpolation" }
+ }
+
+ import codeql.ruby.security.TaintedFormatStringSpecific as TaintedFormat
+
+ /**
+ * A string constructed from a printf-style call,
+ * where the resulting string ends up being executed as a code.
+ */
+ class TaintedFormatStringAsSink extends Sink {
+ Concepts::CodeExecution s;
+ TaintedFormat::PrintfStyleCall call;
+
+ TaintedFormatStringAsSink() {
+ call = getANodeExecutedAsCode(s) and
+ this = [call.getFormatArgument(_), call.getFormatString()]
+ }
+
+ override DataFlow::Node getCodeSink() { result = s }
+
+ override string getSinkType() { result = "string format" }
+ }
+}
diff --git a/ruby/ql/lib/codeql/ruby/security/UnsafeCodeConstructionQuery.qll b/ruby/ql/lib/codeql/ruby/security/UnsafeCodeConstructionQuery.qll
new file mode 100644
index 00000000000..4b27a258716
--- /dev/null
+++ b/ruby/ql/lib/codeql/ruby/security/UnsafeCodeConstructionQuery.qll
@@ -0,0 +1,33 @@
+/**
+ * Provides a taint-tracking configuration for reasoning about code
+ * constructed from library input vulnerabilities.
+ *
+ * Note, for performance reasons: only import this file if `Configuration` is needed,
+ * otherwise `UnsafeCodeConstructionCustomizations` should be imported instead.
+ */
+
+import codeql.ruby.DataFlow
+import UnsafeCodeConstructionCustomizations::UnsafeCodeConstruction
+private import codeql.ruby.TaintTracking
+private import codeql.ruby.dataflow.BarrierGuards
+
+/**
+ * A taint-tracking configuration for detecting shell command constructed from library input vulnerabilities.
+ */
+class Configuration extends TaintTracking::Configuration {
+ Configuration() { this = "UnsafeShellCommandConstruction" }
+
+ override predicate isSource(DataFlow::Node source) { source instanceof Source }
+
+ override predicate isSink(DataFlow::Node sink) { sink instanceof Sink }
+
+ override predicate isSanitizer(DataFlow::Node node) {
+ node instanceof StringConstCompareBarrier or
+ node instanceof StringConstArrayInclusionCallBarrier
+ }
+
+ // override to require the path doesn't have unmatched return steps
+ override DataFlow::FlowFeature getAFeature() {
+ result instanceof DataFlow::FeatureHasSourceCallContext
+ }
+}
diff --git a/ruby/ql/src/queries/security/cwe-094/UnsafeCodeConstruction.qhelp b/ruby/ql/src/queries/security/cwe-094/UnsafeCodeConstruction.qhelp
new file mode 100644
index 00000000000..c430259b029
--- /dev/null
+++ b/ruby/ql/src/queries/security/cwe-094/UnsafeCodeConstruction.qhelp
@@ -0,0 +1,55 @@
+
+
+
+
+
+When a library function dynamically constructs code in a potentially unsafe way, then
+it's important to document to clients of the library that the function should only be
+used with trusted inputs.
+
+If the function is not documented as being potentially unsafe, then a client may
+incorrectly use inputs containing unsafe code fragments, and thereby leave the
+client vulnerable to code-injection attacks.
+
+
+
+
+
+
+Properly document library functions that construct code from unsanitized
+inputs, or avoid constructing code in the first place.
+
+
+
+
+
+The following example shows two methods implemented using `eval`: a simple
+deserialization routine and a getter method.
+If untrusted inputs are used with these methods,
+then an attacker might be able to execute arbitrary code on the system.
+
+
+
+
+
+To avoid this problem, either properly document that the function is potentially
+unsafe, or use an alternative solution such as `JSON.parse` or another library, like in the examples below,
+that does not allow arbitrary code to be executed.
+
+
+
diff --git a/ruby/ql/src/queries/security/cwe-094/UnsafeCodeConstruction.ql b/ruby/ql/src/queries/security/cwe-094/UnsafeCodeConstruction.ql
new file mode 100644
index 00000000000..6b7b923e934
--- /dev/null
+++ b/ruby/ql/src/queries/security/cwe-094/UnsafeCodeConstruction.ql
@@ -0,0 +1,23 @@
+/**
+ * @name Unsafe code constructed from library input
+ * @description Using externally controlled strings to construct code may allow a malicious
+ * user to execute arbitrary code.
+ * @kind path-problem
+ * @problem.severity warning
+ * @security-severity 6.1
+ * @precision medium
+ * @id rb/unsafe-code-construction
+ * @tags security
+ * external/cwe/cwe-094
+ * external/cwe/cwe-079
+ * external/cwe/cwe-116
+ */
+
+import codeql.ruby.security.UnsafeCodeConstructionQuery
+import DataFlow::PathGraph
+
+from Configuration cfg, DataFlow::PathNode source, DataFlow::PathNode sink, Sink sinkNode
+where cfg.hasFlowPath(source, sink) and sinkNode = sink.getNode()
+select sink.getNode(), source, sink,
+ "This " + sinkNode.getSinkType() + " which depends on $@ is later $@.", source.getNode(),
+ "library input", sinkNode.getCodeSink(), "interpreted as code"
diff --git a/ruby/ql/src/queries/security/cwe-094/examples/UnsafeCodeConstruction.rb b/ruby/ql/src/queries/security/cwe-094/examples/UnsafeCodeConstruction.rb
new file mode 100644
index 00000000000..d900a950a50
--- /dev/null
+++ b/ruby/ql/src/queries/security/cwe-094/examples/UnsafeCodeConstruction.rb
@@ -0,0 +1,10 @@
+module MyLib
+ def unsafeDeserialize(value)
+ eval("foo = #{value}")
+ foo
+ end
+
+ def unsafeGetter(obj, path)
+ eval("obj.#{path}")
+ end
+end
diff --git a/ruby/ql/src/queries/security/cwe-094/examples/UnsafeCodeConstructionSafe.rb b/ruby/ql/src/queries/security/cwe-094/examples/UnsafeCodeConstructionSafe.rb
new file mode 100644
index 00000000000..aa2445ae234
--- /dev/null
+++ b/ruby/ql/src/queries/security/cwe-094/examples/UnsafeCodeConstructionSafe.rb
@@ -0,0 +1,11 @@
+require 'json'
+
+module MyLib
+ def safeDeserialize(value)
+ JSON.parse(value)
+ end
+
+ def safeGetter(obj, path)
+ obj.dig(*path.split("."))
+ end
+end
diff --git a/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/UnsafeCodeConstruction.expected b/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/UnsafeCodeConstruction.expected
new file mode 100644
index 00000000000..56fc308e99d
--- /dev/null
+++ b/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/UnsafeCodeConstruction.expected
@@ -0,0 +1,16 @@
+edges
+| impl/unsafeCode.rb:2:12:2:17 | target : | impl/unsafeCode.rb:3:17:3:25 | #{...} |
+| impl/unsafeCode.rb:7:12:7:12 | x : | impl/unsafeCode.rb:8:30:8:30 | x |
+| impl/unsafeCode.rb:12:12:12:12 | x : | impl/unsafeCode.rb:13:33:13:33 | x |
+nodes
+| impl/unsafeCode.rb:2:12:2:17 | target : | semmle.label | target : |
+| impl/unsafeCode.rb:3:17:3:25 | #{...} | semmle.label | #{...} |
+| impl/unsafeCode.rb:7:12:7:12 | x : | semmle.label | x : |
+| impl/unsafeCode.rb:8:30:8:30 | x | semmle.label | x |
+| impl/unsafeCode.rb:12:12:12:12 | x : | semmle.label | x : |
+| impl/unsafeCode.rb:13:33:13:33 | x | semmle.label | x |
+subpaths
+#select
+| impl/unsafeCode.rb:3:17:3:25 | #{...} | impl/unsafeCode.rb:2:12:2:17 | target : | impl/unsafeCode.rb:3:17:3:25 | #{...} | This string interpolation which depends on $@ is later $@. | impl/unsafeCode.rb:2:12:2:17 | target | library input | impl/unsafeCode.rb:3:5:3:27 | call to eval | interpreted as code |
+| impl/unsafeCode.rb:8:30:8:30 | x | impl/unsafeCode.rb:7:12:7:12 | x : | impl/unsafeCode.rb:8:30:8:30 | x | This string format which depends on $@ is later $@. | impl/unsafeCode.rb:7:12:7:12 | x | library input | impl/unsafeCode.rb:8:5:8:32 | call to eval | interpreted as code |
+| impl/unsafeCode.rb:13:33:13:33 | x | impl/unsafeCode.rb:12:12:12:12 | x : | impl/unsafeCode.rb:13:33:13:33 | x | This string format which depends on $@ is later $@. | impl/unsafeCode.rb:12:12:12:12 | x | library input | impl/unsafeCode.rb:13:5:13:35 | call to eval | interpreted as code |
diff --git a/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/UnsafeCodeConstruction.qlref b/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/UnsafeCodeConstruction.qlref
new file mode 100644
index 00000000000..ec336901db5
--- /dev/null
+++ b/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/UnsafeCodeConstruction.qlref
@@ -0,0 +1 @@
+queries/security/cwe-094/UnsafeCodeConstruction.ql
\ No newline at end of file
diff --git a/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/impl/unsafeCode.rb b/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/impl/unsafeCode.rb
new file mode 100644
index 00000000000..4ee84d07ad2
--- /dev/null
+++ b/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/impl/unsafeCode.rb
@@ -0,0 +1,19 @@
+class Foobar
+ def foo1(target)
+ eval("foo = #{target}") # NOT OK
+ end
+
+ # sprintf
+ def foo2(x)
+ eval(sprintf("foo = %s", x)) # NOT OK
+ end
+
+ # String#%
+ def foo3(x)
+ eval("foo = %{foo}" % {foo: x}) # NOT OK
+ end
+
+ def indirect_eval(x)
+ eval(x) # OK - no construction.
+ end
+end
diff --git a/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/unsafe-code.gemspec b/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/unsafe-code.gemspec
new file mode 100644
index 00000000000..ab9639a5fc6
--- /dev/null
+++ b/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/unsafe-code.gemspec
@@ -0,0 +1,5 @@
+Gem::Specification.new do |s|
+ s.name = 'unsafe-code'
+ s.require_path = "impl"
+ end
+
\ No newline at end of file
From e7c6571f5240dde63851c808d56348f0b7a55866 Mon Sep 17 00:00:00 2001
From: erik-krogh
Date: Mon, 17 Oct 2022 21:00:59 +0200
Subject: [PATCH 005/381] remove the "send(..)" and similar from
unsafe-code-construction
---
.../ruby/security/UnsafeCodeConstructionCustomizations.qll | 3 ++-
.../cwe-094/UnsafeCodeConstruction/impl/unsafeCode.rb | 4 ++++
2 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/ruby/ql/lib/codeql/ruby/security/UnsafeCodeConstructionCustomizations.qll b/ruby/ql/lib/codeql/ruby/security/UnsafeCodeConstructionCustomizations.qll
index 188bbb34cc9..07ca5978a8a 100644
--- a/ruby/ql/lib/codeql/ruby/security/UnsafeCodeConstructionCustomizations.qll
+++ b/ruby/ql/lib/codeql/ruby/security/UnsafeCodeConstructionCustomizations.qll
@@ -47,7 +47,8 @@ module UnsafeCodeConstruction {
TypeTracker::TypeBackTracker t, Concepts::CodeExecution codeExec
) {
t.start() and
- result = codeExec.getCode().getALocalSource()
+ result = codeExec.getCode().getALocalSource() and
+ codeExec.runsArbitraryCode() // methods like `Object.send` is benign here, because of the string-construction the attacker cannot control the entire method name
or
exists(TypeTracker::TypeBackTracker t2 |
result = getANodeExecutedAsCode(t2, codeExec).backtrack(t2, t)
diff --git a/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/impl/unsafeCode.rb b/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/impl/unsafeCode.rb
index 4ee84d07ad2..30bf04bab84 100644
--- a/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/impl/unsafeCode.rb
+++ b/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/impl/unsafeCode.rb
@@ -16,4 +16,8 @@ class Foobar
def indirect_eval(x)
eval(x) # OK - no construction.
end
+
+ def send_stuff(x)
+ foo.send("foo_#{x}") # OK - attacker cannot control entire string.
+ end
end
From 2033dd2dcc96ef903bceba0aa9a7de7165416b40 Mon Sep 17 00:00:00 2001
From: erik-krogh
Date: Tue, 18 Oct 2022 12:35:30 +0200
Subject: [PATCH 006/381] remove parameters named "code" as source
---
.../ruby/security/UnsafeCodeConstructionCustomizations.qll | 5 ++++-
.../cwe-094/UnsafeCodeConstruction/impl/unsafeCode.rb | 4 ++++
2 files changed, 8 insertions(+), 1 deletion(-)
diff --git a/ruby/ql/lib/codeql/ruby/security/UnsafeCodeConstructionCustomizations.qll b/ruby/ql/lib/codeql/ruby/security/UnsafeCodeConstructionCustomizations.qll
index 07ca5978a8a..fe261de3dca 100644
--- a/ruby/ql/lib/codeql/ruby/security/UnsafeCodeConstructionCustomizations.qll
+++ b/ruby/ql/lib/codeql/ruby/security/UnsafeCodeConstructionCustomizations.qll
@@ -19,7 +19,10 @@ module UnsafeCodeConstruction {
/** An input parameter to a gem seen as a source. */
private class LibraryInputAsSource extends Source instanceof DataFlow::ParameterNode {
- LibraryInputAsSource() { this = Gem::getALibraryInput() }
+ LibraryInputAsSource() {
+ this = Gem::getALibraryInput() and
+ not this.getName() = "code"
+ }
}
/** A sink for code constructed from library input vulnerabilities. */
diff --git a/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/impl/unsafeCode.rb b/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/impl/unsafeCode.rb
index 30bf04bab84..d7d720d5d32 100644
--- a/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/impl/unsafeCode.rb
+++ b/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/impl/unsafeCode.rb
@@ -20,4 +20,8 @@ class Foobar
def send_stuff(x)
foo.send("foo_#{x}") # OK - attacker cannot control entire string.
end
+
+ def named_code(code)
+ foo.send("def \n #{code} \n end") # OK - parameter is named code
+ end
end
From 0f2a48f461ea33962bb9477cf7fbbbc0a4efedb9 Mon Sep 17 00:00:00 2001
From: erik-krogh
Date: Tue, 18 Oct 2022 12:37:50 +0200
Subject: [PATCH 007/381] fix QL-for-QL warnings
---
.../UnsafeCodeConstructionCustomizations.qll | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)
diff --git a/ruby/ql/lib/codeql/ruby/security/UnsafeCodeConstructionCustomizations.qll b/ruby/ql/lib/codeql/ruby/security/UnsafeCodeConstructionCustomizations.qll
index fe261de3dca..6a03718808c 100644
--- a/ruby/ql/lib/codeql/ruby/security/UnsafeCodeConstructionCustomizations.qll
+++ b/ruby/ql/lib/codeql/ruby/security/UnsafeCodeConstructionCustomizations.qll
@@ -64,11 +64,12 @@ module UnsafeCodeConstruction {
*/
class StringFormatAsSink extends Sink {
Concepts::CodeExecution s;
- Ast::StringLiteral lit;
StringFormatAsSink() {
- any(DataFlow::Node n | n.asExpr().getExpr() = lit) = getANodeExecutedAsCode(s) and
- this.asExpr().getExpr() = lit.getComponent(_)
+ exists(Ast::StringLiteral lit |
+ any(DataFlow::Node n | n.asExpr().getExpr() = lit) = getANodeExecutedAsCode(s) and
+ this.asExpr().getExpr() = lit.getComponent(_)
+ )
}
override DataFlow::Node getCodeSink() { result = s }
@@ -84,11 +85,12 @@ module UnsafeCodeConstruction {
*/
class TaintedFormatStringAsSink extends Sink {
Concepts::CodeExecution s;
- TaintedFormat::PrintfStyleCall call;
TaintedFormatStringAsSink() {
- call = getANodeExecutedAsCode(s) and
- this = [call.getFormatArgument(_), call.getFormatString()]
+ exists(TaintedFormat::PrintfStyleCall call |
+ call = getANodeExecutedAsCode(s) and
+ this = [call.getFormatArgument(_), call.getFormatString()]
+ )
}
override DataFlow::Node getCodeSink() { result = s }
From 3461404bbba7d417779eec305cdfcc3a13bb9112 Mon Sep 17 00:00:00 2001
From: erik-krogh
Date: Thu, 24 Nov 2022 17:35:27 +0100
Subject: [PATCH 008/381] add basic support for arrays
---
.../UnsafeCodeConstructionCustomizations.qll | 22 +++++++++++++++++--
.../UnsafeCodeConstruction.expected | 4 ++++
.../UnsafeCodeConstruction/impl/unsafeCode.rb | 7 ++++++
3 files changed, 31 insertions(+), 2 deletions(-)
diff --git a/ruby/ql/lib/codeql/ruby/security/UnsafeCodeConstructionCustomizations.qll b/ruby/ql/lib/codeql/ruby/security/UnsafeCodeConstructionCustomizations.qll
index 6a03718808c..559a21f761a 100644
--- a/ruby/ql/lib/codeql/ruby/security/UnsafeCodeConstructionCustomizations.qll
+++ b/ruby/ql/lib/codeql/ruby/security/UnsafeCodeConstructionCustomizations.qll
@@ -4,10 +4,9 @@
* well as extension points for adding your own.
*/
-private import codeql.ruby.DataFlow
+private import ruby
private import codeql.ruby.ApiGraphs
private import codeql.ruby.frameworks.core.Gem::Gem as Gem
-private import codeql.ruby.AST as Ast
private import codeql.ruby.Concepts as Concepts
/**
@@ -58,6 +57,25 @@ module UnsafeCodeConstruction {
)
}
+ /**
+ * A string constructed using a `.join(...)` call, where the resulting string ends up being executed as code.
+ */
+ class ArrayJoin extends Sink {
+ Concepts::CodeExecution s;
+ DataFlow::CallNode call;
+
+ ArrayJoin() {
+ call.getMethodName() = "join" and
+ call.getNumberOfArguments() = 1 and // any string. E.g. ";" or "\n".
+ call = getANodeExecutedAsCode(s) and
+ this = call.getReceiver()
+ }
+
+ override DataFlow::Node getCodeSink() { result = s }
+
+ override string getSinkType() { result = "array" }
+ }
+
/**
* A string constructed from a string-literal (e.g. `"foo #{sink}"`),
* where the resulting string ends up being executed as a code.
diff --git a/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/UnsafeCodeConstruction.expected b/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/UnsafeCodeConstruction.expected
index 56fc308e99d..1f4d4e33719 100644
--- a/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/UnsafeCodeConstruction.expected
+++ b/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/UnsafeCodeConstruction.expected
@@ -2,6 +2,7 @@ edges
| impl/unsafeCode.rb:2:12:2:17 | target : | impl/unsafeCode.rb:3:17:3:25 | #{...} |
| impl/unsafeCode.rb:7:12:7:12 | x : | impl/unsafeCode.rb:8:30:8:30 | x |
| impl/unsafeCode.rb:12:12:12:12 | x : | impl/unsafeCode.rb:13:33:13:33 | x |
+| impl/unsafeCode.rb:28:17:28:22 | my_arr : | impl/unsafeCode.rb:29:10:29:15 | my_arr |
nodes
| impl/unsafeCode.rb:2:12:2:17 | target : | semmle.label | target : |
| impl/unsafeCode.rb:3:17:3:25 | #{...} | semmle.label | #{...} |
@@ -9,8 +10,11 @@ nodes
| impl/unsafeCode.rb:8:30:8:30 | x | semmle.label | x |
| impl/unsafeCode.rb:12:12:12:12 | x : | semmle.label | x : |
| impl/unsafeCode.rb:13:33:13:33 | x | semmle.label | x |
+| impl/unsafeCode.rb:28:17:28:22 | my_arr : | semmle.label | my_arr : |
+| impl/unsafeCode.rb:29:10:29:15 | my_arr | semmle.label | my_arr |
subpaths
#select
| impl/unsafeCode.rb:3:17:3:25 | #{...} | impl/unsafeCode.rb:2:12:2:17 | target : | impl/unsafeCode.rb:3:17:3:25 | #{...} | This string interpolation which depends on $@ is later $@. | impl/unsafeCode.rb:2:12:2:17 | target | library input | impl/unsafeCode.rb:3:5:3:27 | call to eval | interpreted as code |
| impl/unsafeCode.rb:8:30:8:30 | x | impl/unsafeCode.rb:7:12:7:12 | x : | impl/unsafeCode.rb:8:30:8:30 | x | This string format which depends on $@ is later $@. | impl/unsafeCode.rb:7:12:7:12 | x | library input | impl/unsafeCode.rb:8:5:8:32 | call to eval | interpreted as code |
| impl/unsafeCode.rb:13:33:13:33 | x | impl/unsafeCode.rb:12:12:12:12 | x : | impl/unsafeCode.rb:13:33:13:33 | x | This string format which depends on $@ is later $@. | impl/unsafeCode.rb:12:12:12:12 | x | library input | impl/unsafeCode.rb:13:5:13:35 | call to eval | interpreted as code |
+| impl/unsafeCode.rb:29:10:29:15 | my_arr | impl/unsafeCode.rb:28:17:28:22 | my_arr : | impl/unsafeCode.rb:29:10:29:15 | my_arr | This array which depends on $@ is later $@. | impl/unsafeCode.rb:28:17:28:22 | my_arr | library input | impl/unsafeCode.rb:29:5:29:27 | call to eval | interpreted as code |
diff --git a/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/impl/unsafeCode.rb b/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/impl/unsafeCode.rb
index d7d720d5d32..ca3605ec050 100644
--- a/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/impl/unsafeCode.rb
+++ b/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/impl/unsafeCode.rb
@@ -24,4 +24,11 @@ class Foobar
def named_code(code)
foo.send("def \n #{code} \n end") # OK - parameter is named code
end
+
+ def joinStuff(my_arr)
+ eval(my_arr.join("\n")) # NOT OK
+ end
+
+ # TODO: [x, y].join("\n") is not yet supported
+ # TODO: list << element.
end
From 80c92dc3e65a07a75f487a9b0ddcdfe8ca3e09cf Mon Sep 17 00:00:00 2001
From: erik-krogh
Date: Thu, 24 Nov 2022 17:47:03 +0100
Subject: [PATCH 009/381] add support for array pushes
---
.../security/UnsafeCodeConstructionQuery.qll | 16 ++++++++++++++++
.../UnsafeCodeConstruction.expected | 11 +++++++++++
.../UnsafeCodeConstruction/impl/unsafeCode.rb | 16 ++++++++++++++--
3 files changed, 41 insertions(+), 2 deletions(-)
diff --git a/ruby/ql/lib/codeql/ruby/security/UnsafeCodeConstructionQuery.qll b/ruby/ql/lib/codeql/ruby/security/UnsafeCodeConstructionQuery.qll
index 4b27a258716..a5670a783e4 100644
--- a/ruby/ql/lib/codeql/ruby/security/UnsafeCodeConstructionQuery.qll
+++ b/ruby/ql/lib/codeql/ruby/security/UnsafeCodeConstructionQuery.qll
@@ -30,4 +30,20 @@ class Configuration extends TaintTracking::Configuration {
override DataFlow::FlowFeature getAFeature() {
result instanceof DataFlow::FeatureHasSourceCallContext
}
+
+ override predicate isAdditionalTaintStep(DataFlow::Node pred, DataFlow::Node succ) {
+ // if an array element gets tainted, then we treat the entire array as tainted
+ exists(DataFlow::CallNode call |
+ call.getMethodName() = ["<<", "push", "append"] and
+ call.getReceiver() = succ and
+ pred = call.getArgument(0) and
+ call.getNumberOfArguments() = 1
+ )
+ or
+ exists(DataFlow::CallNode call |
+ call.getMethodName() = "[]" and
+ succ = call and
+ pred = call.getArgument(_)
+ )
+ }
}
diff --git a/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/UnsafeCodeConstruction.expected b/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/UnsafeCodeConstruction.expected
index 1f4d4e33719..ffc53d43faf 100644
--- a/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/UnsafeCodeConstruction.expected
+++ b/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/UnsafeCodeConstruction.expected
@@ -3,6 +3,9 @@ edges
| impl/unsafeCode.rb:7:12:7:12 | x : | impl/unsafeCode.rb:8:30:8:30 | x |
| impl/unsafeCode.rb:12:12:12:12 | x : | impl/unsafeCode.rb:13:33:13:33 | x |
| impl/unsafeCode.rb:28:17:28:22 | my_arr : | impl/unsafeCode.rb:29:10:29:15 | my_arr |
+| impl/unsafeCode.rb:32:21:32:21 | x : | impl/unsafeCode.rb:34:10:34:12 | arr |
+| impl/unsafeCode.rb:37:15:37:15 | x : | impl/unsafeCode.rb:40:10:40:12 | arr |
+| impl/unsafeCode.rb:37:15:37:15 | x : | impl/unsafeCode.rb:44:10:44:12 | arr |
nodes
| impl/unsafeCode.rb:2:12:2:17 | target : | semmle.label | target : |
| impl/unsafeCode.rb:3:17:3:25 | #{...} | semmle.label | #{...} |
@@ -12,9 +15,17 @@ nodes
| impl/unsafeCode.rb:13:33:13:33 | x | semmle.label | x |
| impl/unsafeCode.rb:28:17:28:22 | my_arr : | semmle.label | my_arr : |
| impl/unsafeCode.rb:29:10:29:15 | my_arr | semmle.label | my_arr |
+| impl/unsafeCode.rb:32:21:32:21 | x : | semmle.label | x : |
+| impl/unsafeCode.rb:34:10:34:12 | arr | semmle.label | arr |
+| impl/unsafeCode.rb:37:15:37:15 | x : | semmle.label | x : |
+| impl/unsafeCode.rb:40:10:40:12 | arr | semmle.label | arr |
+| impl/unsafeCode.rb:44:10:44:12 | arr | semmle.label | arr |
subpaths
#select
| impl/unsafeCode.rb:3:17:3:25 | #{...} | impl/unsafeCode.rb:2:12:2:17 | target : | impl/unsafeCode.rb:3:17:3:25 | #{...} | This string interpolation which depends on $@ is later $@. | impl/unsafeCode.rb:2:12:2:17 | target | library input | impl/unsafeCode.rb:3:5:3:27 | call to eval | interpreted as code |
| impl/unsafeCode.rb:8:30:8:30 | x | impl/unsafeCode.rb:7:12:7:12 | x : | impl/unsafeCode.rb:8:30:8:30 | x | This string format which depends on $@ is later $@. | impl/unsafeCode.rb:7:12:7:12 | x | library input | impl/unsafeCode.rb:8:5:8:32 | call to eval | interpreted as code |
| impl/unsafeCode.rb:13:33:13:33 | x | impl/unsafeCode.rb:12:12:12:12 | x : | impl/unsafeCode.rb:13:33:13:33 | x | This string format which depends on $@ is later $@. | impl/unsafeCode.rb:12:12:12:12 | x | library input | impl/unsafeCode.rb:13:5:13:35 | call to eval | interpreted as code |
| impl/unsafeCode.rb:29:10:29:15 | my_arr | impl/unsafeCode.rb:28:17:28:22 | my_arr : | impl/unsafeCode.rb:29:10:29:15 | my_arr | This array which depends on $@ is later $@. | impl/unsafeCode.rb:28:17:28:22 | my_arr | library input | impl/unsafeCode.rb:29:5:29:27 | call to eval | interpreted as code |
+| impl/unsafeCode.rb:34:10:34:12 | arr | impl/unsafeCode.rb:32:21:32:21 | x : | impl/unsafeCode.rb:34:10:34:12 | arr | This array which depends on $@ is later $@. | impl/unsafeCode.rb:32:21:32:21 | x | library input | impl/unsafeCode.rb:34:5:34:24 | call to eval | interpreted as code |
+| impl/unsafeCode.rb:40:10:40:12 | arr | impl/unsafeCode.rb:37:15:37:15 | x : | impl/unsafeCode.rb:40:10:40:12 | arr | This array which depends on $@ is later $@. | impl/unsafeCode.rb:37:15:37:15 | x | library input | impl/unsafeCode.rb:40:5:40:24 | call to eval | interpreted as code |
+| impl/unsafeCode.rb:44:10:44:12 | arr | impl/unsafeCode.rb:37:15:37:15 | x : | impl/unsafeCode.rb:44:10:44:12 | arr | This array which depends on $@ is later $@. | impl/unsafeCode.rb:37:15:37:15 | x | library input | impl/unsafeCode.rb:44:5:44:24 | call to eval | interpreted as code |
diff --git a/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/impl/unsafeCode.rb b/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/impl/unsafeCode.rb
index ca3605ec050..dac4703abda 100644
--- a/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/impl/unsafeCode.rb
+++ b/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/impl/unsafeCode.rb
@@ -29,6 +29,18 @@ class Foobar
eval(my_arr.join("\n")) # NOT OK
end
- # TODO: [x, y].join("\n") is not yet supported
- # TODO: list << element.
+ def joinWithElemt(x)
+ arr = [x, "foobar"]
+ eval(arr.join("\n")) # NOT OK
+ end
+
+ def pushArr(x, y)
+ arr = []
+ arr.push(x)
+ eval(arr.join("\n")) # NOT OK
+
+ arr2 = []
+ arr2 << y
+ eval(arr.join("\n")) # NOT OK
+ end
end
From 378cc1aed2e17589235d0bcb102f367cef5b30d8 Mon Sep 17 00:00:00 2001
From: erik-krogh
Date: Thu, 24 Nov 2022 18:01:54 +0100
Subject: [PATCH 010/381] add support for string-like-literals
---
.../ruby/security/UnsafeCodeConstructionCustomizations.qll | 2 +-
.../UnsafeCodeConstruction/UnsafeCodeConstruction.expected | 4 ++++
.../cwe-094/UnsafeCodeConstruction/impl/unsafeCode.rb | 7 +++++++
3 files changed, 12 insertions(+), 1 deletion(-)
diff --git a/ruby/ql/lib/codeql/ruby/security/UnsafeCodeConstructionCustomizations.qll b/ruby/ql/lib/codeql/ruby/security/UnsafeCodeConstructionCustomizations.qll
index 559a21f761a..4599179db5c 100644
--- a/ruby/ql/lib/codeql/ruby/security/UnsafeCodeConstructionCustomizations.qll
+++ b/ruby/ql/lib/codeql/ruby/security/UnsafeCodeConstructionCustomizations.qll
@@ -84,7 +84,7 @@ module UnsafeCodeConstruction {
Concepts::CodeExecution s;
StringFormatAsSink() {
- exists(Ast::StringLiteral lit |
+ exists(Ast::StringlikeLiteral lit |
any(DataFlow::Node n | n.asExpr().getExpr() = lit) = getANodeExecutedAsCode(s) and
this.asExpr().getExpr() = lit.getComponent(_)
)
diff --git a/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/UnsafeCodeConstruction.expected b/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/UnsafeCodeConstruction.expected
index ffc53d43faf..5b7cd78cca3 100644
--- a/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/UnsafeCodeConstruction.expected
+++ b/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/UnsafeCodeConstruction.expected
@@ -6,6 +6,7 @@ edges
| impl/unsafeCode.rb:32:21:32:21 | x : | impl/unsafeCode.rb:34:10:34:12 | arr |
| impl/unsafeCode.rb:37:15:37:15 | x : | impl/unsafeCode.rb:40:10:40:12 | arr |
| impl/unsafeCode.rb:37:15:37:15 | x : | impl/unsafeCode.rb:44:10:44:12 | arr |
+| impl/unsafeCode.rb:47:15:47:15 | x : | impl/unsafeCode.rb:49:9:49:12 | #{...} |
nodes
| impl/unsafeCode.rb:2:12:2:17 | target : | semmle.label | target : |
| impl/unsafeCode.rb:3:17:3:25 | #{...} | semmle.label | #{...} |
@@ -20,6 +21,8 @@ nodes
| impl/unsafeCode.rb:37:15:37:15 | x : | semmle.label | x : |
| impl/unsafeCode.rb:40:10:40:12 | arr | semmle.label | arr |
| impl/unsafeCode.rb:44:10:44:12 | arr | semmle.label | arr |
+| impl/unsafeCode.rb:47:15:47:15 | x : | semmle.label | x : |
+| impl/unsafeCode.rb:49:9:49:12 | #{...} | semmle.label | #{...} |
subpaths
#select
| impl/unsafeCode.rb:3:17:3:25 | #{...} | impl/unsafeCode.rb:2:12:2:17 | target : | impl/unsafeCode.rb:3:17:3:25 | #{...} | This string interpolation which depends on $@ is later $@. | impl/unsafeCode.rb:2:12:2:17 | target | library input | impl/unsafeCode.rb:3:5:3:27 | call to eval | interpreted as code |
@@ -29,3 +32,4 @@ subpaths
| impl/unsafeCode.rb:34:10:34:12 | arr | impl/unsafeCode.rb:32:21:32:21 | x : | impl/unsafeCode.rb:34:10:34:12 | arr | This array which depends on $@ is later $@. | impl/unsafeCode.rb:32:21:32:21 | x | library input | impl/unsafeCode.rb:34:5:34:24 | call to eval | interpreted as code |
| impl/unsafeCode.rb:40:10:40:12 | arr | impl/unsafeCode.rb:37:15:37:15 | x : | impl/unsafeCode.rb:40:10:40:12 | arr | This array which depends on $@ is later $@. | impl/unsafeCode.rb:37:15:37:15 | x | library input | impl/unsafeCode.rb:40:5:40:24 | call to eval | interpreted as code |
| impl/unsafeCode.rb:44:10:44:12 | arr | impl/unsafeCode.rb:37:15:37:15 | x : | impl/unsafeCode.rb:44:10:44:12 | arr | This array which depends on $@ is later $@. | impl/unsafeCode.rb:37:15:37:15 | x | library input | impl/unsafeCode.rb:44:5:44:24 | call to eval | interpreted as code |
+| impl/unsafeCode.rb:49:9:49:12 | #{...} | impl/unsafeCode.rb:47:15:47:15 | x : | impl/unsafeCode.rb:49:9:49:12 | #{...} | This string interpolation which depends on $@ is later $@. | impl/unsafeCode.rb:47:15:47:15 | x | library input | impl/unsafeCode.rb:51:5:51:13 | call to eval | interpreted as code |
diff --git a/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/impl/unsafeCode.rb b/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/impl/unsafeCode.rb
index dac4703abda..64bba0aadc6 100644
--- a/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/impl/unsafeCode.rb
+++ b/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/impl/unsafeCode.rb
@@ -43,4 +43,11 @@ class Foobar
arr2 << y
eval(arr.join("\n")) # NOT OK
end
+
+ def hereDoc(x)
+ foo = <<~HERE
+ #{x}
+ HERE
+ eval(foo) # NOT OK
+ end
end
From 0817238177ec1c818a05d69c0c633154cb65c9d4 Mon Sep 17 00:00:00 2001
From: erik-krogh
Date: Thu, 24 Nov 2022 18:02:27 +0100
Subject: [PATCH 011/381] drive-by: same change in
unsafe-shell-command-construction
---
.../security/UnsafeShellCommandConstructionCustomizations.qll | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ruby/ql/lib/codeql/ruby/security/UnsafeShellCommandConstructionCustomizations.qll b/ruby/ql/lib/codeql/ruby/security/UnsafeShellCommandConstructionCustomizations.qll
index 88e9625c822..d4fa74cab89 100644
--- a/ruby/ql/lib/codeql/ruby/security/UnsafeShellCommandConstructionCustomizations.qll
+++ b/ruby/ql/lib/codeql/ruby/security/UnsafeShellCommandConstructionCustomizations.qll
@@ -67,7 +67,7 @@ module UnsafeShellCommandConstruction {
*/
class StringInterpolationAsSink extends Sink {
Concepts::SystemCommandExecution s;
- Ast::StringLiteral lit;
+ Ast::StringlikeLiteral lit;
StringInterpolationAsSink() {
isUsedAsShellCommand(any(DataFlow::Node n | n.asExpr().getExpr() = lit), s) and
From 53f24a528147d52173e788f7fae0d79290013a2f Mon Sep 17 00:00:00 2001
From: erik-krogh
Date: Thu, 24 Nov 2022 18:28:42 +0100
Subject: [PATCH 012/381] fix QL-for-QL warning
---
.../security/UnsafeCodeConstructionCustomizations.qll | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/ruby/ql/lib/codeql/ruby/security/UnsafeCodeConstructionCustomizations.qll b/ruby/ql/lib/codeql/ruby/security/UnsafeCodeConstructionCustomizations.qll
index 4599179db5c..b6c9c3b5219 100644
--- a/ruby/ql/lib/codeql/ruby/security/UnsafeCodeConstructionCustomizations.qll
+++ b/ruby/ql/lib/codeql/ruby/security/UnsafeCodeConstructionCustomizations.qll
@@ -62,13 +62,14 @@ module UnsafeCodeConstruction {
*/
class ArrayJoin extends Sink {
Concepts::CodeExecution s;
- DataFlow::CallNode call;
ArrayJoin() {
- call.getMethodName() = "join" and
- call.getNumberOfArguments() = 1 and // any string. E.g. ";" or "\n".
- call = getANodeExecutedAsCode(s) and
- this = call.getReceiver()
+ exists(DataFlow::CallNode call |
+ call.getMethodName() = "join" and
+ call.getNumberOfArguments() = 1 and // any string. E.g. ";" or "\n".
+ call = getANodeExecutedAsCode(s) and
+ this = call.getReceiver()
+ )
}
override DataFlow::Node getCodeSink() { result = s }
From f75b853ae40f1d5f5a98f4d1c3d14d5732a30988 Mon Sep 17 00:00:00 2001
From: erik-krogh
Date: Fri, 25 Nov 2022 11:08:14 +0100
Subject: [PATCH 013/381] add change-note
---
.../src/change-notes/2022-11-25-unsafe-code-construction.md | 4 ++++
1 file changed, 4 insertions(+)
create mode 100644 ruby/ql/src/change-notes/2022-11-25-unsafe-code-construction.md
diff --git a/ruby/ql/src/change-notes/2022-11-25-unsafe-code-construction.md b/ruby/ql/src/change-notes/2022-11-25-unsafe-code-construction.md
new file mode 100644
index 00000000000..485a902693b
--- /dev/null
+++ b/ruby/ql/src/change-notes/2022-11-25-unsafe-code-construction.md
@@ -0,0 +1,4 @@
+---
+category: newQuery
+---
+* Added a new query, `rb/unsafe-code-construction`, to detect libraries that unsafely construct code from their inputs.
From fd7442868f7a90ae221db5bf27dd1fd10e7dc936 Mon Sep 17 00:00:00 2001
From: erik-krogh
Date: Mon, 28 Nov 2022 13:45:24 +0100
Subject: [PATCH 014/381] fix copy-pate error in
UnsafeCodeConstructionQuery.qll
---
.../ql/lib/codeql/ruby/security/UnsafeCodeConstructionQuery.qll | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ruby/ql/lib/codeql/ruby/security/UnsafeCodeConstructionQuery.qll b/ruby/ql/lib/codeql/ruby/security/UnsafeCodeConstructionQuery.qll
index a5670a783e4..68e8c56100c 100644
--- a/ruby/ql/lib/codeql/ruby/security/UnsafeCodeConstructionQuery.qll
+++ b/ruby/ql/lib/codeql/ruby/security/UnsafeCodeConstructionQuery.qll
@@ -12,7 +12,7 @@ private import codeql.ruby.TaintTracking
private import codeql.ruby.dataflow.BarrierGuards
/**
- * A taint-tracking configuration for detecting shell command constructed from library input vulnerabilities.
+ * A taint-tracking configuration for detecting code constructed from library input vulnerabilities.
*/
class Configuration extends TaintTracking::Configuration {
Configuration() { this = "UnsafeShellCommandConstruction" }
From a2210959b5f0cfe51ab5d575e303ffa5afc46f8f Mon Sep 17 00:00:00 2001
From: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
Date: Thu, 17 Nov 2022 13:57:14 +0000
Subject: [PATCH 015/381] Swift: Uncontrolled format string query (initial
version).
---
.../CWE-134/UncontrolledFormatString.ql | 105 ++++++++++++++++++
1 file changed, 105 insertions(+)
create mode 100644 swift/ql/src/queries/Security/CWE-134/UncontrolledFormatString.ql
diff --git a/swift/ql/src/queries/Security/CWE-134/UncontrolledFormatString.ql b/swift/ql/src/queries/Security/CWE-134/UncontrolledFormatString.ql
new file mode 100644
index 00000000000..e4c7049fdb2
--- /dev/null
+++ b/swift/ql/src/queries/Security/CWE-134/UncontrolledFormatString.ql
@@ -0,0 +1,105 @@
+/**
+ * @name Uncontrolled format string
+ * @description TODO
+ * @kind path-problem
+ * @problem.severity TODO
+ * @security-severity TODO
+ * @precision TODO
+ * @id swift/uncontrolled-format-string
+ * @tags security
+ * external/cwe/cwe-134
+ */
+
+import swift
+import codeql.swift.dataflow.DataFlow
+import codeql.swift.dataflow.TaintTracking
+import codeql.swift.dataflow.FlowSources
+import DataFlow::PathGraph
+import swift
+
+/**
+ * A function that takes a `printf` style format argument.
+ */
+abstract class FormattingFunction extends AbstractFunctionDecl {
+ /**
+ * Gets the position of the format argument.
+ */
+ abstract int getFormatParameterIndex();
+}
+
+/**
+ * An initializer for `String`, `NSString` or `NSMutableString` that takes a
+ * `printf` style format argument.
+ */
+class StringInitWithFormat extends FormattingFunction, MethodDecl {
+ StringInitWithFormat() {
+ exists(string fName |
+ this.hasQualifiedName(["String", "NSString", "NSMutableString"], fName) and
+ fName.matches("init(format:%")
+ )
+ }
+
+ override int getFormatParameterIndex() { result = 0 }
+}
+
+/**
+ * The `localizedStringWithFormat` method of `String`, `NSString` and `NSMutableString`.
+ */
+class LocalizedStringWithFormat extends FormattingFunction, MethodDecl {
+ LocalizedStringWithFormat() {
+ this.hasQualifiedName(["String", "NSString", "NSMutableString"],
+ "localizedStringWithFormat(_:_:)")
+ }
+
+ override int getFormatParameterIndex() { result = 0 }
+}
+
+/**
+ * The functions `NSLog` and `NSLogv`.
+ */
+class NsLog extends FormattingFunction, FreeFunctionDecl {
+ NsLog() { this.getName() = ["NSLog(_:_:)", "NSLogv(_:_:)"] }
+
+ override int getFormatParameterIndex() { result = 0 }
+}
+
+/**
+ * The `NSException.raise` method.
+ */
+class NsExceptionRaise extends FormattingFunction, MethodDecl {
+ NsExceptionRaise() { this.hasQualifiedName("NSException", "raise(_:format:arguments:)") }
+
+ override int getFormatParameterIndex() { result = 1 }
+}
+
+/**
+ * A call to a function that takes a `printf` style format argument.
+ */
+class FormattingFunctionCall extends CallExpr {
+ FormattingFunction target;
+
+ FormattingFunctionCall() { target = this.getStaticTarget() }
+
+ /**
+ * Gets the format expression used in this call.
+ */
+ Expr getFormat() { result = this.getArgument(target.getFormatParameterIndex()).getExpr() }
+}
+
+/**
+ * A taint configuration for tainted data that reaches a format string.
+ */
+class TaintedFormatConfiguration extends TaintTracking::Configuration {
+ TaintedFormatConfiguration() { this = "TaintedFormatConfiguration" }
+
+ override predicate isSource(DataFlow::Node node) { node instanceof FlowSource }
+
+ override predicate isSink(DataFlow::Node node) {
+ node.asExpr() = any(FormattingFunctionCall fc).getFormat()
+ }
+}
+
+from TaintedFormatConfiguration config, DataFlow::PathNode sourceNode, DataFlow::PathNode sinkNode
+where config.hasFlowPath(sourceNode, sinkNode)
+select sinkNode.getNode(), sourceNode, sinkNode, "This format string is derived from a $@.",
+ sourceNode.getNode(), "user-provided value"
From 32c4728f83a93e7fd3e900408119c2e473fad66f Mon Sep 17 00:00:00 2001
From: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
Date: Fri, 18 Nov 2022 13:06:28 +0000
Subject: [PATCH 016/381] Swift: Add tests.
---
.../CWE-134/UncontrolledFormatString.expected | 32 ++++++
.../CWE-134/UncontrolledFormatString.qlref | 1 +
.../CWE-134/UncontrolledFormatString.swift | 98 +++++++++++++++++++
3 files changed, 131 insertions(+)
create mode 100644 swift/ql/test/query-tests/Security/CWE-134/UncontrolledFormatString.expected
create mode 100644 swift/ql/test/query-tests/Security/CWE-134/UncontrolledFormatString.qlref
create mode 100644 swift/ql/test/query-tests/Security/CWE-134/UncontrolledFormatString.swift
diff --git a/swift/ql/test/query-tests/Security/CWE-134/UncontrolledFormatString.expected b/swift/ql/test/query-tests/Security/CWE-134/UncontrolledFormatString.expected
new file mode 100644
index 00000000000..56aaf090d4a
--- /dev/null
+++ b/swift/ql/test/query-tests/Security/CWE-134/UncontrolledFormatString.expected
@@ -0,0 +1,32 @@
+edges
+| UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:68:28:68:28 | tainted |
+| UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:71:28:71:28 | tainted |
+| UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:72:28:72:28 | tainted |
+| UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:74:28:74:28 | tainted |
+| UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:75:28:75:28 | tainted |
+| UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:76:28:76:28 | tainted |
+| UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:77:46:77:46 | tainted |
+| UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:86:11:86:11 | tainted |
+| UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:89:61:89:61 | tainted |
+nodes
+| UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | semmle.label | call to init(contentsOf:) : |
+| UncontrolledFormatString.swift:68:28:68:28 | tainted | semmle.label | tainted |
+| UncontrolledFormatString.swift:71:28:71:28 | tainted | semmle.label | tainted |
+| UncontrolledFormatString.swift:72:28:72:28 | tainted | semmle.label | tainted |
+| UncontrolledFormatString.swift:74:28:74:28 | tainted | semmle.label | tainted |
+| UncontrolledFormatString.swift:75:28:75:28 | tainted | semmle.label | tainted |
+| UncontrolledFormatString.swift:76:28:76:28 | tainted | semmle.label | tainted |
+| UncontrolledFormatString.swift:77:46:77:46 | tainted | semmle.label | tainted |
+| UncontrolledFormatString.swift:86:11:86:11 | tainted | semmle.label | tainted |
+| UncontrolledFormatString.swift:89:61:89:61 | tainted | semmle.label | tainted |
+subpaths
+#select
+| UncontrolledFormatString.swift:68:28:68:28 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:68:28:68:28 | tainted | This format string is derived from a $@. | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) | user-provided value |
+| UncontrolledFormatString.swift:71:28:71:28 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:71:28:71:28 | tainted | This format string is derived from a $@. | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) | user-provided value |
+| UncontrolledFormatString.swift:72:28:72:28 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:72:28:72:28 | tainted | This format string is derived from a $@. | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) | user-provided value |
+| UncontrolledFormatString.swift:74:28:74:28 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:74:28:74:28 | tainted | This format string is derived from a $@. | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) | user-provided value |
+| UncontrolledFormatString.swift:75:28:75:28 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:75:28:75:28 | tainted | This format string is derived from a $@. | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) | user-provided value |
+| UncontrolledFormatString.swift:76:28:76:28 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:76:28:76:28 | tainted | This format string is derived from a $@. | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) | user-provided value |
+| UncontrolledFormatString.swift:77:46:77:46 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:77:46:77:46 | tainted | This format string is derived from a $@. | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) | user-provided value |
+| UncontrolledFormatString.swift:86:11:86:11 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:86:11:86:11 | tainted | This format string is derived from a $@. | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) | user-provided value |
+| UncontrolledFormatString.swift:89:61:89:61 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:89:61:89:61 | tainted | This format string is derived from a $@. | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) | user-provided value |
diff --git a/swift/ql/test/query-tests/Security/CWE-134/UncontrolledFormatString.qlref b/swift/ql/test/query-tests/Security/CWE-134/UncontrolledFormatString.qlref
new file mode 100644
index 00000000000..115fef47e47
--- /dev/null
+++ b/swift/ql/test/query-tests/Security/CWE-134/UncontrolledFormatString.qlref
@@ -0,0 +1 @@
+queries/Security/CWE-134/UncontrolledFormatString.ql
\ No newline at end of file
diff --git a/swift/ql/test/query-tests/Security/CWE-134/UncontrolledFormatString.swift b/swift/ql/test/query-tests/Security/CWE-134/UncontrolledFormatString.swift
new file mode 100644
index 00000000000..3536bee3954
--- /dev/null
+++ b/swift/ql/test/query-tests/Security/CWE-134/UncontrolledFormatString.swift
@@ -0,0 +1,98 @@
+
+// --- stubs ---
+
+struct URL
+{
+ init?(string: String) {}
+}
+
+struct Locale {
+}
+
+extension String : CVarArg {
+ public var _cVarArgEncoding: [Int] { get { return [] } }
+
+ init(contentsOf: URL) throws { self.init() }
+ init(format: String, _ arguments: CVarArg...) { self.init() }
+ init(format: String, arguments: [CVarArg]) { self.init() }
+ init(format: String, locale: Locale?, _ args: CVarArg...) { self.init() }
+ init(format: String, locale: Locale?, arguments: [CVarArg]) { self.init() }
+
+ static func localizedStringWithFormat(_ format: String, _ arguments: CVarArg...) -> String { return "" }
+}
+
+class NSObject
+{
+}
+
+class NSString : NSObject
+{
+ init(string aString: String) {}
+ init(format: NSString, _ args: CVarArg...) {}
+
+ class func localizedStringWithFormat(_ format: NSString, _ args: CVarArg...) {}
+}
+
+class NSMutableString : NSString
+{
+}
+
+struct NSExceptionName {
+ init(_ rawValue: String) {}
+}
+
+class NSException: NSObject
+{
+ class func raise(_ name: NSExceptionName, format: String, arguments argList: CVaListPointer) {}
+}
+
+func NSLog(_ format: String, _ args: CVarArg...) {}
+
+func NSLogv(_ format: String, _ args: CVaListPointer) {}
+
+// --- tests ---
+
+func MyLog(_ format: String, _ args: CVarArg...) {
+ withVaList(args) { arglist in
+ NSLogv(format, arglist) // BAD [NOT DETECTED]
+ }
+}
+
+func tests() {
+ let tainted = try! String(contentsOf: URL(string: "http://example.com")!)
+
+ let a = String("abc") // GOOD: not a format string
+ let b = String(tainted) // GOOD: not a format string
+
+ let c = String(format: "abc") // GOOD: not tainted
+ let d = String(format: tainted) // BAD
+ let e = String(format: "%s", "abc") // GOOD: not tainted
+ let f = String(format: "%s", tainted) // GOOD: format string itself is not tainted
+ let g = String(format: tainted, "abc") // BAD
+ let h = String(format: tainted, tainted) // BAD
+
+ let i = String(format: tainted, arguments: []) // BAD
+ let j = String(format: tainted, locale: nil) // BAD
+ let k = String(format: tainted, locale: nil, arguments: []) // BAD
+ let l = String.localizedStringWithFormat(tainted) // BAD
+
+ let m = NSString(format: NSString(string: tainted), "abc") // BAD [NOT DETECTED]
+ let n = NSString.localizedStringWithFormat(NSString(string: tainted)) // BAD [NOT DETECTED]
+
+ var o = NSMutableString(format: NSString(string: tainted), "abc") // BAD [NOT DETECTED]
+ var p = NSMutableString.localizedStringWithFormat(NSString(string: tainted)) // BAD [NOT DETECTED]
+
+ NSLog("abc") // GOOD: not tainted
+ NSLog(tainted) // BAD
+ MyLog(tainted) // BAD [NOT DETECTED]
+
+ NSException.raise(NSExceptionName("exception"), format: tainted, arguments: getVaList([])) // BAD
+
+ let taintedVal = Int(tainted)!
+ let taintedSan = "\(taintedVal)"
+ let q = String(format: taintedSan) // GOOD: sufficiently sanitized
+
+ let taintedVal2 = Int(tainted) ?? 0
+ let taintedSan2 = String(taintedVal2)
+ let r = String(format: taintedSan2) // GOOD: sufficiently sanitized
+}
From 2b61f26a6404b426260e5ce90e121cc9813c14e5 Mon Sep 17 00:00:00 2001
From: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
Date: Fri, 18 Nov 2022 15:07:54 +0000
Subject: [PATCH 017/381] Swift: Add doc.
---
.../CWE-134/UncontrolledFormatString.qhelp | 39 +++++++++++++++++++
.../CWE-134/UncontrolledFormatStringBad.swift | 2 +
.../UncontrolledFormatStringGood.swift | 2 +
3 files changed, 43 insertions(+)
create mode 100644 swift/ql/src/queries/Security/CWE-134/UncontrolledFormatString.qhelp
create mode 100644 swift/ql/src/queries/Security/CWE-134/UncontrolledFormatStringBad.swift
create mode 100644 swift/ql/src/queries/Security/CWE-134/UncontrolledFormatStringGood.swift
diff --git a/swift/ql/src/queries/Security/CWE-134/UncontrolledFormatString.qhelp b/swift/ql/src/queries/Security/CWE-134/UncontrolledFormatString.qhelp
new file mode 100644
index 00000000000..71b74e13c04
--- /dev/null
+++ b/swift/ql/src/queries/Security/CWE-134/UncontrolledFormatString.qhelp
@@ -0,0 +1,39 @@
+
+
+
+
+Passing untrusted format strings to functions that use printf style formatting can lead to buffer overflows and data representation problems. An attacker can exploit this weakness to crash the program or obtain sensitive information from its internal state.
+
+
+
+
+
+
Use a string literal for the format string to prevent the possibility of data flow from
+an untrusted source. This also helps to prevent errors where the format arguments do not match the format string.
+
+
If the format string cannot be constant, ensure that it comes from a secure data source or is compiled into the source code. If you need to include a value from the user, use the %s specifier in the format string and include that value as a format argument.
+
+
+
+
+
+
In this example, the format string includes a user-controlled inputString:
+
+
+
+
To fix it, make inputString a format argument rather than part of the format string, as in the following code:
+
+
+
diff --git a/swift/ql/src/queries/Security/CWE-134/UncontrolledFormatStringBad.swift b/swift/ql/src/queries/Security/CWE-134/UncontrolledFormatStringBad.swift
new file mode 100644
index 00000000000..8bce9ef8128
--- /dev/null
+++ b/swift/ql/src/queries/Security/CWE-134/UncontrolledFormatStringBad.swift
@@ -0,0 +1,2 @@
+
+print(String(format: "User input: " + inputString)) // vulnerable
diff --git a/swift/ql/src/queries/Security/CWE-134/UncontrolledFormatStringGood.swift b/swift/ql/src/queries/Security/CWE-134/UncontrolledFormatStringGood.swift
new file mode 100644
index 00000000000..3c5431b9f5c
--- /dev/null
+++ b/swift/ql/src/queries/Security/CWE-134/UncontrolledFormatStringGood.swift
@@ -0,0 +1,2 @@
+
+print(String(format: "User input: %s", inputString)) // fixed
From 58e9a0436e29d48616bd155e3c0a6f46753ffeb3 Mon Sep 17 00:00:00 2001
From: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
Date: Thu, 1 Dec 2022 16:50:11 +0000
Subject: [PATCH 018/381] Swift: Add metadata.
---
.../queries/Security/CWE-134/UncontrolledFormatString.ql | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/swift/ql/src/queries/Security/CWE-134/UncontrolledFormatString.ql b/swift/ql/src/queries/Security/CWE-134/UncontrolledFormatString.ql
index e4c7049fdb2..9073333fba0 100644
--- a/swift/ql/src/queries/Security/CWE-134/UncontrolledFormatString.ql
+++ b/swift/ql/src/queries/Security/CWE-134/UncontrolledFormatString.ql
@@ -1,10 +1,10 @@
/**
* @name Uncontrolled format string
- * @description TODO
+ * @description Using external input in format strings can lead to exceptions or information leaks.
* @kind path-problem
- * @problem.severity TODO
+ * @problem.severity error
* @security-severity TODO
- * @precision TODO
+ * @precision high
* @id swift/uncontrolled-format-string
* @tags security
* external/cwe/cwe-134
From 87fa159384471dc5c22f29689ace13e1cf520d2c Mon Sep 17 00:00:00 2001
From: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
Date: Thu, 1 Dec 2022 17:26:38 +0000
Subject: [PATCH 019/381] Swift: Add security-severity, and correct one for
another query that apparently wasn't right.
---
.../ql/src/queries/Security/CWE-134/UncontrolledFormatString.ql | 2 +-
swift/ql/src/queries/Security/CWE-321/HardcodedEncryptionKey.ql | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/swift/ql/src/queries/Security/CWE-134/UncontrolledFormatString.ql b/swift/ql/src/queries/Security/CWE-134/UncontrolledFormatString.ql
index 9073333fba0..b8a82747105 100644
--- a/swift/ql/src/queries/Security/CWE-134/UncontrolledFormatString.ql
+++ b/swift/ql/src/queries/Security/CWE-134/UncontrolledFormatString.ql
@@ -3,7 +3,7 @@
* @description Using external input in format strings can lead to exceptions or information leaks.
* @kind path-problem
* @problem.severity error
- * @security-severity TODO
+ * @security-severity 9.3
* @precision high
* @id swift/uncontrolled-format-string
* @tags security
diff --git a/swift/ql/src/queries/Security/CWE-321/HardcodedEncryptionKey.ql b/swift/ql/src/queries/Security/CWE-321/HardcodedEncryptionKey.ql
index 2f2c88855b2..36132d93b78 100644
--- a/swift/ql/src/queries/Security/CWE-321/HardcodedEncryptionKey.ql
+++ b/swift/ql/src/queries/Security/CWE-321/HardcodedEncryptionKey.ql
@@ -3,7 +3,7 @@
* @description Using hardcoded keys for encryption is not secure, because potential attackers can easily guess them.
* @kind path-problem
* @problem.severity error
- * @security-severity 8.1
+ * @security-severity 7.7
* @precision high
* @id swift/hardcoded-key
* @tags security
From 43596869e73331689cc3456ceb71e16b36ae976b Mon Sep 17 00:00:00 2001
From: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
Date: Thu, 1 Dec 2022 17:35:05 +0000
Subject: [PATCH 020/381] Swift: Move query logic to a .qll.
---
.../UncontrolledFormatStringQuery.qll | 91 +++++++++++++++++++
.../CWE-134/UncontrolledFormatString.ql | 86 +-----------------
2 files changed, 92 insertions(+), 85 deletions(-)
create mode 100644 swift/ql/lib/codeql/swift/security/UncontrolledFormatStringQuery.qll
diff --git a/swift/ql/lib/codeql/swift/security/UncontrolledFormatStringQuery.qll b/swift/ql/lib/codeql/swift/security/UncontrolledFormatStringQuery.qll
new file mode 100644
index 00000000000..b54b8d1cd70
--- /dev/null
+++ b/swift/ql/lib/codeql/swift/security/UncontrolledFormatStringQuery.qll
@@ -0,0 +1,91 @@
+/**
+ * Provides a taint-tracking configuration for reasoning about uncontrolled format string
+ * vulnerabilities.
+ */
+
+import swift
+import codeql.swift.dataflow.DataFlow
+import codeql.swift.dataflow.TaintTracking
+import codeql.swift.dataflow.FlowSources
+
+/**
+ * A function that takes a `printf` style format argument.
+ */
+abstract class FormattingFunction extends AbstractFunctionDecl {
+ /**
+ * Gets the position of the format argument.
+ */
+ abstract int getFormatParameterIndex();
+}
+
+/**
+ * An initializer for `String`, `NSString` or `NSMutableString` that takes a
+ * `printf` style format argument.
+ */
+class StringInitWithFormat extends FormattingFunction, MethodDecl {
+ StringInitWithFormat() {
+ exists(string fName |
+ this.hasQualifiedName(["String", "NSString", "NSMutableString"], fName) and
+ fName.matches("init(format:%")
+ )
+ }
+
+ override int getFormatParameterIndex() { result = 0 }
+}
+
+/**
+ * The `localizedStringWithFormat` method of `String`, `NSString` and `NSMutableString`.
+ */
+class LocalizedStringWithFormat extends FormattingFunction, MethodDecl {
+ LocalizedStringWithFormat() {
+ this.hasQualifiedName(["String", "NSString", "NSMutableString"],
+ "localizedStringWithFormat(_:_:)")
+ }
+
+ override int getFormatParameterIndex() { result = 0 }
+}
+
+/**
+ * The functions `NSLog` and `NSLogv`.
+ */
+class NsLog extends FormattingFunction, FreeFunctionDecl {
+ NsLog() { this.getName() = ["NSLog(_:_:)", "NSLogv(_:_:)"] }
+
+ override int getFormatParameterIndex() { result = 0 }
+}
+
+/**
+ * The `NSException.raise` method.
+ */
+class NsExceptionRaise extends FormattingFunction, MethodDecl {
+ NsExceptionRaise() { this.hasQualifiedName("NSException", "raise(_:format:arguments:)") }
+
+ override int getFormatParameterIndex() { result = 1 }
+}
+
+/**
+ * A call to a function that takes a `printf` style format argument.
+ */
+class FormattingFunctionCall extends CallExpr {
+ FormattingFunction target;
+
+ FormattingFunctionCall() { target = this.getStaticTarget() }
+
+ /**
+ * Gets the format expression used in this call.
+ */
+ Expr getFormat() { result = this.getArgument(target.getFormatParameterIndex()).getExpr() }
+}
+
+/**
+ * A taint configuration for tainted data that reaches a format string.
+ */
+class TaintedFormatConfiguration extends TaintTracking::Configuration {
+ TaintedFormatConfiguration() { this = "TaintedFormatConfiguration" }
+
+ override predicate isSource(DataFlow::Node node) { node instanceof FlowSource }
+
+ override predicate isSink(DataFlow::Node node) {
+ node.asExpr() = any(FormattingFunctionCall fc).getFormat()
+ }
+}
diff --git a/swift/ql/src/queries/Security/CWE-134/UncontrolledFormatString.ql b/swift/ql/src/queries/Security/CWE-134/UncontrolledFormatString.ql
index b8a82747105..0452d965b97 100644
--- a/swift/ql/src/queries/Security/CWE-134/UncontrolledFormatString.ql
+++ b/swift/ql/src/queries/Security/CWE-134/UncontrolledFormatString.ql
@@ -12,92 +12,8 @@
import swift
import codeql.swift.dataflow.DataFlow
-import codeql.swift.dataflow.TaintTracking
-import codeql.swift.dataflow.FlowSources
+import codeql.swift.security.UncontrolledFormatStringQuery
import DataFlow::PathGraph
-import swift
-
-/**
- * A function that takes a `printf` style format argument.
- */
-abstract class FormattingFunction extends AbstractFunctionDecl {
- /**
- * Gets the position of the format argument.
- */
- abstract int getFormatParameterIndex();
-}
-
-/**
- * An initializer for `String`, `NSString` or `NSMutableString` that takes a
- * `printf` style format argument.
- */
-class StringInitWithFormat extends FormattingFunction, MethodDecl {
- StringInitWithFormat() {
- exists(string fName |
- this.hasQualifiedName(["String", "NSString", "NSMutableString"], fName) and
- fName.matches("init(format:%")
- )
- }
-
- override int getFormatParameterIndex() { result = 0 }
-}
-
-/**
- * The `localizedStringWithFormat` method of `String`, `NSString` and `NSMutableString`.
- */
-class LocalizedStringWithFormat extends FormattingFunction, MethodDecl {
- LocalizedStringWithFormat() {
- this.hasQualifiedName(["String", "NSString", "NSMutableString"],
- "localizedStringWithFormat(_:_:)")
- }
-
- override int getFormatParameterIndex() { result = 0 }
-}
-
-/**
- * The functions `NSLog` and `NSLogv`.
- */
-class NsLog extends FormattingFunction, FreeFunctionDecl {
- NsLog() { this.getName() = ["NSLog(_:_:)", "NSLogv(_:_:)"] }
-
- override int getFormatParameterIndex() { result = 0 }
-}
-
-/**
- * The `NSException.raise` method.
- */
-class NsExceptionRaise extends FormattingFunction, MethodDecl {
- NsExceptionRaise() { this.hasQualifiedName("NSException", "raise(_:format:arguments:)") }
-
- override int getFormatParameterIndex() { result = 1 }
-}
-
-/**
- * A call to a function that takes a `printf` style format argument.
- */
-class FormattingFunctionCall extends CallExpr {
- FormattingFunction target;
-
- FormattingFunctionCall() { target = this.getStaticTarget() }
-
- /**
- * Gets the format expression used in this call.
- */
- Expr getFormat() { result = this.getArgument(target.getFormatParameterIndex()).getExpr() }
-}
-
-/**
- * A taint configuration for tainted data that reaches a format string.
- */
-class TaintedFormatConfiguration extends TaintTracking::Configuration {
- TaintedFormatConfiguration() { this = "TaintedFormatConfiguration" }
-
- override predicate isSource(DataFlow::Node node) { node instanceof FlowSource }
-
- override predicate isSink(DataFlow::Node node) {
- node.asExpr() = any(FormattingFunctionCall fc).getFormat()
- }
-}
from TaintedFormatConfiguration config, DataFlow::PathNode sourceNode, DataFlow::PathNode sinkNode
where config.hasFlowPath(sourceNode, sinkNode)
From ad05cc3cb1533a56710bcaa5fd762f712b670ba9 Mon Sep 17 00:00:00 2001
From: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
Date: Thu, 1 Dec 2022 17:46:43 +0000
Subject: [PATCH 021/381] Swift: Separate out a FormatString library as well.
---
swift/ql/lib/codeql/swift/FormatString.qll | 74 +++++++++++++++++++
.../UncontrolledFormatStringQuery.qll | 70 +-----------------
2 files changed, 75 insertions(+), 69 deletions(-)
create mode 100644 swift/ql/lib/codeql/swift/FormatString.qll
diff --git a/swift/ql/lib/codeql/swift/FormatString.qll b/swift/ql/lib/codeql/swift/FormatString.qll
new file mode 100644
index 00000000000..4dbb127fc69
--- /dev/null
+++ b/swift/ql/lib/codeql/swift/FormatString.qll
@@ -0,0 +1,74 @@
+/**
+ * Provides classes and predicates for reasoning about string formatting.
+ */
+
+import swift
+
+/**
+ * A function that takes a `printf` style format argument.
+ */
+abstract class FormattingFunction extends AbstractFunctionDecl {
+ /**
+ * Gets the position of the format argument.
+ */
+ abstract int getFormatParameterIndex();
+}
+
+/**
+ * A call to a function that takes a `printf` style format argument.
+ */
+class FormattingFunctionCall extends CallExpr {
+ FormattingFunction target;
+
+ FormattingFunctionCall() { target = this.getStaticTarget() }
+
+ /**
+ * Gets the format expression used in this call.
+ */
+ Expr getFormat() { result = this.getArgument(target.getFormatParameterIndex()).getExpr() }
+}
+
+/**
+ * An initializer for `String`, `NSString` or `NSMutableString` that takes a
+ * `printf` style format argument.
+ */
+class StringInitWithFormat extends FormattingFunction, MethodDecl {
+ StringInitWithFormat() {
+ exists(string fName |
+ this.hasQualifiedName(["String", "NSString", "NSMutableString"], fName) and
+ fName.matches("init(format:%")
+ )
+ }
+
+ override int getFormatParameterIndex() { result = 0 }
+}
+
+/**
+ * The `localizedStringWithFormat` method of `String`, `NSString` and `NSMutableString`.
+ */
+class LocalizedStringWithFormat extends FormattingFunction, MethodDecl {
+ LocalizedStringWithFormat() {
+ this.hasQualifiedName(["String", "NSString", "NSMutableString"],
+ "localizedStringWithFormat(_:_:)")
+ }
+
+ override int getFormatParameterIndex() { result = 0 }
+}
+
+/**
+ * The functions `NSLog` and `NSLogv`.
+ */
+class NsLog extends FormattingFunction, FreeFunctionDecl {
+ NsLog() { this.getName() = ["NSLog(_:_:)", "NSLogv(_:_:)"] }
+
+ override int getFormatParameterIndex() { result = 0 }
+}
+
+/**
+ * The `NSException.raise` method.
+ */
+class NsExceptionRaise extends FormattingFunction, MethodDecl {
+ NsExceptionRaise() { this.hasQualifiedName("NSException", "raise(_:format:arguments:)") }
+
+ override int getFormatParameterIndex() { result = 1 }
+}
diff --git a/swift/ql/lib/codeql/swift/security/UncontrolledFormatStringQuery.qll b/swift/ql/lib/codeql/swift/security/UncontrolledFormatStringQuery.qll
index b54b8d1cd70..b489572cb97 100644
--- a/swift/ql/lib/codeql/swift/security/UncontrolledFormatStringQuery.qll
+++ b/swift/ql/lib/codeql/swift/security/UncontrolledFormatStringQuery.qll
@@ -4,79 +4,11 @@
*/
import swift
+import codeql.swift.StringFormat
import codeql.swift.dataflow.DataFlow
import codeql.swift.dataflow.TaintTracking
import codeql.swift.dataflow.FlowSources
-/**
- * A function that takes a `printf` style format argument.
- */
-abstract class FormattingFunction extends AbstractFunctionDecl {
- /**
- * Gets the position of the format argument.
- */
- abstract int getFormatParameterIndex();
-}
-
-/**
- * An initializer for `String`, `NSString` or `NSMutableString` that takes a
- * `printf` style format argument.
- */
-class StringInitWithFormat extends FormattingFunction, MethodDecl {
- StringInitWithFormat() {
- exists(string fName |
- this.hasQualifiedName(["String", "NSString", "NSMutableString"], fName) and
- fName.matches("init(format:%")
- )
- }
-
- override int getFormatParameterIndex() { result = 0 }
-}
-
-/**
- * The `localizedStringWithFormat` method of `String`, `NSString` and `NSMutableString`.
- */
-class LocalizedStringWithFormat extends FormattingFunction, MethodDecl {
- LocalizedStringWithFormat() {
- this.hasQualifiedName(["String", "NSString", "NSMutableString"],
- "localizedStringWithFormat(_:_:)")
- }
-
- override int getFormatParameterIndex() { result = 0 }
-}
-
-/**
- * The functions `NSLog` and `NSLogv`.
- */
-class NsLog extends FormattingFunction, FreeFunctionDecl {
- NsLog() { this.getName() = ["NSLog(_:_:)", "NSLogv(_:_:)"] }
-
- override int getFormatParameterIndex() { result = 0 }
-}
-
-/**
- * The `NSException.raise` method.
- */
-class NsExceptionRaise extends FormattingFunction, MethodDecl {
- NsExceptionRaise() { this.hasQualifiedName("NSException", "raise(_:format:arguments:)") }
-
- override int getFormatParameterIndex() { result = 1 }
-}
-
-/**
- * A call to a function that takes a `printf` style format argument.
- */
-class FormattingFunctionCall extends CallExpr {
- FormattingFunction target;
-
- FormattingFunctionCall() { target = this.getStaticTarget() }
-
- /**
- * Gets the format expression used in this call.
- */
- Expr getFormat() { result = this.getArgument(target.getFormatParameterIndex()).getExpr() }
-}
-
/**
* A taint configuration for tainted data that reaches a format string.
*/
From 157a7829ca377c8bc7e483a3c108da0b1a5b44c9 Mon Sep 17 00:00:00 2001
From: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
Date: Thu, 1 Dec 2022 18:35:10 +0000
Subject: [PATCH 022/381] Swift: correct the example.
---
.../src/queries/Security/CWE-134/UncontrolledFormatString.qhelp | 2 +-
.../queries/Security/CWE-134/UncontrolledFormatStringGood.swift | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/swift/ql/src/queries/Security/CWE-134/UncontrolledFormatString.qhelp b/swift/ql/src/queries/Security/CWE-134/UncontrolledFormatString.qhelp
index 71b74e13c04..f0f60aedfd0 100644
--- a/swift/ql/src/queries/Security/CWE-134/UncontrolledFormatString.qhelp
+++ b/swift/ql/src/queries/Security/CWE-134/UncontrolledFormatString.qhelp
@@ -13,7 +13,7 @@ Passing untrusted format strings to functions that use printf style
Use a string literal for the format string to prevent the possibility of data flow from
an untrusted source. This also helps to prevent errors where the format arguments do not match the format string.
-
If the format string cannot be constant, ensure that it comes from a secure data source or is compiled into the source code. If you need to include a value from the user, use the %s specifier in the format string and include that value as a format argument.
+
If the format string cannot be constant, ensure that it comes from a secure data source or is compiled into the source code. If you need to include a value from the user, use the %@ specifier in the format string and include that value as a format argument.
diff --git a/swift/ql/src/queries/Security/CWE-134/UncontrolledFormatStringGood.swift b/swift/ql/src/queries/Security/CWE-134/UncontrolledFormatStringGood.swift
index 3c5431b9f5c..d0d85952956 100644
--- a/swift/ql/src/queries/Security/CWE-134/UncontrolledFormatStringGood.swift
+++ b/swift/ql/src/queries/Security/CWE-134/UncontrolledFormatStringGood.swift
@@ -1,2 +1,2 @@
-print(String(format: "User input: %s", inputString)) // fixed
+print(String(format: "User input: %@", inputString)) // fixed
From f7ebd1312ee40035731fbf2fff51d7e266da58ad Mon Sep 17 00:00:00 2001
From: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
Date: Thu, 1 Dec 2022 19:16:40 +0000
Subject: [PATCH 023/381] Swift: Corrections.
---
.../{FormatString.qll => StringFormat.qll} | 0
.../security/UncontrolledFormatStringQuery.qll | 6 +++---
.../CWE-134/UncontrolledFormatString.qhelp | 11 +++++------
.../CWE-134/UncontrolledFormatString.ql | 4 ++--
.../CWE-134/UncontrolledFormatString.expected | 18 +++++++++---------
.../CWE-134/UncontrolledFormatString.swift | 4 ++--
6 files changed, 21 insertions(+), 22 deletions(-)
rename swift/ql/lib/codeql/swift/{FormatString.qll => StringFormat.qll} (100%)
diff --git a/swift/ql/lib/codeql/swift/FormatString.qll b/swift/ql/lib/codeql/swift/StringFormat.qll
similarity index 100%
rename from swift/ql/lib/codeql/swift/FormatString.qll
rename to swift/ql/lib/codeql/swift/StringFormat.qll
diff --git a/swift/ql/lib/codeql/swift/security/UncontrolledFormatStringQuery.qll b/swift/ql/lib/codeql/swift/security/UncontrolledFormatStringQuery.qll
index b489572cb97..41ff57f2084 100644
--- a/swift/ql/lib/codeql/swift/security/UncontrolledFormatStringQuery.qll
+++ b/swift/ql/lib/codeql/swift/security/UncontrolledFormatStringQuery.qll
@@ -1,8 +1,8 @@
/**
- * Provides a taint-tracking configuration for reasoning about uncontrolled format string
- * vulnerabilities.
+ * Provides a taint-tracking configuration for reasoning about uncontrolled
+ * format string vulnerabilities.
*/
-
+
import swift
import codeql.swift.StringFormat
import codeql.swift.dataflow.DataFlow
diff --git a/swift/ql/src/queries/Security/CWE-134/UncontrolledFormatString.qhelp b/swift/ql/src/queries/Security/CWE-134/UncontrolledFormatString.qhelp
index f0f60aedfd0..efc5eb9bff9 100644
--- a/swift/ql/src/queries/Security/CWE-134/UncontrolledFormatString.qhelp
+++ b/swift/ql/src/queries/Security/CWE-134/UncontrolledFormatString.qhelp
@@ -4,16 +4,15 @@
-Passing untrusted format strings to functions that use printf style formatting can lead to buffer overflows and data representation problems. An attacker can exploit this weakness to crash the program or obtain sensitive information from its internal state.
-
+Passing untrusted format strings to functions that use printf style formatting can lead to buffer overflows and data representation problems. An attacker may be able to exploit this weakness to crash the program or obtain sensitive information from its internal state.
-
Use a string literal for the format string to prevent the possibility of data flow from
+
Use a constant string literal for the format string to prevent the possibility of data flow from
an untrusted source. This also helps to prevent errors where the format arguments do not match the format string.
-
If the format string cannot be constant, ensure that it comes from a secure data source or is compiled into the source code. If you need to include a value from the user, use the %@ specifier in the format string and include that value as a format argument.
+
If the format string cannot be constant, ensure that it comes from a secure data source or is compiled into the source code. If you need to include a string value from the user, use an appropriate specifier (such as %@) in the format string and include the user provided value as a format argument.
@@ -21,11 +20,11 @@ an untrusted source. This also helps to prevent errors where the format argument
In this example, the format string includes a user-controlled inputString:
-
+
To fix it, make inputString a format argument rather than part of the format string, as in the following code:
-
+
diff --git a/swift/ql/src/queries/Security/CWE-134/UncontrolledFormatString.ql b/swift/ql/src/queries/Security/CWE-134/UncontrolledFormatString.ql
index 0452d965b97..6d2540c864e 100644
--- a/swift/ql/src/queries/Security/CWE-134/UncontrolledFormatString.ql
+++ b/swift/ql/src/queries/Security/CWE-134/UncontrolledFormatString.ql
@@ -17,5 +17,5 @@ import DataFlow::PathGraph
from TaintedFormatConfiguration config, DataFlow::PathNode sourceNode, DataFlow::PathNode sinkNode
where config.hasFlowPath(sourceNode, sinkNode)
-select sinkNode.getNode(), sourceNode, sinkNode, "This format string is derived from a $@.",
- sourceNode.getNode(), "user-provided value"
+select sinkNode.getNode(), sourceNode, sinkNode, "This format string depends on $@.",
+ sourceNode.getNode(), "a user-provided value"
diff --git a/swift/ql/test/query-tests/Security/CWE-134/UncontrolledFormatString.expected b/swift/ql/test/query-tests/Security/CWE-134/UncontrolledFormatString.expected
index 56aaf090d4a..f1faf8c16f0 100644
--- a/swift/ql/test/query-tests/Security/CWE-134/UncontrolledFormatString.expected
+++ b/swift/ql/test/query-tests/Security/CWE-134/UncontrolledFormatString.expected
@@ -21,12 +21,12 @@ nodes
| UncontrolledFormatString.swift:89:61:89:61 | tainted | semmle.label | tainted |
subpaths
#select
-| UncontrolledFormatString.swift:68:28:68:28 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:68:28:68:28 | tainted | This format string is derived from a $@. | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) | user-provided value |
-| UncontrolledFormatString.swift:71:28:71:28 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:71:28:71:28 | tainted | This format string is derived from a $@. | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) | user-provided value |
-| UncontrolledFormatString.swift:72:28:72:28 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:72:28:72:28 | tainted | This format string is derived from a $@. | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) | user-provided value |
-| UncontrolledFormatString.swift:74:28:74:28 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:74:28:74:28 | tainted | This format string is derived from a $@. | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) | user-provided value |
-| UncontrolledFormatString.swift:75:28:75:28 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:75:28:75:28 | tainted | This format string is derived from a $@. | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) | user-provided value |
-| UncontrolledFormatString.swift:76:28:76:28 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:76:28:76:28 | tainted | This format string is derived from a $@. | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) | user-provided value |
-| UncontrolledFormatString.swift:77:46:77:46 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:77:46:77:46 | tainted | This format string is derived from a $@. | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) | user-provided value |
-| UncontrolledFormatString.swift:86:11:86:11 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:86:11:86:11 | tainted | This format string is derived from a $@. | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) | user-provided value |
-| UncontrolledFormatString.swift:89:61:89:61 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:89:61:89:61 | tainted | This format string is derived from a $@. | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) | user-provided value |
+| UncontrolledFormatString.swift:68:28:68:28 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:68:28:68:28 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) | a user-provided value |
+| UncontrolledFormatString.swift:71:28:71:28 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:71:28:71:28 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) | a user-provided value |
+| UncontrolledFormatString.swift:72:28:72:28 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:72:28:72:28 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) | a user-provided value |
+| UncontrolledFormatString.swift:74:28:74:28 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:74:28:74:28 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) | a user-provided value |
+| UncontrolledFormatString.swift:75:28:75:28 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:75:28:75:28 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) | a user-provided value |
+| UncontrolledFormatString.swift:76:28:76:28 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:76:28:76:28 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) | a user-provided value |
+| UncontrolledFormatString.swift:77:46:77:46 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:77:46:77:46 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) | a user-provided value |
+| UncontrolledFormatString.swift:86:11:86:11 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:86:11:86:11 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) | a user-provided value |
+| UncontrolledFormatString.swift:89:61:89:61 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:89:61:89:61 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) | a user-provided value |
diff --git a/swift/ql/test/query-tests/Security/CWE-134/UncontrolledFormatString.swift b/swift/ql/test/query-tests/Security/CWE-134/UncontrolledFormatString.swift
index 3536bee3954..e6d1d8a2646 100644
--- a/swift/ql/test/query-tests/Security/CWE-134/UncontrolledFormatString.swift
+++ b/swift/ql/test/query-tests/Security/CWE-134/UncontrolledFormatString.swift
@@ -3,7 +3,7 @@
struct URL
{
- init?(string: String) {}
+ init?(string: String) {}
}
struct Locale {
@@ -12,7 +12,7 @@ struct Locale {
extension String : CVarArg {
public var _cVarArgEncoding: [Int] { get { return [] } }
- init(contentsOf: URL) throws { self.init() }
+ init(contentsOf: URL) throws { self.init() }
init(format: String, _ arguments: CVarArg...) { self.init() }
init(format: String, arguments: [CVarArg]) { self.init() }
init(format: String, locale: Locale?, _ args: CVarArg...) { self.init() }
From 85a0a42da91c4182fa3fa913cba2245a61a27d9b Mon Sep 17 00:00:00 2001
From: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
Date: Fri, 2 Dec 2022 10:15:11 +0000
Subject: [PATCH 024/381] Swift: try again to satisfy ql-for-ql.
---
.../CWE-134/UncontrolledFormatString.ql | 2 +-
.../CWE-134/UncontrolledFormatString.expected | 18 +++++++++---------
2 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/swift/ql/src/queries/Security/CWE-134/UncontrolledFormatString.ql b/swift/ql/src/queries/Security/CWE-134/UncontrolledFormatString.ql
index 6d2540c864e..d5111f50e3a 100644
--- a/swift/ql/src/queries/Security/CWE-134/UncontrolledFormatString.ql
+++ b/swift/ql/src/queries/Security/CWE-134/UncontrolledFormatString.ql
@@ -18,4 +18,4 @@ import DataFlow::PathGraph
from TaintedFormatConfiguration config, DataFlow::PathNode sourceNode, DataFlow::PathNode sinkNode
where config.hasFlowPath(sourceNode, sinkNode)
select sinkNode.getNode(), sourceNode, sinkNode, "This format string depends on $@.",
- sourceNode.getNode(), "a user-provided value"
+ sourceNode.getNode(), "this user-provided value"
diff --git a/swift/ql/test/query-tests/Security/CWE-134/UncontrolledFormatString.expected b/swift/ql/test/query-tests/Security/CWE-134/UncontrolledFormatString.expected
index f1faf8c16f0..fcca34232d4 100644
--- a/swift/ql/test/query-tests/Security/CWE-134/UncontrolledFormatString.expected
+++ b/swift/ql/test/query-tests/Security/CWE-134/UncontrolledFormatString.expected
@@ -21,12 +21,12 @@ nodes
| UncontrolledFormatString.swift:89:61:89:61 | tainted | semmle.label | tainted |
subpaths
#select
-| UncontrolledFormatString.swift:68:28:68:28 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:68:28:68:28 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) | a user-provided value |
-| UncontrolledFormatString.swift:71:28:71:28 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:71:28:71:28 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) | a user-provided value |
-| UncontrolledFormatString.swift:72:28:72:28 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:72:28:72:28 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) | a user-provided value |
-| UncontrolledFormatString.swift:74:28:74:28 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:74:28:74:28 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) | a user-provided value |
-| UncontrolledFormatString.swift:75:28:75:28 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:75:28:75:28 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) | a user-provided value |
-| UncontrolledFormatString.swift:76:28:76:28 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:76:28:76:28 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) | a user-provided value |
-| UncontrolledFormatString.swift:77:46:77:46 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:77:46:77:46 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) | a user-provided value |
-| UncontrolledFormatString.swift:86:11:86:11 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:86:11:86:11 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) | a user-provided value |
-| UncontrolledFormatString.swift:89:61:89:61 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:89:61:89:61 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) | a user-provided value |
+| UncontrolledFormatString.swift:68:28:68:28 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:68:28:68:28 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) | this user-provided value |
+| UncontrolledFormatString.swift:71:28:71:28 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:71:28:71:28 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) | this user-provided value |
+| UncontrolledFormatString.swift:72:28:72:28 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:72:28:72:28 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) | this user-provided value |
+| UncontrolledFormatString.swift:74:28:74:28 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:74:28:74:28 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) | this user-provided value |
+| UncontrolledFormatString.swift:75:28:75:28 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:75:28:75:28 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) | this user-provided value |
+| UncontrolledFormatString.swift:76:28:76:28 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:76:28:76:28 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) | this user-provided value |
+| UncontrolledFormatString.swift:77:46:77:46 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:77:46:77:46 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) | this user-provided value |
+| UncontrolledFormatString.swift:86:11:86:11 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:86:11:86:11 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) | this user-provided value |
+| UncontrolledFormatString.swift:89:61:89:61 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:89:61:89:61 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) | this user-provided value |
From cf3345ee8f0caab63bf9b23da34c4ec1f849aa47 Mon Sep 17 00:00:00 2001
From: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
Date: Fri, 2 Dec 2022 12:01:43 +0000
Subject: [PATCH 025/381] Swift: Revert security-severity on CWE-321, for now.
---
swift/ql/src/queries/Security/CWE-321/HardcodedEncryptionKey.ql | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/swift/ql/src/queries/Security/CWE-321/HardcodedEncryptionKey.ql b/swift/ql/src/queries/Security/CWE-321/HardcodedEncryptionKey.ql
index 36132d93b78..2f2c88855b2 100644
--- a/swift/ql/src/queries/Security/CWE-321/HardcodedEncryptionKey.ql
+++ b/swift/ql/src/queries/Security/CWE-321/HardcodedEncryptionKey.ql
@@ -3,7 +3,7 @@
* @description Using hardcoded keys for encryption is not secure, because potential attackers can easily guess them.
* @kind path-problem
* @problem.severity error
- * @security-severity 7.7
+ * @security-severity 8.1
* @precision high
* @id swift/hardcoded-key
* @tags security
From dba344451f9c24cad6a29a45b1a6f9318f6e2f5d Mon Sep 17 00:00:00 2001
From: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
Date: Thu, 8 Dec 2022 11:26:24 +0000
Subject: [PATCH 026/381] Swift: Add UncontrolledFormatStringExtensions.qll.
---
.../UncontrolledFormatStringExtensions.qll | 36 +++++++++++++++++++
.../UncontrolledFormatStringQuery.qll | 11 ++++--
2 files changed, 45 insertions(+), 2 deletions(-)
create mode 100644 swift/ql/lib/codeql/swift/security/UncontrolledFormatStringExtensions.qll
diff --git a/swift/ql/lib/codeql/swift/security/UncontrolledFormatStringExtensions.qll b/swift/ql/lib/codeql/swift/security/UncontrolledFormatStringExtensions.qll
new file mode 100644
index 00000000000..3e9572ab37d
--- /dev/null
+++ b/swift/ql/lib/codeql/swift/security/UncontrolledFormatStringExtensions.qll
@@ -0,0 +1,36 @@
+/**
+ * Provides classes and predicates for reasoning about uncontrolled
+ * format string vulnerabilities.
+ */
+
+import swift
+import codeql.swift.StringFormat
+import codeql.swift.dataflow.DataFlow
+import codeql.swift.dataflow.TaintTracking
+
+/**
+ * A dataflow sink for uncontrolled format string vulnerabilities.
+ */
+abstract class UncontrolledFormatStringSink extends DataFlow::Node { }
+
+/**
+ * A sanitizer for uncontrolled format string vulnerabilities.
+ */
+abstract class UncontrolledFormatStringSanitizer extends DataFlow::Node { }
+
+/**
+ * A unit class for adding additional taint steps.
+ */
+class UncontrolledFormatStringAdditionalTaintStep extends Unit {
+ abstract predicate step(DataFlow::Node nodeFrom, DataFlow::Node nodeTo);
+}
+
+/**
+ * A default uncontrolled format string sink, that is, the format argument to
+ * a `FormattingFunctionCall`.
+ */
+private class DefaultUncontrolledFormatStringSink extends UncontrolledFormatStringSink {
+ DefaultUncontrolledFormatStringSink() {
+ this.asExpr() = any(FormattingFunctionCall fc).getFormat()
+ }
+}
diff --git a/swift/ql/lib/codeql/swift/security/UncontrolledFormatStringQuery.qll b/swift/ql/lib/codeql/swift/security/UncontrolledFormatStringQuery.qll
index 41ff57f2084..bb8aee50ac4 100644
--- a/swift/ql/lib/codeql/swift/security/UncontrolledFormatStringQuery.qll
+++ b/swift/ql/lib/codeql/swift/security/UncontrolledFormatStringQuery.qll
@@ -8,6 +8,7 @@ import codeql.swift.StringFormat
import codeql.swift.dataflow.DataFlow
import codeql.swift.dataflow.TaintTracking
import codeql.swift.dataflow.FlowSources
+import codeql.swift.security.UncontrolledFormatStringExtensions
/**
* A taint configuration for tainted data that reaches a format string.
@@ -17,7 +18,13 @@ class TaintedFormatConfiguration extends TaintTracking::Configuration {
override predicate isSource(DataFlow::Node node) { node instanceof FlowSource }
- override predicate isSink(DataFlow::Node node) {
- node.asExpr() = any(FormattingFunctionCall fc).getFormat()
+ override predicate isSink(DataFlow::Node node) { node instanceof UncontrolledFormatStringSink }
+
+ override predicate isSanitizer(DataFlow::Node sanitizer) {
+ sanitizer instanceof UncontrolledFormatStringSanitizer
+ }
+
+ override predicate isAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
+ any(UncontrolledFormatStringAdditionalTaintStep s).step(nodeFrom, nodeTo)
}
}
From 07ea006cee9530b00ce55297838742c6b32a5920 Mon Sep 17 00:00:00 2001
From: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
Date: Thu, 8 Dec 2022 11:36:55 +0000
Subject: [PATCH 027/381] Swift: Add support for CSV modelled sinks as well.
---
.../UncontrolledFormatStringExtensions.qll | 14 +++++++++-----
1 file changed, 9 insertions(+), 5 deletions(-)
diff --git a/swift/ql/lib/codeql/swift/security/UncontrolledFormatStringExtensions.qll b/swift/ql/lib/codeql/swift/security/UncontrolledFormatStringExtensions.qll
index 3e9572ab37d..4f8c70f81c4 100644
--- a/swift/ql/lib/codeql/swift/security/UncontrolledFormatStringExtensions.qll
+++ b/swift/ql/lib/codeql/swift/security/UncontrolledFormatStringExtensions.qll
@@ -4,9 +4,10 @@
*/
import swift
-import codeql.swift.StringFormat
-import codeql.swift.dataflow.DataFlow
-import codeql.swift.dataflow.TaintTracking
+private import codeql.swift.StringFormat
+private import codeql.swift.dataflow.DataFlow
+private import codeql.swift.dataflow.TaintTracking
+private import codeql.swift.dataflow.ExternalFlow
/**
* A dataflow sink for uncontrolled format string vulnerabilities.
@@ -26,11 +27,14 @@ class UncontrolledFormatStringAdditionalTaintStep extends Unit {
}
/**
- * A default uncontrolled format string sink, that is, the format argument to
- * a `FormattingFunctionCall`.
+ * A default uncontrolled format string sink.
*/
private class DefaultUncontrolledFormatStringSink extends UncontrolledFormatStringSink {
DefaultUncontrolledFormatStringSink() {
+ // the format argument to a `FormattingFunctionCall`.
this.asExpr() = any(FormattingFunctionCall fc).getFormat()
+ or
+ // a sink defined in a Csv model.
+ sinkNode(this, "uncontrolled-format-string")
}
}
From 24ce1c27bc084eb1c1f62aee2d8cbcc5f1b1d485 Mon Sep 17 00:00:00 2001
From: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
Date: Thu, 8 Dec 2022 13:09:37 +0000
Subject: [PATCH 028/381] Swift: Autoformat.
---
swift/ql/lib/codeql/swift/StringFormat.qll | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/swift/ql/lib/codeql/swift/StringFormat.qll b/swift/ql/lib/codeql/swift/StringFormat.qll
index 4dbb127fc69..41eeb6efdcd 100644
--- a/swift/ql/lib/codeql/swift/StringFormat.qll
+++ b/swift/ql/lib/codeql/swift/StringFormat.qll
@@ -1,7 +1,7 @@
/**
* Provides classes and predicates for reasoning about string formatting.
*/
-
+
import swift
/**
From 219ed64b7414a7b06424b80370bfef867df4e326 Mon Sep 17 00:00:00 2001
From: Paolo Tranquilli
Date: Thu, 8 Dec 2022 11:00:00 +0100
Subject: [PATCH 029/381] Swift: reorganize bazel third party dependencies
---
misc/bazel/workspace.bzl | 42 +--------------
swift/third_party/BUILD.bazel | 0
swift/third_party/load.bzl | 52 +++++++++++++++++++
...t.bazel => BUILD.swift-llvm-support.bazel} | 0
4 files changed, 54 insertions(+), 40 deletions(-)
create mode 100644 swift/third_party/BUILD.bazel
create mode 100644 swift/third_party/load.bzl
rename swift/third_party/swift-llvm-support/{BUILD.swift-prebuilt.bazel => BUILD.swift-llvm-support.bazel} (100%)
diff --git a/misc/bazel/workspace.bzl b/misc/bazel/workspace.bzl
index d0aee216668..46426f48d5c 100644
--- a/misc/bazel/workspace.bzl
+++ b/misc/bazel/workspace.bzl
@@ -1,47 +1,9 @@
load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe")
-
-_swift_prebuilt_version = "swift-5.7.1-RELEASE.44428.89"
-_swift_sha_map = {
- "Linux-X64": "1fa0b62b3a87c6528bd21b3f3fa1b32ad00e2b6ff04c20652c93c7d00c4cf517",
- "macOS-X64": "6e1239335874cbde635ae9ca9eeb215efee4988888a75f4eda1abbcf97e4d038",
-}
-
-_swift_arch_map = {
- "Linux-X64": "linux",
- "macOS-X64": "darwin_x86_64",
-}
+load("//swift/third_party:load.bzl", load_swift_dependencies = "load_dependencies")
def codeql_workspace(repository_name = "codeql"):
- for repo_arch, arch in _swift_arch_map.items():
- sha256 = _swift_sha_map[repo_arch]
-
- http_archive(
- name = "swift_prebuilt_%s" % arch,
- url = "https://github.com/dsp-testing/codeql-swift-artifacts/releases/download/%s/swift-prebuilt-%s.zip" % (
- _swift_prebuilt_version,
- repo_arch,
- ),
- build_file = "@%s//swift/third_party/swift-llvm-support:BUILD.swift-prebuilt.bazel" % repository_name,
- sha256 = sha256,
- )
-
- http_archive(
- name = "fishhook",
- url = "https://github.com/facebook/fishhook/archive/aadc161ac3b80db07a9908851839a17ba63a9eb1.zip",
- build_file = "@%s//swift/third_party/fishhook:BUILD.fishhook.bazel" % repository_name,
- strip_prefix = "fishhook-aadc161ac3b80db07a9908851839a17ba63a9eb1",
- sha256 = "9f2cdee6dcc2039d4c47d25ab5141fe0678ce6ed27ef482cab17fe9fa38a30ce",
- )
-
- http_archive(
- name = "picosha2",
- url = "https://github.com/okdshin/PicoSHA2/archive/27fcf6979298949e8a462e16d09a0351c18fcaf2.zip",
- strip_prefix = "PicoSHA2-27fcf6979298949e8a462e16d09a0351c18fcaf2",
- build_file = "@%s//swift/third_party/picosha2:BUILD.picosha2.bazel" % repository_name,
- sha256 = "d6647ca45a8b7bdaf027ecb68d041b22a899a0218b7206dee755c558a2725abb",
- )
-
+ load_swift_dependencies(repository_name)
maybe(
repo_rule = http_archive,
name = "rules_pkg",
diff --git a/swift/third_party/BUILD.bazel b/swift/third_party/BUILD.bazel
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/swift/third_party/load.bzl b/swift/third_party/load.bzl
new file mode 100644
index 00000000000..8621ee65b07
--- /dev/null
+++ b/swift/third_party/load.bzl
@@ -0,0 +1,52 @@
+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
+
+_swift_prebuilt_version = "swift-5.7.1-RELEASE.44428.89"
+_swift_sha_map = {
+ "Linux-X64": "1fa0b62b3a87c6528bd21b3f3fa1b32ad00e2b6ff04c20652c93c7d00c4cf517",
+ "macOS-X64": "6e1239335874cbde635ae9ca9eeb215efee4988888a75f4eda1abbcf97e4d038",
+}
+
+_swift_arch_map = {
+ "Linux-X64": "linux",
+ "macOS-X64": "darwin_x86_64",
+}
+
+def _get_label(repository_name, package, target):
+ return "@%s//swift/third_party/%s:%s" % (repository_name, package, target)
+
+def _get_build(repository_name, package):
+ return _get_label(repository_name, package, "BUILD.%s.bazel" % package)
+
+def _get_patch(repository_name, package, patch):
+ return _get_label(repository_name, package, "patches/%s.patch" % patch)
+
+def load_dependencies(repository_name):
+ for repo_arch, arch in _swift_arch_map.items():
+ sha256 = _swift_sha_map[repo_arch]
+
+ http_archive(
+ name = "swift_prebuilt_%s" % arch,
+ url = "https://github.com/dsp-testing/codeql-swift-artifacts/releases/download/%s/swift-prebuilt-%s.zip" % (
+ _swift_prebuilt_version,
+ repo_arch,
+ ),
+ build_file = _get_build(repository_name, "swift-llvm-support"),
+ sha256 = sha256,
+ patch_args = ["-p1"],
+ )
+
+ http_archive(
+ name = "fishhook",
+ url = "https://github.com/facebook/fishhook/archive/aadc161ac3b80db07a9908851839a17ba63a9eb1.zip",
+ build_file = "@%s//swift/third_party/fishhook:BUILD.fishhook.bazel" % repository_name,
+ strip_prefix = "fishhook-aadc161ac3b80db07a9908851839a17ba63a9eb1",
+ sha256 = "9f2cdee6dcc2039d4c47d25ab5141fe0678ce6ed27ef482cab17fe9fa38a30ce",
+ )
+
+ http_archive(
+ name = "picosha2",
+ url = "https://github.com/okdshin/PicoSHA2/archive/27fcf6979298949e8a462e16d09a0351c18fcaf2.zip",
+ strip_prefix = "PicoSHA2-27fcf6979298949e8a462e16d09a0351c18fcaf2",
+ build_file = _get_build(repository_name, "picosha2"),
+ sha256 = "d6647ca45a8b7bdaf027ecb68d041b22a899a0218b7206dee755c558a2725abb",
+ )
diff --git a/swift/third_party/swift-llvm-support/BUILD.swift-prebuilt.bazel b/swift/third_party/swift-llvm-support/BUILD.swift-llvm-support.bazel
similarity index 100%
rename from swift/third_party/swift-llvm-support/BUILD.swift-prebuilt.bazel
rename to swift/third_party/swift-llvm-support/BUILD.swift-llvm-support.bazel
From 944adfe727793f432868875ce0c3efaa36cdedb7 Mon Sep 17 00:00:00 2001
From: Paolo Tranquilli
Date: Thu, 8 Dec 2022 11:14:22 +0100
Subject: [PATCH 030/381] Swift: allow modifying frontend outputs
---
swift/third_party/load.bzl | 3 +++
.../patches/allow_modfying_output.patch | 12 ++++++++++++
2 files changed, 15 insertions(+)
create mode 100644 swift/third_party/swift-llvm-support/patches/allow_modfying_output.patch
diff --git a/swift/third_party/load.bzl b/swift/third_party/load.bzl
index 8621ee65b07..fbd98b6aedb 100644
--- a/swift/third_party/load.bzl
+++ b/swift/third_party/load.bzl
@@ -33,6 +33,9 @@ def load_dependencies(repository_name):
build_file = _get_build(repository_name, "swift-llvm-support"),
sha256 = sha256,
patch_args = ["-p1"],
+ patches = [
+ _get_patch(repository_name, "swift-llvm-support", "allow_modfying_output"),
+ ],
)
http_archive(
diff --git a/swift/third_party/swift-llvm-support/patches/allow_modfying_output.patch b/swift/third_party/swift-llvm-support/patches/allow_modfying_output.patch
new file mode 100644
index 00000000000..9a7e4e0964a
--- /dev/null
+++ b/swift/third_party/swift-llvm-support/patches/allow_modfying_output.patch
@@ -0,0 +1,12 @@
+We want to be able to redirect module output options to an internal artifact storage.
+--- a/include/swift/Frontend/FrontendInputsAndOutputs.h 2022-11-30 12:57:18.000000000 +0100
++++ b/include/swift/Frontend/FrontendInputsAndOutputs.h 2022-12-08 10:30:43.286040435 +0100
+@@ -182,8 +182,6 @@
+ llvm::MemoryBuffer *buffer = nullptr);
+
+ // Outputs
+-
+-private:
+ friend class ArgsToFrontendOptionsConverter;
+ friend struct InterfaceSubContextDelegateImpl;
+ void setMainAndSupplementaryOutputs(
From bf1b32f210c7390a16859611b52e83823c7965cc Mon Sep 17 00:00:00 2001
From: Paolo Tranquilli
Date: Mon, 5 Dec 2022 17:22:45 +0100
Subject: [PATCH 031/381] Swift: rework file redirection
The hash map mechanism that was already in use for reading swiftmodule
files on macOS is now in use also on Linux. The output replacing
mechanism has been also reworked so that:
* frontend module emission modes have the remapping done directly in
the internal frontend options instead of painstakingly modifying input
flags (this requires a patch on the swift headers though)
* object emission mode is silenced to be just a type checking pass,
thus producing no output files
* all other passes but some debugging and version related ones become
noops
The open file read redirection uses a global weak pointer instance to
maximize robustness in the face of possibly multi-threaded calls to open
happening while `main` is exiting. Possibly overkill, but better safe
than sorry.
---
swift/extractor/BUILD.bazel | 1 +
swift/extractor/SwiftExtractor.h | 2 +-
swift/extractor/TargetTrapFile.cpp | 5 -
swift/extractor/TargetTrapFile.h | 2 +-
swift/extractor/config/BUILD.bazel | 8 +
.../SwiftExtractorConfiguration.h | 4 +-
swift/extractor/main.cpp | 106 +++++++-----
swift/extractor/remapping/BUILD.bazel | 18 +-
.../remapping/SwiftFileInterception.cpp | 160 ++++++++++++++++++
.../remapping/SwiftFileInterception.h | 19 +++
.../remapping/SwiftOpenInterception.Linux.cpp | 9 -
.../remapping/SwiftOpenInterception.h | 15 --
.../remapping/SwiftOpenInterception.macOS.cpp | 85 ----------
.../remapping/SwiftOutputRewrite.cpp | 137 ---------------
.../extractor/remapping/SwiftOutputRewrite.h | 21 ---
.../posix-only/frontend-invocations/F1.swift | 1 +
.../posix-only/frontend-invocations/F2.swift | 1 +
.../posix-only/frontend-invocations/build.sh | 2 +-
18 files changed, 263 insertions(+), 333 deletions(-)
create mode 100644 swift/extractor/config/BUILD.bazel
rename swift/extractor/{ => config}/SwiftExtractorConfiguration.h (88%)
create mode 100644 swift/extractor/remapping/SwiftFileInterception.cpp
create mode 100644 swift/extractor/remapping/SwiftFileInterception.h
delete mode 100644 swift/extractor/remapping/SwiftOpenInterception.Linux.cpp
delete mode 100644 swift/extractor/remapping/SwiftOpenInterception.h
delete mode 100644 swift/extractor/remapping/SwiftOpenInterception.macOS.cpp
delete mode 100644 swift/extractor/remapping/SwiftOutputRewrite.cpp
delete mode 100644 swift/extractor/remapping/SwiftOutputRewrite.h
diff --git a/swift/extractor/BUILD.bazel b/swift/extractor/BUILD.bazel
index 2e6d93adf8c..101e8657c3f 100644
--- a/swift/extractor/BUILD.bazel
+++ b/swift/extractor/BUILD.bazel
@@ -9,6 +9,7 @@ swift_cc_binary(
]),
visibility = ["//swift:__pkg__"],
deps = [
+ "//swift/extractor/config",
"//swift/extractor/infra",
"//swift/extractor/invocation",
"//swift/extractor/remapping",
diff --git a/swift/extractor/SwiftExtractor.h b/swift/extractor/SwiftExtractor.h
index f8c6dbfb6c7..d59c3163390 100644
--- a/swift/extractor/SwiftExtractor.h
+++ b/swift/extractor/SwiftExtractor.h
@@ -1,6 +1,6 @@
#pragma once
-#include "swift/extractor/SwiftExtractorConfiguration.h"
+#include "swift/extractor/config/SwiftExtractorConfiguration.h"
#include
#include
#include
diff --git a/swift/extractor/TargetTrapFile.cpp b/swift/extractor/TargetTrapFile.cpp
index d1f1ca8520b..4677568c248 100644
--- a/swift/extractor/TargetTrapFile.cpp
+++ b/swift/extractor/TargetTrapFile.cpp
@@ -11,11 +11,6 @@ std::optional createTargetTrapFile(const SwiftExtractorConfiguration
for (const auto& opt : configuration.frontendOptions) {
*ret << " " << std::quoted(opt) << " \\\n";
}
- *ret << "\n*/\n"
- "/* swift-frontend-args:\n";
- for (const auto& opt : configuration.patchedFrontendOptions) {
- *ret << " " << std::quoted(opt) << " \\\n";
- }
*ret << "\n*/\n";
}
return ret;
diff --git a/swift/extractor/TargetTrapFile.h b/swift/extractor/TargetTrapFile.h
index 8e4f99fcad2..f8cf5bf4277 100644
--- a/swift/extractor/TargetTrapFile.h
+++ b/swift/extractor/TargetTrapFile.h
@@ -1,7 +1,7 @@
#pragma once
#include "swift/extractor/infra/file/TargetFile.h"
-#include "swift/extractor/SwiftExtractorConfiguration.h"
+#include "swift/extractor/config/SwiftExtractorConfiguration.h"
namespace codeql {
diff --git a/swift/extractor/config/BUILD.bazel b/swift/extractor/config/BUILD.bazel
new file mode 100644
index 00000000000..492db13f666
--- /dev/null
+++ b/swift/extractor/config/BUILD.bazel
@@ -0,0 +1,8 @@
+load("//swift:rules.bzl", "swift_cc_library")
+
+swift_cc_library(
+ name = "config",
+ srcs = glob(["*.cpp"]),
+ hdrs = glob(["*.h"]),
+ visibility = ["//swift:__subpackages__"],
+)
diff --git a/swift/extractor/SwiftExtractorConfiguration.h b/swift/extractor/config/SwiftExtractorConfiguration.h
similarity index 88%
rename from swift/extractor/SwiftExtractorConfiguration.h
rename to swift/extractor/config/SwiftExtractorConfiguration.h
index 04179d8c0c5..b9456148c89 100644
--- a/swift/extractor/SwiftExtractorConfiguration.h
+++ b/swift/extractor/config/SwiftExtractorConfiguration.h
@@ -17,9 +17,7 @@ struct SwiftExtractorConfiguration {
std::filesystem::path scratchDir;
// The original arguments passed to the extractor. Used for debugging.
- std::vector frontendOptions;
- // The patched arguments passed to the swift::performFrontend/ Used for debugging.
- std::vector patchedFrontendOptions;
+ std::vector frontendOptions;
// A temporary directory that contains TRAP files before they are moved into their final
// destination.
diff --git a/swift/extractor/main.cpp b/swift/extractor/main.cpp
index ff975f5c25d..fff97ba9f51 100644
--- a/swift/extractor/main.cpp
+++ b/swift/extractor/main.cpp
@@ -12,13 +12,58 @@
#include "swift/extractor/SwiftExtractor.h"
#include "swift/extractor/TargetTrapFile.h"
-#include "swift/extractor/remapping/SwiftOutputRewrite.h"
-#include "swift/extractor/remapping/SwiftOpenInterception.h"
+#include "swift/extractor/remapping/SwiftFileInterception.h"
#include "swift/extractor/invocation/SwiftDiagnosticsConsumer.h"
#include "swift/extractor/trap/TrapDomain.h"
using namespace std::string_literals;
+static void lockOutputSwiftModuleTraps(const codeql::SwiftExtractorConfiguration& config,
+ const swift::CompilerInstance& compiler) {
+ std::filesystem::path output = compiler.getInvocation().getOutputFilename();
+ if (output.extension() == ".swiftmodule") {
+ if (auto target = codeql::createTargetTrapFile(config, output)) {
+ *target << "// trap file deliberately empty\n"
+ "// this swiftmodule was created during the build, so its entities must have"
+ " been extracted directly from source files";
+ }
+ }
+}
+
+static void modifyFrontendOptions(swift::FrontendOptions& options) {
+ using Action = swift::FrontendOptions::ActionType;
+ switch (options.RequestedAction) {
+ case Action::EmitModuleOnly:
+ case Action::MergeModules:
+ case Action::CompileModuleFromInterface:
+ // for module emission actions, we redirect the output to our internal artifact storage
+ {
+ swift::SupplementaryOutputPaths paths;
+ paths.ModuleOutputPath =
+ codeql::redirect(options.InputsAndOutputs.getSingleOutputFilename()).string();
+ options.InputsAndOutputs.setMainAndSupplementaryOutputs(std::vector{paths.ModuleOutputPath},
+ std::vector{paths});
+ return;
+ }
+ case Action::EmitObject:
+ // for object emission, we do a type check pass instead, muting output but getting the sema
+ // phase to run in order to extract everything
+ options.RequestedAction = Action::Typecheck;
+ return;
+ case Action::PrintVersion:
+ case Action::DumpAST:
+ case Action::PrintAST:
+ case Action::PrintASTDecl:
+ // these actions are nice to have on the extractor for debugging, so we preserve them. Also,
+ // version printing is used by CI to match up the correct compiler version
+ return;
+ default:
+ // otherwise, do nothing (the closest action to doing nothing is printing the version)
+ options.RequestedAction = Action::PrintVersion;
+ break;
+ }
+}
+
// This is part of the swiftFrontendTool interface, we hook into the
// compilation pipeline and extract files after the Swift frontend performed
// semantic analysis
@@ -28,8 +73,13 @@ class Observer : public swift::FrontendObserver {
codeql::SwiftDiagnosticsConsumer& diagConsumer)
: config{config}, diagConsumer{diagConsumer} {}
+ void parsedArgs(swift::CompilerInvocation& invocation) override {
+ modifyFrontendOptions(invocation.getFrontendOptions());
+ }
+
void configuredCompiler(swift::CompilerInstance& instance) override {
instance.addDiagnosticConsumer(&diagConsumer);
+ lockOutputSwiftModuleTraps(config, instance);
}
void performedSemanticAnalysis(swift::CompilerInstance& compiler) override {
@@ -48,19 +98,6 @@ static std::string getenv_or(const char* envvar, const std::string& def) {
return def;
}
-static void lockOutputSwiftModuleTraps(const codeql::SwiftExtractorConfiguration& config,
- const codeql::PathRemapping& remapping) {
- for (const auto& [oldPath, newPath] : remapping) {
- if (oldPath.extension() == ".swiftmodule") {
- if (auto target = codeql::createTargetTrapFile(config, oldPath)) {
- *target << "// trap file deliberately empty\n"
- "// this swiftmodule was created during the build, so its entities must have"
- " been extracted directly from source files";
- }
- }
- }
-}
-
static bool checkRunUnderFilter(int argc, char* const* argv) {
auto runUnderFilter = getenv("CODEQL_EXTRACTOR_SWIFT_RUN_UNDER_FILTER");
if (runUnderFilter == nullptr) {
@@ -106,7 +143,7 @@ static void checkWhetherToRunUnderTool(int argc, char* const* argv) {
// Creates a target file that should store per-invocation info, e.g. compilation args,
// compilations, diagnostics, etc.
-codeql::TargetFile invocationTargetFile(codeql::SwiftExtractorConfiguration& configuration) {
+codeql::TargetFile invocationTargetFile(const codeql::SwiftExtractorConfiguration& configuration) {
auto timestamp = std::chrono::system_clock::now().time_since_epoch().count();
auto filename = std::to_string(timestamp) + '-' + std::to_string(getpid());
auto target = std::filesystem::path("invocations") / std::filesystem::path(filename);
@@ -118,6 +155,15 @@ codeql::TargetFile invocationTargetFile(codeql::SwiftExtractorConfiguration& con
return std::move(maybeFile.value());
}
+codeql::SwiftExtractorConfiguration configure(int argc, char** argv) {
+ codeql::SwiftExtractorConfiguration configuration{};
+ configuration.trapDir = getenv_or("CODEQL_EXTRACTOR_SWIFT_TRAP_DIR", ".");
+ configuration.sourceArchiveDir = getenv_or("CODEQL_EXTRACTOR_SWIFT_SOURCE_ARCHIVE_DIR", ".");
+ configuration.scratchDir = getenv_or("CODEQL_EXTRACTOR_SWIFT_SCRATCH_DIR", ".");
+ configuration.frontendOptions.assign(argv + 1, argv + argc);
+ return configuration;
+}
+
int main(int argc, char** argv) {
checkWhetherToRunUnderTool(argc, argv);
@@ -130,36 +176,16 @@ int main(int argc, char** argv) {
PROGRAM_START(argc, argv);
INITIALIZE_LLVM();
- codeql::SwiftExtractorConfiguration configuration{};
- configuration.trapDir = getenv_or("CODEQL_EXTRACTOR_SWIFT_TRAP_DIR", ".");
- configuration.sourceArchiveDir = getenv_or("CODEQL_EXTRACTOR_SWIFT_SOURCE_ARCHIVE_DIR", ".");
- configuration.scratchDir = getenv_or("CODEQL_EXTRACTOR_SWIFT_SCRATCH_DIR", ".");
+ const auto configuration = configure(argc, argv);
- codeql::initRemapping(configuration.getTempArtifactDir());
-
- configuration.frontendOptions.reserve(argc - 1);
- for (int i = 1; i < argc; i++) {
- configuration.frontendOptions.push_back(argv[i]);
- }
- configuration.patchedFrontendOptions = configuration.frontendOptions;
-
- auto remapping = codeql::rewriteOutputsInPlace(configuration.getTempArtifactDir(),
- configuration.patchedFrontendOptions);
- codeql::ensureDirectoriesForNewPathsExist(remapping);
- lockOutputSwiftModuleTraps(configuration, remapping);
-
- std::vector args;
- for (auto& arg : configuration.patchedFrontendOptions) {
- args.push_back(arg.c_str());
- }
+ auto openInterception = codeql::setupFileInterception(configuration.getTempArtifactDir());
auto invocationTrapFile = invocationTargetFile(configuration);
codeql::TrapDomain invocationDomain(invocationTrapFile);
codeql::SwiftDiagnosticsConsumer diagConsumer(invocationDomain);
Observer observer(configuration, diagConsumer);
- int frontend_rc = swift::performFrontend(args, "swift-extractor", (void*)main, &observer);
-
- codeql::finalizeRemapping(remapping);
+ int frontend_rc = swift::performFrontend(configuration.frontendOptions, "swift-extractor",
+ (void*)main, &observer);
return frontend_rc;
}
diff --git a/swift/extractor/remapping/BUILD.bazel b/swift/extractor/remapping/BUILD.bazel
index 84f942f7708..dafd1f9e3a9 100644
--- a/swift/extractor/remapping/BUILD.bazel
+++ b/swift/extractor/remapping/BUILD.bazel
@@ -2,23 +2,11 @@ load("//swift:rules.bzl", "swift_cc_library")
swift_cc_library(
name = "remapping",
- srcs = ["SwiftOutputRewrite.cpp"] + select({
- "@platforms//os:linux": [
- "SwiftOpenInterception.Linux.cpp",
- ],
- "@platforms//os:macos": [
- "SwiftOpenInterception.macOS.cpp",
- ],
- }),
+ srcs = glob(["*.cpp"]),
hdrs = glob(["*.h"]),
visibility = ["//swift:__subpackages__"],
deps = [
- "//swift/third_party/swift-llvm-support",
"//swift/extractor/infra/file",
- ] + select({
- "@platforms//os:linux": [],
- "@platforms//os:macos": [
- "@fishhook//:fishhook",
- ],
- }),
+ "//swift/third_party/swift-llvm-support",
+ ],
)
diff --git a/swift/extractor/remapping/SwiftFileInterception.cpp b/swift/extractor/remapping/SwiftFileInterception.cpp
new file mode 100644
index 00000000000..5743826fb22
--- /dev/null
+++ b/swift/extractor/remapping/SwiftFileInterception.cpp
@@ -0,0 +1,160 @@
+#include "swift/extractor/remapping/SwiftFileInterception.h"
+
+#include
+#include
+
+#include
+#include
+#include
+#include
+
+#include "swift/extractor/infra/file/FileHash.h"
+#include "swift/extractor/infra/file/FileHash.h"
+
+#ifdef __APPLE__
+#define SHARED_LIBC "libc.dylib"
+#define FILE_CREATION_MODE O_CREAT
+#else
+#define SHARED_LIBC "libc.so.6"
+#define FILE_CREATION_MODE (O_CREAT | O_TMPFILE)
+#endif
+
+namespace fs = std::filesystem;
+
+namespace {
+namespace original {
+
+void* libc() {
+ static auto ret = dlopen(SHARED_LIBC, RTLD_LAZY);
+ return ret;
+}
+
+template
+Signature get(const char* name) {
+ return reinterpret_cast(dlsym(libc(), name));
+}
+
+int open(const char* path, int flags, mode_t mode = 0) {
+ static auto original = get("open");
+ return original(path, flags, mode);
+}
+
+} // namespace original
+
+bool endsWith(const std::string_view& s, const std::string_view& suffix) {
+ return s.size() >= suffix.size() && s.substr(s.size() - suffix.size()) == suffix;
+}
+
+auto& fileInterceptorInstance() {
+ static std::weak_ptr ret{};
+ return ret;
+}
+
+bool mayBeRedirected(const char* path, int flags = O_RDONLY) {
+ return (!fileInterceptorInstance().expired() && (flags & O_ACCMODE) == O_RDONLY &&
+ endsWith(path, ".swiftmodule"));
+}
+
+} // namespace
+
+namespace codeql {
+
+class FileInterceptor {
+ public:
+ FileInterceptor(fs::path&& workingDir) : workingDir{std::move(workingDir)} {
+ fs::create_directories(hashesPath());
+ fs::create_directories(storePath());
+ }
+
+ int open(const char* path, int flags, mode_t mode = 0) const {
+ fs::path fsPath{path};
+ assert((flags & O_ACCMODE) == O_RDONLY);
+ errno = 0;
+ // first, try the same path underneath the artifact store
+ if (auto ret = original::open(redirectedPath(path).c_str(), flags);
+ ret >= 0 || errno != ENOENT) {
+ return ret;
+ }
+ errno = 0;
+ // then try to use the hash map
+ if (auto hashed = hashPath(path)) {
+ if (auto ret = original::open(hashed->c_str(), flags); ret >= 0 || errno != ENOENT) {
+ return ret;
+ }
+ }
+ return original::open(path, flags, mode);
+ }
+
+ fs::path redirect(const fs::path& target) const {
+ assert(mayBeRedirected(target.c_str()));
+ auto ret = redirectedPath(target);
+ fs::create_directories(ret.parent_path());
+ if (auto hashed = hashPath(target)) {
+ std::error_code ec;
+ fs::create_symlink(ret, *hashed, ec);
+ if (ec) {
+ std::cerr << "Cannot remap file " << ret << " -> " << *hashed << ": " << ec.message()
+ << "\n";
+ }
+ }
+ return ret;
+ }
+
+ private:
+ fs::path hashesPath() const { return workingDir / "hashes"; }
+
+ fs::path storePath() const { return workingDir / "store"; }
+
+ fs::path redirectedPath(const fs::path& target) const {
+ return storePath() / target.relative_path();
+ }
+
+ std::optional hashPath(const fs::path& target) const {
+ if (auto fd = original::open(target.c_str(), O_RDONLY | O_CLOEXEC); fd >= 0) {
+ return hashesPath() / hashFile(fd);
+ }
+ return std::nullopt;
+ }
+
+ fs::path workingDir;
+};
+
+int openReal(const fs::path& path) {
+ return original::open(path.c_str(), O_RDONLY | O_CLOEXEC);
+}
+
+fs::path redirect(const fs::path& target) {
+ if (auto interceptor = fileInterceptorInstance().lock()) {
+ return interceptor->redirect(target);
+ } else {
+ return target;
+ }
+}
+
+std::shared_ptr setupFileInterception(fs::path workginDir) {
+ auto ret = std::make_shared(std::move(workginDir));
+ fileInterceptorInstance() = ret;
+ return ret;
+}
+} // namespace codeql
+
+extern "C" {
+int open(const char* path, int flags, ...) {
+ mode_t mode = 0;
+ if (flags & FILE_CREATION_MODE) {
+ va_list ap;
+ // mode only applies when creating a file
+ va_start(ap, flags);
+ mode = va_arg(ap, int);
+ va_end(ap);
+ }
+
+ if (mayBeRedirected(path, flags)) {
+ if (auto interceptor = fileInterceptorInstance().lock()) {
+ return interceptor->open(path, flags, mode);
+ }
+ }
+ return original::open(path, flags, mode);
+}
+
+} // namespace codeql
diff --git a/swift/extractor/remapping/SwiftFileInterception.h b/swift/extractor/remapping/SwiftFileInterception.h
new file mode 100644
index 00000000000..80a298d454f
--- /dev/null
+++ b/swift/extractor/remapping/SwiftFileInterception.h
@@ -0,0 +1,19 @@
+#pragma once
+
+#include
+#include
+#include
+#include
+
+#include "swift/extractor/infra/file/PathHash.h"
+
+namespace codeql {
+
+int openReal(const std::filesystem::path& path);
+
+class FileInterceptor;
+
+std::shared_ptr setupFileInterception(std::filesystem::path workingDir);
+
+std::filesystem::path redirect(const std::filesystem::path& target);
+} // namespace codeql
diff --git a/swift/extractor/remapping/SwiftOpenInterception.Linux.cpp b/swift/extractor/remapping/SwiftOpenInterception.Linux.cpp
deleted file mode 100644
index 9304e027f0d..00000000000
--- a/swift/extractor/remapping/SwiftOpenInterception.Linux.cpp
+++ /dev/null
@@ -1,9 +0,0 @@
-#include "swift/extractor/remapping/SwiftOpenInterception.h"
-
-namespace codeql {
-// TBD
-void initRemapping(const std::filesystem::path& dir) {}
-void finalizeRemapping(
- const std::unordered_map& mapping) {}
-
-} // namespace codeql
diff --git a/swift/extractor/remapping/SwiftOpenInterception.h b/swift/extractor/remapping/SwiftOpenInterception.h
deleted file mode 100644
index e477e3996e1..00000000000
--- a/swift/extractor/remapping/SwiftOpenInterception.h
+++ /dev/null
@@ -1,15 +0,0 @@
-#pragma once
-
-#include
-#include
-#include
-
-#include "swift/extractor/infra/file/PathHash.h"
-
-namespace codeql {
-
-void initRemapping(const std::filesystem::path& dir);
-void finalizeRemapping(
- const std::unordered_map& mapping);
-
-} // namespace codeql
diff --git a/swift/extractor/remapping/SwiftOpenInterception.macOS.cpp b/swift/extractor/remapping/SwiftOpenInterception.macOS.cpp
deleted file mode 100644
index d378a571e58..00000000000
--- a/swift/extractor/remapping/SwiftOpenInterception.macOS.cpp
+++ /dev/null
@@ -1,85 +0,0 @@
-#include "swift/extractor/remapping/SwiftOpenInterception.h"
-
-#include
-
-#include
-#include
-#include
-
-#include "swift/extractor/infra/file/FileHash.h"
-
-namespace fs = std::filesystem;
-
-namespace codeql {
-
-static fs::path scratchDir;
-static bool interceptionEnabled = false;
-
-static int (*original_open)(const char*, int, ...) = nullptr;
-
-static std::string originalHashFile(const fs::path& filename) {
- int fd = original_open(filename.c_str(), O_RDONLY);
- if (fd == -1) {
- return {};
- }
-
- return hashFile(fd);
-}
-
-static int codeql_open(const char* path, int oflag, ...) {
- va_list ap;
- mode_t mode = 0;
- if ((oflag & O_CREAT) != 0) {
- // mode only applies to O_CREAT
- va_start(ap, oflag);
- mode = va_arg(ap, int);
- va_end(ap);
- }
-
- fs::path newPath(path);
-
- if (interceptionEnabled && fs::exists(newPath)) {
- // TODO: check file magic instead
- if (newPath.extension() == ".swiftmodule") {
- auto hash = originalHashFile(newPath);
- auto hashed = scratchDir / hash;
- if (!hash.empty() && fs::exists(hashed)) {
- newPath = hashed;
- }
- }
- }
-
- return original_open(newPath.c_str(), oflag, mode);
-}
-
-void finalizeRemapping(
- const std::unordered_map& mapping) {
- for (auto& [original, patched] : mapping) {
- // TODO: Check file magic instead
- if (original.extension() != ".swiftmodule") {
- continue;
- }
- auto hash = originalHashFile(original);
- auto hashed = scratchDir / hash;
- if (!hash.empty() && fs::exists(patched)) {
- std::error_code ec;
- fs::create_symlink(/* target */ patched, /* symlink */ hashed, ec);
- if (ec) {
- std::cerr << "Cannot remap file '" << patched << "' -> '" << hashed << "': " << ec.message()
- << "\n";
- }
- }
- }
- interceptionEnabled = false;
-}
-
-void initRemapping(const std::filesystem::path& dir) {
- scratchDir = dir;
-
- struct rebinding binding[] = {
- {"open", reinterpret_cast(codeql_open), reinterpret_cast(&original_open)}};
- rebind_symbols(binding, 1);
- interceptionEnabled = true;
-}
-
-} // namespace codeql
diff --git a/swift/extractor/remapping/SwiftOutputRewrite.cpp b/swift/extractor/remapping/SwiftOutputRewrite.cpp
deleted file mode 100644
index 914a54d93f1..00000000000
--- a/swift/extractor/remapping/SwiftOutputRewrite.cpp
+++ /dev/null
@@ -1,137 +0,0 @@
-#include "swift/extractor/remapping/SwiftOutputRewrite.h"
-
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include "swift/extractor/infra/file/PathHash.h"
-
-namespace fs = std::filesystem;
-
-namespace codeql {
-
-// Creates a copy of the output file map and updates remapping table in place
-// It does not change the original map file as it is depended upon by the original compiler
-// Returns path to the newly created output file map on success, or None in a case of failure
-static std::optional rewriteOutputFileMap(const fs::path& scratchDir,
- const fs::path& outputFileMapPath,
- const std::vector& inputs,
- PathRemapping& remapping) {
- auto newMapPath = scratchDir / outputFileMapPath.relative_path();
-
- // TODO: do not assume absolute path for the second parameter
- auto outputMapOrError = swift::OutputFileMap::loadFromPath(outputFileMapPath.c_str(), "");
- if (!outputMapOrError) {
- std::cerr << "Cannot load output map " << outputFileMapPath << "\n";
- return std::nullopt;
- }
- auto oldOutputMap = outputMapOrError.get();
- swift::OutputFileMap newOutputMap;
- std::vector keys;
- for (auto& key : inputs) {
- auto oldMap = oldOutputMap.getOutputMapForInput(key.c_str());
- if (!oldMap) {
- continue;
- }
- keys.push_back(key.c_str());
- auto& newMap = newOutputMap.getOrCreateOutputMapForInput(key.c_str());
- newMap.copyFrom(*oldMap);
- for (auto& entry : newMap) {
- fs::path oldPath = entry.getSecond();
- auto newPath = scratchDir / oldPath.relative_path();
- entry.getSecond() = newPath;
- remapping[oldPath] = newPath;
- }
- }
- std::error_code ec;
- fs::create_directories(newMapPath.parent_path(), ec);
- if (ec) {
- std::cerr << "Cannot create relocated output map dir " << newMapPath.parent_path() << ": "
- << ec.message() << "\n";
- return std::nullopt;
- }
-
- llvm::raw_fd_ostream fd(newMapPath.c_str(), ec, llvm::sys::fs::OF_None);
- newOutputMap.write(fd, keys);
- return newMapPath;
-}
-
-PathRemapping rewriteOutputsInPlace(const fs::path& scratchDir, std::vector& CLIArgs) {
- PathRemapping remapping;
-
- // TODO: handle filelists?
- const std::unordered_set pathRewriteOptions({
- "-emit-abi-descriptor-path",
- "-emit-dependencies-path",
- "-emit-module-path",
- "-emit-module-doc-path",
- "-emit-module-source-info-path",
- "-emit-objc-header-path",
- "-emit-reference-dependencies-path",
- "-index-store-path",
- "-index-unit-output-path",
- "-module-cache-path",
- "-o",
- "-pch-output-dir",
- "-serialize-diagnostics-path",
- });
-
- std::unordered_set outputFileMaps(
- {"-supplementary-output-file-map", "-output-file-map"});
-
- std::vector outputFileMapIndexes;
- std::vector maybeInput;
- std::string targetTriple;
-
- std::vector newLocations;
- for (size_t i = 0; i < CLIArgs.size(); i++) {
- if (pathRewriteOptions.count(CLIArgs[i])) {
- fs::path oldPath = CLIArgs[i + 1];
- auto newPath = scratchDir / oldPath.relative_path();
- CLIArgs[++i] = newPath.string();
- newLocations.push_back(newPath);
-
- remapping[oldPath] = newPath;
- } else if (outputFileMaps.count(CLIArgs[i])) {
- // collect output map indexes for further rewriting and skip the following argument
- // We don't patch the map in place as we need to collect all the input files first
- outputFileMapIndexes.push_back(++i);
- } else if (CLIArgs[i] == "-target") {
- targetTriple = CLIArgs[++i];
- } else if (CLIArgs[i][0] != '-') {
- // TODO: add support for input file lists?
- // We need to collect input file names to later use them to extract information from the
- // output file maps.
- maybeInput.push_back(CLIArgs[i]);
- }
- }
-
- for (auto index : outputFileMapIndexes) {
- auto oldPath = CLIArgs[index];
- auto maybeNewPath = rewriteOutputFileMap(scratchDir, oldPath, maybeInput, remapping);
- if (maybeNewPath) {
- const auto& newPath = maybeNewPath.value();
- CLIArgs[index] = newPath;
- remapping[oldPath] = newPath;
- }
- }
-
- return remapping;
-}
-
-void ensureDirectoriesForNewPathsExist(const PathRemapping& remapping) {
- for (auto& [_, newPath] : remapping) {
- std::error_code ec;
- fs::create_directories(newPath.parent_path(), ec);
- if (ec) {
- std::cerr << "Cannot create redirected directory " << newPath.parent_path() << ": "
- << ec.message() << "\n";
- }
- }
-}
-
-} // namespace codeql
diff --git a/swift/extractor/remapping/SwiftOutputRewrite.h b/swift/extractor/remapping/SwiftOutputRewrite.h
deleted file mode 100644
index 27d135aa8cf..00000000000
--- a/swift/extractor/remapping/SwiftOutputRewrite.h
+++ /dev/null
@@ -1,21 +0,0 @@
-#pragma once
-
-#include
-#include
-#include
-#include "swift/extractor/infra/file/PathHash.h"
-
-namespace codeql {
-
-using PathRemapping = std::unordered_map;
-// Rewrites all the output CLI args to point to a scratch dir instead of the actual locations.
-// This is needed to ensure that the artifacts produced by the extractor do not collide with the
-// artifacts produced by the actual Swift compiler.
-// Returns the map containing remapping oldpath -> newPath.
-PathRemapping rewriteOutputsInPlace(const std::filesystem::path& scratchDir,
- std::vector& CLIArgs);
-
-// Create directories for all the redirected new paths as the Swift compiler expects them to exist.
-void ensureDirectoriesForNewPathsExist(const PathRemapping& remapping);
-
-} // namespace codeql
diff --git a/swift/integration-tests/posix-only/frontend-invocations/F1.swift b/swift/integration-tests/posix-only/frontend-invocations/F1.swift
index e69de29bb2d..d29f0705072 100644
--- a/swift/integration-tests/posix-only/frontend-invocations/F1.swift
+++ b/swift/integration-tests/posix-only/frontend-invocations/F1.swift
@@ -0,0 +1 @@
+func foo() {}
diff --git a/swift/integration-tests/posix-only/frontend-invocations/F2.swift b/swift/integration-tests/posix-only/frontend-invocations/F2.swift
index e69de29bb2d..68497daef9d 100644
--- a/swift/integration-tests/posix-only/frontend-invocations/F2.swift
+++ b/swift/integration-tests/posix-only/frontend-invocations/F2.swift
@@ -0,0 +1 @@
+func bar() {}
diff --git a/swift/integration-tests/posix-only/frontend-invocations/build.sh b/swift/integration-tests/posix-only/frontend-invocations/build.sh
index 03f1148ca05..12a51efed78 100755
--- a/swift/integration-tests/posix-only/frontend-invocations/build.sh
+++ b/swift/integration-tests/posix-only/frontend-invocations/build.sh
@@ -15,4 +15,4 @@ $FRONTEND -frontend -c -primary-file D.swift -o D.o $SDK
$FRONTEND -frontend -c -primary-file E.swift Esup.swift -o E.o $SDK
$FRONTEND -frontend -emit-module -primary-file F1.swift F2.swift -module-name F -o F1.swiftmodule $SDK
$FRONTEND -frontend -emit-module F1.swift -primary-file F2.swift -module-name F -o F2.swiftmodule $SDK
-$FRONTEND -merge-modules F1.swiftmodule F2.swiftmodule -o F.swiftmodule $SDK
+$FRONTEND -frontend -merge-modules F1.swiftmodule F2.swiftmodule -o F.swiftmodule $SDK
From d35c5e90ee5fe6b83d72991fdfba9d1f1b1f82a4 Mon Sep 17 00:00:00 2001
From: Paolo Tranquilli
Date: Thu, 8 Dec 2022 11:07:14 +0100
Subject: [PATCH 032/381] Swift: remove fishhook
---
swift/third_party/fishhook/BUILD.bazel | 0
swift/third_party/fishhook/BUILD.fishhook.bazel | 7 -------
swift/third_party/load.bzl | 8 --------
3 files changed, 15 deletions(-)
delete mode 100644 swift/third_party/fishhook/BUILD.bazel
delete mode 100644 swift/third_party/fishhook/BUILD.fishhook.bazel
diff --git a/swift/third_party/fishhook/BUILD.bazel b/swift/third_party/fishhook/BUILD.bazel
deleted file mode 100644
index e69de29bb2d..00000000000
diff --git a/swift/third_party/fishhook/BUILD.fishhook.bazel b/swift/third_party/fishhook/BUILD.fishhook.bazel
deleted file mode 100644
index 5919f608d65..00000000000
--- a/swift/third_party/fishhook/BUILD.fishhook.bazel
+++ /dev/null
@@ -1,7 +0,0 @@
-cc_library(
- name = "fishhook",
- srcs = glob(["*.c"]),
- hdrs = glob(["*.h"]),
- strip_include_prefix = ".",
- visibility = ["//visibility:public"],
-)
diff --git a/swift/third_party/load.bzl b/swift/third_party/load.bzl
index fbd98b6aedb..2e1fd25ef23 100644
--- a/swift/third_party/load.bzl
+++ b/swift/third_party/load.bzl
@@ -38,14 +38,6 @@ def load_dependencies(repository_name):
],
)
- http_archive(
- name = "fishhook",
- url = "https://github.com/facebook/fishhook/archive/aadc161ac3b80db07a9908851839a17ba63a9eb1.zip",
- build_file = "@%s//swift/third_party/fishhook:BUILD.fishhook.bazel" % repository_name,
- strip_prefix = "fishhook-aadc161ac3b80db07a9908851839a17ba63a9eb1",
- sha256 = "9f2cdee6dcc2039d4c47d25ab5141fe0678ce6ed27ef482cab17fe9fa38a30ce",
- )
-
http_archive(
name = "picosha2",
url = "https://github.com/okdshin/PicoSHA2/archive/27fcf6979298949e8a462e16d09a0351c18fcaf2.zip",
From 26ae8f177b853565fc7accefb9f83cd3b2ae7e9d Mon Sep 17 00:00:00 2001
From: Paolo Tranquilli
Date: Thu, 8 Dec 2022 14:39:28 +0100
Subject: [PATCH 033/381] Swift: accept test changes
Downgrading the emit object action to a type check one has some
unexpected side effects, that seem however acceptable:
* experimental false static assertions do not make compilation fail in
type check mode
* the implicit module loading of `SwiftOnoneSupport` is not happening.
That module contains some "pre-specializations", it does not seem
really relevant for analysis
---
.../generated/decl/ModuleDecl/ModuleDecl.expected | 4 ++--
.../decl/ModuleDecl/ModuleDecl_getImportedModule.expected | 2 --
.../generated/stmt/PoundAssertStmt/PoundAssertStmt.expected | 2 +-
.../stmt/PoundAssertStmt/static_failing_assert.swift | 1 -
4 files changed, 3 insertions(+), 6 deletions(-)
diff --git a/swift/ql/test/extractor-tests/generated/decl/ModuleDecl/ModuleDecl.expected b/swift/ql/test/extractor-tests/generated/decl/ModuleDecl/ModuleDecl.expected
index e73a1739f4c..9f63f229ab3 100644
--- a/swift/ql/test/extractor-tests/generated/decl/ModuleDecl/ModuleDecl.expected
+++ b/swift/ql/test/extractor-tests/generated/decl/ModuleDecl/ModuleDecl.expected
@@ -1,3 +1,3 @@
-| file://:0:0:0:0 | Foo | getModule: | file://:0:0:0:0 | Foo | getInterfaceType: | module | getName: | Foo | getNumberOfBaseTypes: | 0 | isBuiltinModule: | no | isSystemModule: | no | getNumberOfImportedModules: | 4 | getNumberOfExportedModules: | 1 |
+| file://:0:0:0:0 | Foo | getModule: | file://:0:0:0:0 | Foo | getInterfaceType: | module | getName: | Foo | getNumberOfBaseTypes: | 0 | isBuiltinModule: | no | isSystemModule: | no | getNumberOfImportedModules: | 3 | getNumberOfExportedModules: | 1 |
| file://:0:0:0:0 | __ObjC | getModule: | file://:0:0:0:0 | __ObjC | getInterfaceType: | module<__ObjC> | getName: | __ObjC | getNumberOfBaseTypes: | 0 | isBuiltinModule: | no | isSystemModule: | no | getNumberOfImportedModules: | 1 | getNumberOfExportedModules: | 0 |
-| file://:0:0:0:0 | default_module_name | getModule: | file://:0:0:0:0 | default_module_name | getInterfaceType: | module | getName: | default_module_name | getNumberOfBaseTypes: | 0 | isBuiltinModule: | no | isSystemModule: | no | getNumberOfImportedModules: | 4 | getNumberOfExportedModules: | 0 |
+| file://:0:0:0:0 | default_module_name | getModule: | file://:0:0:0:0 | default_module_name | getInterfaceType: | module | getName: | default_module_name | getNumberOfBaseTypes: | 0 | isBuiltinModule: | no | isSystemModule: | no | getNumberOfImportedModules: | 3 | getNumberOfExportedModules: | 0 |
diff --git a/swift/ql/test/extractor-tests/generated/decl/ModuleDecl/ModuleDecl_getImportedModule.expected b/swift/ql/test/extractor-tests/generated/decl/ModuleDecl/ModuleDecl_getImportedModule.expected
index ca1793b95ef..aaae8dfa5cc 100644
--- a/swift/ql/test/extractor-tests/generated/decl/ModuleDecl/ModuleDecl_getImportedModule.expected
+++ b/swift/ql/test/extractor-tests/generated/decl/ModuleDecl/ModuleDecl_getImportedModule.expected
@@ -1,9 +1,7 @@
| file://:0:0:0:0 | Foo | 0 | file://:0:0:0:0 | Swift |
| file://:0:0:0:0 | Foo | 1 | file://:0:0:0:0 | _StringProcessing |
| file://:0:0:0:0 | Foo | 2 | file://:0:0:0:0 | _Concurrency |
-| file://:0:0:0:0 | Foo | 3 | file://:0:0:0:0 | SwiftOnoneSupport |
| file://:0:0:0:0 | __ObjC | 0 | file://:0:0:0:0 | Swift |
| file://:0:0:0:0 | default_module_name | 0 | file://:0:0:0:0 | Swift |
| file://:0:0:0:0 | default_module_name | 1 | file://:0:0:0:0 | _StringProcessing |
| file://:0:0:0:0 | default_module_name | 2 | file://:0:0:0:0 | _Concurrency |
-| file://:0:0:0:0 | default_module_name | 3 | file://:0:0:0:0 | SwiftOnoneSupport |
diff --git a/swift/ql/test/extractor-tests/generated/stmt/PoundAssertStmt/PoundAssertStmt.expected b/swift/ql/test/extractor-tests/generated/stmt/PoundAssertStmt/PoundAssertStmt.expected
index d8ba1130d6f..f157a17ca2e 100644
--- a/swift/ql/test/extractor-tests/generated/stmt/PoundAssertStmt/PoundAssertStmt.expected
+++ b/swift/ql/test/extractor-tests/generated/stmt/PoundAssertStmt/PoundAssertStmt.expected
@@ -1,3 +1,3 @@
| static_assert.swift:2:1:2:15 | #assert ... | getCondition: | static_assert.swift:2:9:2:14 | ... .==(_:_:) ... | getMessage: | |
| static_assert.swift:3:1:3:24 | #assert ... | getCondition: | static_assert.swift:3:9:3:14 | ... .!=(_:_:) ... | getMessage: | hello |
-| static_failing_assert.swift:4:1:4:24 | #assert ... | getCondition: | static_failing_assert.swift:4:9:4:14 | ... .==(_:_:) ... | getMessage: | oh my |
+| static_failing_assert.swift:3:1:3:24 | #assert ... | getCondition: | static_failing_assert.swift:3:9:3:14 | ... .==(_:_:) ... | getMessage: | oh my |
diff --git a/swift/ql/test/extractor-tests/generated/stmt/PoundAssertStmt/static_failing_assert.swift b/swift/ql/test/extractor-tests/generated/stmt/PoundAssertStmt/static_failing_assert.swift
index 2873c0c04b6..bf9bd80f780 100644
--- a/swift/ql/test/extractor-tests/generated/stmt/PoundAssertStmt/static_failing_assert.swift
+++ b/swift/ql/test/extractor-tests/generated/stmt/PoundAssertStmt/static_failing_assert.swift
@@ -1,4 +1,3 @@
//codeql-extractor-options: -enable-experimental-static-assert
-//codeql-extractor-expected-status: 1
#assert(1 == 0, "oh my")
From 71626926562130a37b1d4c305cba127e16a1d8dc Mon Sep 17 00:00:00 2001
From: Paolo Tranquilli
Date: Fri, 9 Dec 2022 10:00:01 +0100
Subject: [PATCH 034/381] Swift: exit directly on actions not requiring
extraction
---
swift/extractor/main.cpp | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/swift/extractor/main.cpp b/swift/extractor/main.cpp
index fff97ba9f51..e86ce4f88a9 100644
--- a/swift/extractor/main.cpp
+++ b/swift/extractor/main.cpp
@@ -30,7 +30,7 @@ static void lockOutputSwiftModuleTraps(const codeql::SwiftExtractorConfiguration
}
}
-static void modifyFrontendOptions(swift::FrontendOptions& options) {
+static void processFrontendOptions(swift::FrontendOptions& options) {
using Action = swift::FrontendOptions::ActionType;
switch (options.RequestedAction) {
case Action::EmitModuleOnly:
@@ -58,9 +58,9 @@ static void modifyFrontendOptions(swift::FrontendOptions& options) {
// version printing is used by CI to match up the correct compiler version
return;
default:
- // otherwise, do nothing (the closest action to doing nothing is printing the version)
- options.RequestedAction = Action::PrintVersion;
- break;
+ // otherwise, we have nothing to do
+ std::cerr << "Frontend action requires no action from extractor, exiting\n";
+ std::exit(0);
}
}
@@ -74,7 +74,7 @@ class Observer : public swift::FrontendObserver {
: config{config}, diagConsumer{diagConsumer} {}
void parsedArgs(swift::CompilerInvocation& invocation) override {
- modifyFrontendOptions(invocation.getFrontendOptions());
+ processFrontendOptions(invocation.getFrontendOptions());
}
void configuredCompiler(swift::CompilerInstance& instance) override {
From d95a4a7bafc2ea4fc0ac8195c9bf890285821842 Mon Sep 17 00:00:00 2001
From: erik-krogh
Date: Tue, 13 Dec 2022 19:33:45 +0100
Subject: [PATCH 035/381] add a second example of how to use module_eval
without constructing a code-string
---
.../cwe-094/UnsafeCodeConstruction.qhelp | 27 +++++++++++++++++--
.../examples/UnsafeCodeConstruction2.rb | 17 ++++++++++++
.../examples/UnsafeCodeConstruction2Safe.rb | 13 +++++++++
3 files changed, 55 insertions(+), 2 deletions(-)
create mode 100644 ruby/ql/src/queries/security/cwe-094/examples/UnsafeCodeConstruction2.rb
create mode 100644 ruby/ql/src/queries/security/cwe-094/examples/UnsafeCodeConstruction2Safe.rb
diff --git a/ruby/ql/src/queries/security/cwe-094/UnsafeCodeConstruction.qhelp b/ruby/ql/src/queries/security/cwe-094/UnsafeCodeConstruction.qhelp
index c430259b029..34227b85539 100644
--- a/ruby/ql/src/queries/security/cwe-094/UnsafeCodeConstruction.qhelp
+++ b/ruby/ql/src/queries/security/cwe-094/UnsafeCodeConstruction.qhelp
@@ -25,7 +25,7 @@ inputs, or avoid constructing code in the first place.
-The following example shows two methods implemented using `eval`: a simple
+The following example shows two methods implemented using eval: a simple
deserialization routine and a getter method.
If untrusted inputs are used with these methods,
then an attacker might be able to execute arbitrary code on the system.
@@ -35,7 +35,7 @@ then an attacker might be able to execute arbitrary code on the system.
To avoid this problem, either properly document that the function is potentially
-unsafe, or use an alternative solution such as `JSON.parse` or another library, like in the examples below,
+unsafe, or use an alternative solution such as JSON.parse or another library, like in the examples below,
that does not allow arbitrary code to be executed.
@@ -43,6 +43,29 @@ that does not allow arbitrary code to be executed.
+
+
+As another example, consider the below code which dynamically constructs
+a class that has a getter method with a custom name.
+
+
+
+
+
+The example dynamically constructs a string which is then executed using module_eval.
+This code will break if the specified name is not a valid Ruby identifier, and
+if the value is controlled by an attacker, then this could lead to code injection.
+
+
+
+A more robust implementation, that is also immune to code injection,
+can be made by using module_eval with a block and using define_method
+to define the getter method.
+
diff --git a/ruby/ql/src/queries/security/cwe-094/examples/UnsafeCodeConstruction3.rb b/ruby/ql/src/queries/security/cwe-094/examples/UnsafeCodeConstruction3.rb
new file mode 100644
index 00000000000..69ea7e03e7b
--- /dev/null
+++ b/ruby/ql/src/queries/security/cwe-094/examples/UnsafeCodeConstruction3.rb
@@ -0,0 +1,12 @@
+module Invoker
+ def attach(klass, name)
+ invoker = self
+ klass.module_eval <<-CODE
+ @@#{name} = invoker
+
+ def #{name}(*args)
+ @@#{name}.call(*args)
+ end
+ CODE
+ end
+end
diff --git a/ruby/ql/src/queries/security/cwe-094/examples/UnsafeCodeConstruction3Safe.rb b/ruby/ql/src/queries/security/cwe-094/examples/UnsafeCodeConstruction3Safe.rb
new file mode 100644
index 00000000000..d18fbf78d98
--- /dev/null
+++ b/ruby/ql/src/queries/security/cwe-094/examples/UnsafeCodeConstruction3Safe.rb
@@ -0,0 +1,9 @@
+module Invoker
+ def attach(klass, name)
+ var = :"@@#{name}"
+ klass.class_variable_set(var, self)
+ klass.define_method(name) do |*args|
+ self.class.class_variable_get(var).call(*args)
+ end
+ end
+end
From a6571a05aba788fbc65550195e3c1427631a279d Mon Sep 17 00:00:00 2001
From: Harry Maclean
Date: Wed, 28 Dec 2022 11:34:55 +1300
Subject: [PATCH 077/381] Ruby: Include send example in qhelp
---
.../queries/security/cwe-094/UnsafeCodeConstruction.qhelp | 8 +++++++-
.../security/cwe-094/examples/UnsafeCodeConstruction3.rb | 7 +++----
.../cwe-094/examples/UnsafeCodeConstruction3Safe.rb | 7 ++++---
3 files changed, 14 insertions(+), 8 deletions(-)
diff --git a/ruby/ql/src/queries/security/cwe-094/UnsafeCodeConstruction.qhelp b/ruby/ql/src/queries/security/cwe-094/UnsafeCodeConstruction.qhelp
index 92821f9d759..97c7adf4c87 100644
--- a/ruby/ql/src/queries/security/cwe-094/UnsafeCodeConstruction.qhelp
+++ b/ruby/ql/src/queries/security/cwe-094/UnsafeCodeConstruction.qhelp
@@ -69,7 +69,7 @@ to define the getter method.
This example dynamically registers a method on another class which
-forwards its arguments to the registering module. This approach uses
+forwards its arguments to a target class. This approach uses
module_eval and string interpolation to construct class variables
and methods.
@@ -81,6 +81,12 @@ A safer approach is to use class_variable_set and
class_variable_get along with define_method. String
interpolation is still used to construct the class variable name, but this is
safe because class_variable_set is not susceptible to code injection.
+To construct a dynamic method call we use send, which is ulnerable
+to code injection: if an attacker can control the first argument, they can call
+any method on the receiver. However this is less powerful than being able to run
+arbitrary Ruby code, so it is an improvement in security. We also document to
+callers that they should not pass arbitrary user data to the name
+parameter.
diff --git a/ruby/ql/src/queries/security/cwe-094/examples/UnsafeCodeConstruction3.rb b/ruby/ql/src/queries/security/cwe-094/examples/UnsafeCodeConstruction3.rb
index 69ea7e03e7b..e1a81bafe52 100644
--- a/ruby/ql/src/queries/security/cwe-094/examples/UnsafeCodeConstruction3.rb
+++ b/ruby/ql/src/queries/security/cwe-094/examples/UnsafeCodeConstruction3.rb
@@ -1,11 +1,10 @@
module Invoker
- def attach(klass, name)
- invoker = self
+ def attach(klass, name, target)
klass.module_eval <<-CODE
- @@#{name} = invoker
+ @@#{name} = target
def #{name}(*args)
- @@#{name}.call(*args)
+ @@#{name}.#{name}(*args)
end
CODE
end
diff --git a/ruby/ql/src/queries/security/cwe-094/examples/UnsafeCodeConstruction3Safe.rb b/ruby/ql/src/queries/security/cwe-094/examples/UnsafeCodeConstruction3Safe.rb
index d18fbf78d98..65608f8aa20 100644
--- a/ruby/ql/src/queries/security/cwe-094/examples/UnsafeCodeConstruction3Safe.rb
+++ b/ruby/ql/src/queries/security/cwe-094/examples/UnsafeCodeConstruction3Safe.rb
@@ -1,9 +1,10 @@
module Invoker
- def attach(klass, name)
+ # Do not pass arbitrary user input to +name+.
+ def attach(klass, name, target)
var = :"@@#{name}"
- klass.class_variable_set(var, self)
+ klass.class_variable_set(var, target)
klass.define_method(name) do |*args|
- self.class.class_variable_get(var).call(*args)
+ self.class.class_variable_get(var).send(name, *args)
end
end
end
From e259ef5d1dced3d9ba5a7094c7e83c0e5a54f55f Mon Sep 17 00:00:00 2001
From: Ed Minnix
Date: Wed, 26 Oct 2022 12:33:36 -0400
Subject: [PATCH 078/381] Java: Add class for
`android.webkit.WebSettings.setAllowContentAccess`
---
.../lib/semmle/code/java/frameworks/android/WebView.qll | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/java/ql/lib/semmle/code/java/frameworks/android/WebView.qll b/java/ql/lib/semmle/code/java/frameworks/android/WebView.qll
index dadcef4158e..2a6d869c0fd 100644
--- a/java/ql/lib/semmle/code/java/frameworks/android/WebView.qll
+++ b/java/ql/lib/semmle/code/java/frameworks/android/WebView.qll
@@ -78,6 +78,14 @@ class WebViewSetWebViewClientMethod extends Method {
}
}
+/** The method `setAllowContentAccess` of the class `android.webkit.WebSettings` */
+class AllowContentAccessMethod extends Method {
+ AllowContentAccessMethod() {
+ this.getDeclaringType() instanceof TypeWebSettings and
+ this.hasName("setAllowContentAccess")
+ }
+}
+
/** The method `shouldOverrideUrlLoading` of the class `android.webkit.WebViewClient`. */
class ShouldOverrideUrlLoading extends Method {
ShouldOverrideUrlLoading() {
From e4e13d38b71701ee99674d55ec275e9a24258d5f Mon Sep 17 00:00:00 2001
From: Ed Minnix
Date: Fri, 11 Nov 2022 22:34:39 -0500
Subject: [PATCH 079/381] Java: query for Android WebView setAllowContentAccess
---
.../AndroidWebViewSettingsContentAccess.qhelp | 35 +++++++++++++++++++
.../AndroidWebViewSettingsContentAccess.ql | 21 +++++++++++
.../CWE/CWE-200/ContentAccessEnabled.java | 3 ++
3 files changed, 59 insertions(+)
create mode 100644 java/ql/src/Security/CWE/CWE-200/AndroidWebViewSettingsContentAccess.qhelp
create mode 100644 java/ql/src/Security/CWE/CWE-200/AndroidWebViewSettingsContentAccess.ql
create mode 100644 java/ql/src/Security/CWE/CWE-200/ContentAccessEnabled.java
diff --git a/java/ql/src/Security/CWE/CWE-200/AndroidWebViewSettingsContentAccess.qhelp b/java/ql/src/Security/CWE/CWE-200/AndroidWebViewSettingsContentAccess.qhelp
new file mode 100644
index 00000000000..6f4dbb3505a
--- /dev/null
+++ b/java/ql/src/Security/CWE/CWE-200/AndroidWebViewSettingsContentAccess.qhelp
@@ -0,0 +1,35 @@
+
+
+
+
Android can provide access to content providers within a WebView using
+ the setAllowContentAccess setting.
+
+
Allowing access to content providers via content:// URLs
+ may allow JavaScript to access protected content.
+
+
+
+
+ If your app does not require access to the content:// URL
+ functionality, you should explicitly disable the setting by
+ calling setAllowContentAccess(false) on the settings of the
+ WebView.
+
+
+
+
+
In the following (bad) example, access to content:// URLs is explicitly allowed.
From 3811eae67946eba9814c4945fd77e554890dc76c Mon Sep 17 00:00:00 2001
From: erik-krogh
Date: Mon, 2 Jan 2023 11:26:58 +0100
Subject: [PATCH 096/381] simplify the qhelp for unsafe-code-construction The
`send()` example is not flagged by any current query, so it was weird talking
about it as "vulnerable".
---
.../cwe-094/UnsafeCodeConstruction.qhelp | 19 ++++++++++---------
.../examples/UnsafeCodeConstruction3Safe.rb | 1 -
2 files changed, 10 insertions(+), 10 deletions(-)
diff --git a/ruby/ql/src/queries/security/cwe-094/UnsafeCodeConstruction.qhelp b/ruby/ql/src/queries/security/cwe-094/UnsafeCodeConstruction.qhelp
index 63f566aaa57..6936aee149d 100644
--- a/ruby/ql/src/queries/security/cwe-094/UnsafeCodeConstruction.qhelp
+++ b/ruby/ql/src/queries/security/cwe-094/UnsafeCodeConstruction.qhelp
@@ -54,11 +54,11 @@ a class that has a getter method with a custom name.
The example dynamically constructs a string which is then executed using module_eval.
This code will break if the specified name is not a valid Ruby identifier, and
-if the value is controlled by an attacker, then this could lead to code injection.
+if the value is controlled by an attacker, then this could lead to code-injection.
-A more robust implementation, that is also immune to code injection,
+A more robust implementation, that is also immune to code-injection,
can be made by using module_eval with a block and using define_method
to define the getter method.
@@ -80,13 +80,14 @@ and methods.
A safer approach is to use class_variable_set and
class_variable_get along with define_method. String
interpolation is still used to construct the class variable name, but this is
-safe because class_variable_set is not susceptible to code injection.
-To construct a dynamic method call we use send, which is ulnerable
-to code injection: if an attacker can control the first argument, they can call
-any method on the receiver. However this is less powerful than being able to run
-arbitrary Ruby code, so it is an improvement in security. We also document to
-callers that they should not pass arbitrary user data to the name
-parameter.
+safe because class_variable_set is not susceptible to code-injection.
+
+
+
+send is used to dynamically call the method specified by name.
+This is a more robust alternative than the previous example, because it does not allow
+arbitrary code to be executed, but it does still allow for any method to be called
+on the target object.
diff --git a/ruby/ql/src/queries/security/cwe-094/examples/UnsafeCodeConstruction3Safe.rb b/ruby/ql/src/queries/security/cwe-094/examples/UnsafeCodeConstruction3Safe.rb
index 65608f8aa20..ac32224ce72 100644
--- a/ruby/ql/src/queries/security/cwe-094/examples/UnsafeCodeConstruction3Safe.rb
+++ b/ruby/ql/src/queries/security/cwe-094/examples/UnsafeCodeConstruction3Safe.rb
@@ -1,5 +1,4 @@
module Invoker
- # Do not pass arbitrary user input to +name+.
def attach(klass, name, target)
var = :"@@#{name}"
klass.class_variable_set(var, target)
From fc646a6d48f996d31c6e4130bcddf3153df5c1f7 Mon Sep 17 00:00:00 2001
From: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
Date: Tue, 3 Jan 2023 16:25:04 +0000
Subject: [PATCH 097/381] Swift: Update .expected following a toString change
in main.
---
.../CWE-134/UncontrolledFormatString.expected | 38 +++++++++----------
1 file changed, 19 insertions(+), 19 deletions(-)
diff --git a/swift/ql/test/query-tests/Security/CWE-134/UncontrolledFormatString.expected b/swift/ql/test/query-tests/Security/CWE-134/UncontrolledFormatString.expected
index fcca34232d4..4895b075e6f 100644
--- a/swift/ql/test/query-tests/Security/CWE-134/UncontrolledFormatString.expected
+++ b/swift/ql/test/query-tests/Security/CWE-134/UncontrolledFormatString.expected
@@ -1,15 +1,15 @@
edges
-| UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:68:28:68:28 | tainted |
-| UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:71:28:71:28 | tainted |
-| UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:72:28:72:28 | tainted |
-| UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:74:28:74:28 | tainted |
-| UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:75:28:75:28 | tainted |
-| UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:76:28:76:28 | tainted |
-| UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:77:46:77:46 | tainted |
-| UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:86:11:86:11 | tainted |
-| UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:89:61:89:61 | tainted |
+| UncontrolledFormatString.swift:62:24:62:77 | call to String.init(contentsOf:) : | UncontrolledFormatString.swift:68:28:68:28 | tainted |
+| UncontrolledFormatString.swift:62:24:62:77 | call to String.init(contentsOf:) : | UncontrolledFormatString.swift:71:28:71:28 | tainted |
+| UncontrolledFormatString.swift:62:24:62:77 | call to String.init(contentsOf:) : | UncontrolledFormatString.swift:72:28:72:28 | tainted |
+| UncontrolledFormatString.swift:62:24:62:77 | call to String.init(contentsOf:) : | UncontrolledFormatString.swift:74:28:74:28 | tainted |
+| UncontrolledFormatString.swift:62:24:62:77 | call to String.init(contentsOf:) : | UncontrolledFormatString.swift:75:28:75:28 | tainted |
+| UncontrolledFormatString.swift:62:24:62:77 | call to String.init(contentsOf:) : | UncontrolledFormatString.swift:76:28:76:28 | tainted |
+| UncontrolledFormatString.swift:62:24:62:77 | call to String.init(contentsOf:) : | UncontrolledFormatString.swift:77:46:77:46 | tainted |
+| UncontrolledFormatString.swift:62:24:62:77 | call to String.init(contentsOf:) : | UncontrolledFormatString.swift:86:11:86:11 | tainted |
+| UncontrolledFormatString.swift:62:24:62:77 | call to String.init(contentsOf:) : | UncontrolledFormatString.swift:89:61:89:61 | tainted |
nodes
-| UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | semmle.label | call to init(contentsOf:) : |
+| UncontrolledFormatString.swift:62:24:62:77 | call to String.init(contentsOf:) : | semmle.label | call to String.init(contentsOf:) : |
| UncontrolledFormatString.swift:68:28:68:28 | tainted | semmle.label | tainted |
| UncontrolledFormatString.swift:71:28:71:28 | tainted | semmle.label | tainted |
| UncontrolledFormatString.swift:72:28:72:28 | tainted | semmle.label | tainted |
@@ -21,12 +21,12 @@ nodes
| UncontrolledFormatString.swift:89:61:89:61 | tainted | semmle.label | tainted |
subpaths
#select
-| UncontrolledFormatString.swift:68:28:68:28 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:68:28:68:28 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) | this user-provided value |
-| UncontrolledFormatString.swift:71:28:71:28 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:71:28:71:28 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) | this user-provided value |
-| UncontrolledFormatString.swift:72:28:72:28 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:72:28:72:28 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) | this user-provided value |
-| UncontrolledFormatString.swift:74:28:74:28 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:74:28:74:28 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) | this user-provided value |
-| UncontrolledFormatString.swift:75:28:75:28 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:75:28:75:28 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) | this user-provided value |
-| UncontrolledFormatString.swift:76:28:76:28 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:76:28:76:28 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) | this user-provided value |
-| UncontrolledFormatString.swift:77:46:77:46 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:77:46:77:46 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) | this user-provided value |
-| UncontrolledFormatString.swift:86:11:86:11 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:86:11:86:11 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) | this user-provided value |
-| UncontrolledFormatString.swift:89:61:89:61 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) : | UncontrolledFormatString.swift:89:61:89:61 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:62:24:62:77 | call to init(contentsOf:) | this user-provided value |
+| UncontrolledFormatString.swift:68:28:68:28 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to String.init(contentsOf:) : | UncontrolledFormatString.swift:68:28:68:28 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:62:24:62:77 | call to String.init(contentsOf:) | this user-provided value |
+| UncontrolledFormatString.swift:71:28:71:28 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to String.init(contentsOf:) : | UncontrolledFormatString.swift:71:28:71:28 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:62:24:62:77 | call to String.init(contentsOf:) | this user-provided value |
+| UncontrolledFormatString.swift:72:28:72:28 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to String.init(contentsOf:) : | UncontrolledFormatString.swift:72:28:72:28 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:62:24:62:77 | call to String.init(contentsOf:) | this user-provided value |
+| UncontrolledFormatString.swift:74:28:74:28 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to String.init(contentsOf:) : | UncontrolledFormatString.swift:74:28:74:28 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:62:24:62:77 | call to String.init(contentsOf:) | this user-provided value |
+| UncontrolledFormatString.swift:75:28:75:28 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to String.init(contentsOf:) : | UncontrolledFormatString.swift:75:28:75:28 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:62:24:62:77 | call to String.init(contentsOf:) | this user-provided value |
+| UncontrolledFormatString.swift:76:28:76:28 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to String.init(contentsOf:) : | UncontrolledFormatString.swift:76:28:76:28 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:62:24:62:77 | call to String.init(contentsOf:) | this user-provided value |
+| UncontrolledFormatString.swift:77:46:77:46 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to String.init(contentsOf:) : | UncontrolledFormatString.swift:77:46:77:46 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:62:24:62:77 | call to String.init(contentsOf:) | this user-provided value |
+| UncontrolledFormatString.swift:86:11:86:11 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to String.init(contentsOf:) : | UncontrolledFormatString.swift:86:11:86:11 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:62:24:62:77 | call to String.init(contentsOf:) | this user-provided value |
+| UncontrolledFormatString.swift:89:61:89:61 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to String.init(contentsOf:) : | UncontrolledFormatString.swift:89:61:89:61 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:62:24:62:77 | call to String.init(contentsOf:) | this user-provided value |
From 21a018e5c53c25c55dad90f1da249c47a2de3ab5 Mon Sep 17 00:00:00 2001
From: Jami Cogswell
Date: Tue, 3 Jan 2023 13:12:24 -0500
Subject: [PATCH 098/381] Java: add summary model and test for File.getName
---
java/ql/lib/ext/java.io.model.yml | 2 +-
java/ql/test/ext/TestModels/Test.java | 4 ++++
2 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/java/ql/lib/ext/java.io.model.yml b/java/ql/lib/ext/java.io.model.yml
index f4e63b01c7f..a0e7777c3b5 100644
--- a/java/ql/lib/ext/java.io.model.yml
+++ b/java/ql/lib/ext/java.io.model.yml
@@ -63,6 +63,7 @@ extensions:
- ["java.io", "File", True, "getAbsolutePath", "", "", "Argument[-1]", "ReturnValue", "taint", "manual"]
- ["java.io", "File", True, "getCanonicalFile", "", "", "Argument[-1]", "ReturnValue", "taint", "manual"]
- ["java.io", "File", True, "getCanonicalPath", "", "", "Argument[-1]", "ReturnValue", "taint", "manual"]
+ - ["java.io", "File", True, "getName", "()", "", "Argument[-1]", "ReturnValue", "taint", "manual"]
- ["java.io", "File", True, "toPath", "", "", "Argument[-1]", "ReturnValue", "taint", "manual"]
- ["java.io", "File", True, "toString", "", "", "Argument[-1]", "ReturnValue", "taint", "manual"]
- ["java.io", "File", True, "toURI", "", "", "Argument[-1]", "ReturnValue", "taint", "manual"]
@@ -91,4 +92,3 @@ extensions:
extensible: neutralModel
data:
- ["java.io", "File", "exists", "()", "manual"]
- - ["java.io", "File", "getName", "()", "manual"] # ! unsure if should be neutral model
diff --git a/java/ql/test/ext/TestModels/Test.java b/java/ql/test/ext/TestModels/Test.java
index bfdbe6a6a27..0b29879d907 100644
--- a/java/ql/test/ext/TestModels/Test.java
+++ b/java/ql/test/ext/TestModels/Test.java
@@ -1,4 +1,5 @@
import java.io.IOException;
+import java.io.File;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.DriverManager;
@@ -60,6 +61,9 @@ public class Test {
Exception e1 = new IOException((String)source());
sink((String)e1.getMessage()); // $hasValueFlow
+ File f = (File)source();
+ sink(f.getName()); // $hasTaintFlow
+
// java.lang
Exception e2 = new Exception((String)source());
sink((String)e2.getMessage()); // $hasValueFlow
From 29221ae4262664783fec5b08a5e2d11c75f3e6e2 Mon Sep 17 00:00:00 2001
From: Jami Cogswell
Date: Tue, 3 Jan 2023 15:11:21 -0500
Subject: [PATCH 099/381] Java: add summary model for System.getProperty,
adjust comments
---
java/ql/lib/ext/java.lang.model.yml | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/java/ql/lib/ext/java.lang.model.yml b/java/ql/lib/ext/java.lang.model.yml
index 73ceaf88a8a..02699c278d1 100644
--- a/java/ql/lib/ext/java.lang.model.yml
+++ b/java/ql/lib/ext/java.lang.model.yml
@@ -103,6 +103,7 @@ extensions:
- ["java.lang", "StringBuffer", True, "StringBuffer", "(String)", "", "Argument[0]", "Argument[-1]", "taint", "manual"]
- ["java.lang", "StringBuilder", True, "StringBuilder", "", "", "Argument[0]", "Argument[-1]", "taint", "manual"]
- ["java.lang", "System", False, "arraycopy", "", "", "Argument[0]", "Argument[2]", "taint", "manual"]
+ - ["java.lang", "System", False, "getProperty", "(String)", "", "Argument[-1].MapValue", "ReturnValue", "value", "manual"]
- ["java.lang", "Throwable", False, "Throwable", "(Throwable)", "", "Argument[0]", "Argument[-1].SyntheticField[java.lang.Throwable.cause]", "value", "manual"]
- ["java.lang", "Throwable", True, "getCause", "()", "", "Argument[-1].SyntheticField[java.lang.Throwable.cause]", "ReturnValue", "value", "manual"]
- ["java.lang", "Throwable", True, "getMessage", "()", "", "Argument[-1].SyntheticField[java.lang.Throwable.message]", "ReturnValue", "value", "manual"]
@@ -113,7 +114,7 @@ extensions:
data:
- ["java.lang", "AbstractStringBuilder", "length", "()", "manual"]
- ["java.lang", "Boolean", "equals", "(Object)", "manual"]
- - ["java.lang", "Class", "getClassLoader", "()", "manual"] # ! unsure if should be neutral model
+ - ["java.lang", "Class", "getClassLoader", "()", "manual"]
- ["java.lang", "Class", "getName", "()", "manual"]
- ["java.lang", "Class", "getSimpleName", "()", "manual"]
- ["java.lang", "Class", "isAssignableFrom", "(Class)", "manual"]
@@ -127,16 +128,15 @@ extensions:
- ["java.lang", "Object", "hashCode", "()", "manual"]
- ["java.lang", "Object", "toString", "()", "manual"]
- ["java.lang", "String", "contains", "(CharSequence)", "manual"]
- - ["java.lang", "String", "endsWith", "(String)", "manual"] # ! unsure if should be neutral model since already modeled as a summary above
+ - ["java.lang", "String", "endsWith", "(String)", "manual"] # ! see question on line 65 above
- ["java.lang", "String", "equals", "(Object)", "manual"]
- ["java.lang", "String", "equalsIgnoreCase", "(String)", "manual"]
- ["java.lang", "String", "hashCode", "()", "manual"]
- - ["java.lang", "String", "indexOf", "(String)", "manual"] # ! unsure if should be neutral model, is flow through the param interesting in this case?
+ - ["java.lang", "String", "indexOf", "(String)", "manual"]
- ["java.lang", "String", "isEmpty", "()", "manual"]
- ["java.lang", "String", "length", "()", "manual"]
- ["java.lang", "String", "startsWith", "(String)", "manual"]
- ["java.lang", "System", "currentTimeMillis", "()", "manual"]
- - ["java.lang", "System", "getProperty", "(String)", "manual"] # ! unsure if should be neutral model
- ["java.lang", "System", "nanoTime", "()", "manual"]
- ["java.lang", "Thread", "currentThread", "()", "manual"]
- - ["java.lang", "Thread", "sleep", "(long)", "manual"] # ! unsure if should be neutral model, is flow through the param interesting in this case?
+ - ["java.lang", "Thread", "sleep", "(long)", "manual"]
From 28ad9d00fb8bcb43dd860178a932a34756955d7c Mon Sep 17 00:00:00 2001
From: Ed Minnix
Date: Tue, 3 Jan 2023 15:17:07 -0500
Subject: [PATCH 100/381] Merge both setAllowContentAccess queries into one
query
Previously, the query to detect whether or not access to `content://`
links was done using two queries.
Now they can be merged into one query
---
.../AndroidWebViewSettingsContentAccess.ql | 21 -------------------
...WebViewSettingsPermitsContentAccess.qhelp} | 0
...roidWebViewSettingsPermitsContentAccess.ql | 18 +++++++++++++---
.../tests/WebViewContentAccess.expected | 5 +++++
.../semmle/tests/WebViewContentAccess.qlref | 2 +-
.../WebViewContentAccessDataFlow.expected | 5 -----
.../tests/WebViewContentAccessDataFlow.qlref | 1 -
7 files changed, 21 insertions(+), 31 deletions(-)
delete mode 100644 java/ql/src/Security/CWE/CWE-200/AndroidWebViewSettingsContentAccess.ql
rename java/ql/src/Security/CWE/CWE-200/{AndroidWebViewSettingsContentAccess.qhelp => AndroidWebViewSettingsPermitsContentAccess.qhelp} (100%)
delete mode 100644 java/ql/test/query-tests/security/CWE-200/semmle/tests/WebViewContentAccessDataFlow.expected
delete mode 100644 java/ql/test/query-tests/security/CWE-200/semmle/tests/WebViewContentAccessDataFlow.qlref
diff --git a/java/ql/src/Security/CWE/CWE-200/AndroidWebViewSettingsContentAccess.ql b/java/ql/src/Security/CWE/CWE-200/AndroidWebViewSettingsContentAccess.ql
deleted file mode 100644
index 1657f417754..00000000000
--- a/java/ql/src/Security/CWE/CWE-200/AndroidWebViewSettingsContentAccess.ql
+++ /dev/null
@@ -1,21 +0,0 @@
-/**
- * @name Android WebSettings content access
- * @description Access to content providers in a WebView can enable JavaScript to access protected information.
- * @kind problem
- * @id java/android/websettings-content-access
- * @problem.severity warning
- * @security-severity 6.5
- * @precision medium
- * @tags security
- * external/cwe/cwe-200
- */
-
-import java
-import semmle.code.java.frameworks.android.WebView
-
-from MethodAccess ma
-where
- ma.getMethod() instanceof AllowContentAccessMethod and
- ma.getArgument(0).(CompileTimeConstantExpr).getBooleanValue() = true
-select ma,
- "Sensitive information may be exposed via a malicious link due to access of content:// links being permitted."
diff --git a/java/ql/src/Security/CWE/CWE-200/AndroidWebViewSettingsContentAccess.qhelp b/java/ql/src/Security/CWE/CWE-200/AndroidWebViewSettingsPermitsContentAccess.qhelp
similarity index 100%
rename from java/ql/src/Security/CWE/CWE-200/AndroidWebViewSettingsContentAccess.qhelp
rename to java/ql/src/Security/CWE/CWE-200/AndroidWebViewSettingsPermitsContentAccess.qhelp
diff --git a/java/ql/src/Security/CWE/CWE-200/AndroidWebViewSettingsPermitsContentAccess.ql b/java/ql/src/Security/CWE/CWE-200/AndroidWebViewSettingsPermitsContentAccess.ql
index 509b062c595..7ccf23cc3ae 100644
--- a/java/ql/src/Security/CWE/CWE-200/AndroidWebViewSettingsPermitsContentAccess.ql
+++ b/java/ql/src/Security/CWE/CWE-200/AndroidWebViewSettingsPermitsContentAccess.ql
@@ -94,7 +94,19 @@ class WebViewDisallowContentAccessConfiguration extends TaintTracking::Configura
}
}
-from WebViewSource source
-where not any(WebViewDisallowContentAccessConfiguration cfg).hasFlow(source, _)
-select source,
+from Expr e
+where
+ // explicit: setAllowContentAccess(true)
+ exists(MethodAccess ma |
+ ma = e and
+ ma.getMethod() instanceof AllowContentAccessMethod and
+ ma.getArgument(0).(CompileTimeConstantExpr).getBooleanValue() = true
+ )
+ or
+ // implicit: no setAllowContentAccess(false)
+ exists(WebViewSource source |
+ source.asExpr() = e and
+ not any(WebViewDisallowContentAccessConfiguration cfg).hasFlow(source, _)
+ )
+select e,
"Sensitive information may be exposed via a malicious link due to access of content:// links being permitted."
diff --git a/java/ql/test/query-tests/security/CWE-200/semmle/tests/WebViewContentAccess.expected b/java/ql/test/query-tests/security/CWE-200/semmle/tests/WebViewContentAccess.expected
index dc904ca6cd7..317f847279f 100644
--- a/java/ql/test/query-tests/security/CWE-200/semmle/tests/WebViewContentAccess.expected
+++ b/java/ql/test/query-tests/security/CWE-200/semmle/tests/WebViewContentAccess.expected
@@ -1,5 +1,10 @@
| WebViewContentAccess.java:15:9:15:57 | setAllowContentAccess(...) | Sensitive information may be exposed via a malicious link due to access of content:// links being permitted. |
| WebViewContentAccess.java:38:9:38:55 | setAllowContentAccess(...) | Sensitive information may be exposed via a malicious link due to access of content:// links being permitted. |
+| WebViewContentAccess.java:41:25:41:49 | (...)... | Sensitive information may be exposed via a malicious link due to access of content:// links being permitted. |
| WebViewContentAccess.java:43:9:43:44 | setAllowContentAccess(...) | Sensitive information may be exposed via a malicious link due to access of content:// links being permitted. |
+| WebViewContentAccess.java:46:25:46:41 | new WebView(...) | Sensitive information may be exposed via a malicious link due to access of content:// links being permitted. |
| WebViewContentAccess.java:48:9:48:44 | setAllowContentAccess(...) | Sensitive information may be exposed via a malicious link due to access of content:// links being permitted. |
+| WebViewContentAccess.java:51:25:51:44 | getAWebView(...) | Sensitive information may be exposed via a malicious link due to access of content:// links being permitted. |
| WebViewContentAccess.java:53:9:53:44 | setAllowContentAccess(...) | Sensitive information may be exposed via a malicious link due to access of content:// links being permitted. |
+| WebViewContentAccess.java:55:29:55:48 | getAWebView(...) | Sensitive information may be exposed via a malicious link due to access of content:// links being permitted. |
+| WebViewContentAccess.java:57:25:57:44 | getAWebView(...) | Sensitive information may be exposed via a malicious link due to access of content:// links being permitted. |
diff --git a/java/ql/test/query-tests/security/CWE-200/semmle/tests/WebViewContentAccess.qlref b/java/ql/test/query-tests/security/CWE-200/semmle/tests/WebViewContentAccess.qlref
index f907dcc5755..8ea25a487de 100644
--- a/java/ql/test/query-tests/security/CWE-200/semmle/tests/WebViewContentAccess.qlref
+++ b/java/ql/test/query-tests/security/CWE-200/semmle/tests/WebViewContentAccess.qlref
@@ -1 +1 @@
-Security/CWE/CWE-200/AndroidWebViewSettingsContentAccess.ql
+Security/CWE/CWE-200/AndroidWebViewSettingsPermitsContentAccess.ql
\ No newline at end of file
diff --git a/java/ql/test/query-tests/security/CWE-200/semmle/tests/WebViewContentAccessDataFlow.expected b/java/ql/test/query-tests/security/CWE-200/semmle/tests/WebViewContentAccessDataFlow.expected
deleted file mode 100644
index 6b0c6c52625..00000000000
--- a/java/ql/test/query-tests/security/CWE-200/semmle/tests/WebViewContentAccessDataFlow.expected
+++ /dev/null
@@ -1,5 +0,0 @@
-| WebViewContentAccess.java:41:25:41:49 | (...)... | Sensitive information may be exposed via a malicious link due to access of content:// links being permitted. |
-| WebViewContentAccess.java:46:25:46:41 | new WebView(...) | Sensitive information may be exposed via a malicious link due to access of content:// links being permitted. |
-| WebViewContentAccess.java:51:25:51:44 | getAWebView(...) | Sensitive information may be exposed via a malicious link due to access of content:// links being permitted. |
-| WebViewContentAccess.java:55:29:55:48 | getAWebView(...) | Sensitive information may be exposed via a malicious link due to access of content:// links being permitted. |
-| WebViewContentAccess.java:57:25:57:44 | getAWebView(...) | Sensitive information may be exposed via a malicious link due to access of content:// links being permitted. |
diff --git a/java/ql/test/query-tests/security/CWE-200/semmle/tests/WebViewContentAccessDataFlow.qlref b/java/ql/test/query-tests/security/CWE-200/semmle/tests/WebViewContentAccessDataFlow.qlref
deleted file mode 100644
index 8ea25a487de..00000000000
--- a/java/ql/test/query-tests/security/CWE-200/semmle/tests/WebViewContentAccessDataFlow.qlref
+++ /dev/null
@@ -1 +0,0 @@
-Security/CWE/CWE-200/AndroidWebViewSettingsPermitsContentAccess.ql
\ No newline at end of file
From 81df89f93e29a28a686c4a598ac74cd4d6e0ea95 Mon Sep 17 00:00:00 2001
From: Ed Minnix
Date: Tue, 3 Jan 2023 15:19:26 -0500
Subject: [PATCH 101/381] Use proper @id in changenote
---
.../change-notes/2022-12-21-android-allowcontentaccess-query.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/java/ql/src/change-notes/2022-12-21-android-allowcontentaccess-query.md b/java/ql/src/change-notes/2022-12-21-android-allowcontentaccess-query.md
index 008da665b57..854da87eb54 100644
--- a/java/ql/src/change-notes/2022-12-21-android-allowcontentaccess-query.md
+++ b/java/ql/src/change-notes/2022-12-21-android-allowcontentaccess-query.md
@@ -1,4 +1,4 @@
---
category: newQuery
---
-* Added a new query `java/android/websettings-content-access` to detect Android WebViews which do not disable access to `content://` urls.
+* Added a new query `java/android/websettings-permit-contentacces` to detect Android WebViews which do not disable access to `content://` urls.
From f9b8200009e50d96994097bdc45cd833acd0bb1f Mon Sep 17 00:00:00 2001
From: Ed Minnix
Date: Thu, 8 Dec 2022 12:44:21 -0500
Subject: [PATCH 102/381] Add stub for android.webkit.JavascriptInterface
annoation
---
.../android/webkit/JavascriptInterface.java | 7 +++++++
1 file changed, 7 insertions(+)
create mode 100644 java/ql/test/stubs/google-android-9.0.0/android/webkit/JavascriptInterface.java
diff --git a/java/ql/test/stubs/google-android-9.0.0/android/webkit/JavascriptInterface.java b/java/ql/test/stubs/google-android-9.0.0/android/webkit/JavascriptInterface.java
new file mode 100644
index 00000000000..6ef03118cdb
--- /dev/null
+++ b/java/ql/test/stubs/google-android-9.0.0/android/webkit/JavascriptInterface.java
@@ -0,0 +1,7 @@
+package android.webkit;
+
+import java.lang.annotation.Annotation;
+
+public abstract @interface JavascriptInterface {
+
+}
From ab7ca1d6429e9349feb48d1672fa6f67012a8153 Mon Sep 17 00:00:00 2001
From: Ed Minnix
Date: Thu, 8 Dec 2022 13:53:40 -0500
Subject: [PATCH 103/381] Java: Add parameters of @JavascriptInterface methods
as a remote flow sources
---
.../lib/semmle/code/java/dataflow/FlowSources.qll | 13 +++++++++++++
.../semmle/code/java/frameworks/android/Android.qll | 7 +++++++
2 files changed, 20 insertions(+)
diff --git a/java/ql/lib/semmle/code/java/dataflow/FlowSources.qll b/java/ql/lib/semmle/code/java/dataflow/FlowSources.qll
index 4970b8ff642..055cfb9f94e 100644
--- a/java/ql/lib/semmle/code/java/dataflow/FlowSources.qll
+++ b/java/ql/lib/semmle/code/java/dataflow/FlowSources.qll
@@ -298,3 +298,16 @@ class OnActivityResultIntentSource extends OnActivityResultIncomingIntent, Remot
override string getSourceType() { result = "Android onActivityResult incoming Intent" }
}
+
+/**
+ * A parameter of a method annotated with the `android.webkit.JavascriptInterface` method
+ */
+class AndroidJavascriptInterfaceMethodParameter extends RemoteFlowSource {
+ AndroidJavascriptInterfaceMethodParameter() {
+ exists(JavascriptInterfaceMethod m | this.asParameter() = m.getAParameter())
+ }
+
+ override string getSourceType() {
+ result = "Parameter of method with JavascriptInterface annotation"
+ }
+}
diff --git a/java/ql/lib/semmle/code/java/frameworks/android/Android.qll b/java/ql/lib/semmle/code/java/frameworks/android/Android.qll
index 1a992eb5565..9e98758a523 100644
--- a/java/ql/lib/semmle/code/java/frameworks/android/Android.qll
+++ b/java/ql/lib/semmle/code/java/frameworks/android/Android.qll
@@ -127,3 +127,10 @@ class CreateFromParcelMethod extends Method {
this.getEnclosingCallable().getDeclaringType().getAnAncestor() instanceof TypeParcelable
}
}
+
+/**
+ * A method annotated with the `android.webkit.JavascriptInterface` annotation.
+ */
+class JavascriptInterfaceMethod extends Method {
+ JavascriptInterfaceMethod() { this.hasAnnotation("android.webkit", "JavascriptInterface") }
+}
From 28f555c2b2ab09ef7362e9e095ff5e3fbad043bd Mon Sep 17 00:00:00 2001
From: Ed Minnix
Date: Fri, 9 Dec 2022 11:56:08 -0500
Subject: [PATCH 104/381] Add simple test case for @JavascriptInterface
parameter flow
---
.../dataflow/taintsources/AndroidExposedObject.java | 11 +++++++++++
1 file changed, 11 insertions(+)
create mode 100644 java/ql/test/library-tests/dataflow/taintsources/AndroidExposedObject.java
diff --git a/java/ql/test/library-tests/dataflow/taintsources/AndroidExposedObject.java b/java/ql/test/library-tests/dataflow/taintsources/AndroidExposedObject.java
new file mode 100644
index 00000000000..2460781e196
--- /dev/null
+++ b/java/ql/test/library-tests/dataflow/taintsources/AndroidExposedObject.java
@@ -0,0 +1,11 @@
+import android.webkit.JavascriptInterface;
+
+public class AndroidExposedObject {
+ public void sink(Object o) {
+ }
+
+ @JavascriptInterface
+ public void test(String arg) {
+ sink(arg); // $hasRemoteValueFlow
+ }
+}
From 0be8648a9df7fbf9415283965f241efbc6cc81ac Mon Sep 17 00:00:00 2001
From: Ed Minnix
Date: Tue, 3 Jan 2023 15:55:53 -0500
Subject: [PATCH 105/381] Add changenote
---
...3-android-javascriptinterface-parameters-remote-sources.md | 4 ++++
1 file changed, 4 insertions(+)
create mode 100644 java/ql/lib/change-notes/2022-01-13-android-javascriptinterface-parameters-remote-sources.md
diff --git a/java/ql/lib/change-notes/2022-01-13-android-javascriptinterface-parameters-remote-sources.md b/java/ql/lib/change-notes/2022-01-13-android-javascriptinterface-parameters-remote-sources.md
new file mode 100644
index 00000000000..7915d4ea530
--- /dev/null
+++ b/java/ql/lib/change-notes/2022-01-13-android-javascriptinterface-parameters-remote-sources.md
@@ -0,0 +1,4 @@
+---
+category: minorAnalysis
+---
+* Added an external flow source for the parameters of methods annotated with `android.webkit.JavascriptInterface`.
From feaae16f7cb7056927a1cecdfce5a68e05eefbe8 Mon Sep 17 00:00:00 2001
From: Jami Cogswell
Date: Tue, 3 Jan 2023 16:08:14 -0500
Subject: [PATCH 106/381] Java: adjust comments
---
java/ql/lib/ext/java.sql.model.yml | 2 +-
java/ql/lib/ext/java.text.model.yml | 4 ++--
java/ql/lib/ext/java.time.model.yml | 2 +-
java/ql/lib/ext/java.util.function.model.yml | 4 ++--
java/ql/lib/ext/java.util.model.yml | 2 +-
java/ql/lib/ext/java.util.stream.model.yml | 4 ++--
6 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/java/ql/lib/ext/java.sql.model.yml b/java/ql/lib/ext/java.sql.model.yml
index 181d563bda9..9dd0e7d948c 100644
--- a/java/ql/lib/ext/java.sql.model.yml
+++ b/java/ql/lib/ext/java.sql.model.yml
@@ -28,4 +28,4 @@ extensions:
pack: codeql/java-all
extensible: neutralModel
data:
- - ["java.sql", "ResultSet", "next", "()", "manual"] # ! unsure if should be neutral model
+ - ["java.sql", "ResultSet", "next", "()", "manual"]
diff --git a/java/ql/lib/ext/java.text.model.yml b/java/ql/lib/ext/java.text.model.yml
index 2e10bd3ac39..edf2a4c7d60 100644
--- a/java/ql/lib/ext/java.text.model.yml
+++ b/java/ql/lib/ext/java.text.model.yml
@@ -3,5 +3,5 @@ extensions:
pack: codeql/java-all
extensible: neutralModel
data:
- - ["java.text", "DateFormat", "format", "(Date)", "manual"] # ! unsure if should be neutral model, is flow through the param interesting in this case?
- - ["java.text", "SimpleDateFormat", "SimpleDateFormat", "(String)", "manual"] # ! unsure if should be neutral model, is flow through the param interesting in this case?
+ - ["java.text", "DateFormat", "format", "(Date)", "manual"]
+ - ["java.text", "SimpleDateFormat", "SimpleDateFormat", "(String)", "manual"]
diff --git a/java/ql/lib/ext/java.time.model.yml b/java/ql/lib/ext/java.time.model.yml
index f363058c1db..1a9b745f403 100644
--- a/java/ql/lib/ext/java.time.model.yml
+++ b/java/ql/lib/ext/java.time.model.yml
@@ -4,5 +4,5 @@ extensions:
extensible: neutralModel
data:
- ["java.time", "Instant", "now", "()", "manual"]
- - ["java.time", "LocalDate", "of", "(int,int,int)", "manual"] # ! unsure if should be neutral model, is flow through the param interesting in this case?
+ - ["java.time", "LocalDate", "of", "(int,int,int)", "manual"]
- ["java.time", "ZonedDateTime", "now", "()", "manual"]
diff --git a/java/ql/lib/ext/java.util.function.model.yml b/java/ql/lib/ext/java.util.function.model.yml
index 8cf3a674da6..44c01b611d2 100644
--- a/java/ql/lib/ext/java.util.function.model.yml
+++ b/java/ql/lib/ext/java.util.function.model.yml
@@ -9,11 +9,11 @@ extensions:
pack: codeql/java-all
extensible: summaryModel
data:
- - ["java.util.function", "Function", True, "apply", "(Object)", "", "Argument[0]", "ReturnValue", "taint", "manual"] # ! unsure if should be added as a MaD model and if model is correct
+ - ["java.util.function", "Function", True, "apply", "(Object)", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["java.util.function", "Supplier", False, "get", "()", "", "Argument[-1]", "ReturnValue", "value", "manual"]
- addsTo:
pack: codeql/java-all
extensible: neutralModel
data:
- - ["java.util.function", "Consumer", "accept", "(Object)", "manual"] # ! unsure if should be neutral model
+ - ["java.util.function", "Consumer", "accept", "(Object)", "manual"]
diff --git a/java/ql/lib/ext/java.util.model.yml b/java/ql/lib/ext/java.util.model.yml
index 9d03874f179..ec45266409a 100644
--- a/java/ql/lib/ext/java.util.model.yml
+++ b/java/ql/lib/ext/java.util.model.yml
@@ -369,7 +369,7 @@ extensions:
- ["java.util", "Collections", "emptyList", "()", "manual"]
- ["java.util", "Collections", "emptyMap", "()", "manual"]
- ["java.util", "Collections", "emptySet", "()", "manual"]
- - ["java.util", "Date", "Date", "(long)", "manual"] # ! unsure if should be neutral model, is flow through the param interesting in this case?
+ - ["java.util", "Date", "Date", "(long)", "manual"]
- ["java.util", "Date", "getTime", "()", "manual"]
- ["java.util", "Iterator", "hasNext", "()", "manual"]
- ["java.util", "List", "clear", "()", "manual"]
diff --git a/java/ql/lib/ext/java.util.stream.model.yml b/java/ql/lib/ext/java.util.stream.model.yml
index 885b6e0f478..aae79ed57ac 100644
--- a/java/ql/lib/ext/java.util.stream.model.yml
+++ b/java/ql/lib/ext/java.util.stream.model.yml
@@ -92,7 +92,7 @@ extensions:
pack: codeql/java-all
extensible: neutralModel
data:
- - ["java.util.stream", "Collectors", "joining", "(CharSequence)", "manual"] # ! unsure if should be neutral model, is flow through the param interesting in this case?
+ - ["java.util.stream", "Collectors", "joining", "(CharSequence)", "manual"]
- ["java.util.stream", "Collectors", "toList", "()", "manual"]
- - ["java.util.stream", "Collectors", "toMap", "(Function,Function)", "manual"] # ! unsure if should be neutral model, is flow through the param interesting in this case?
+ - ["java.util.stream", "Collectors", "toMap", "(Function,Function)", "manual"]
- ["java.util.stream", "Collectors", "toSet", "()", "manual"]
From 5d92792e403d441da977e2a485e0d90d6623876f Mon Sep 17 00:00:00 2001
From: Jami Cogswell
Date: Tue, 3 Jan 2023 16:14:08 -0500
Subject: [PATCH 107/381] Java: update test case affected by Function.apply
model
---
java/ql/test/library-tests/dataflow/lambda/flow.expected | 5 +----
1 file changed, 1 insertion(+), 4 deletions(-)
diff --git a/java/ql/test/library-tests/dataflow/lambda/flow.expected b/java/ql/test/library-tests/dataflow/lambda/flow.expected
index 3b467de204b..3d3a73136ee 100644
--- a/java/ql/test/library-tests/dataflow/lambda/flow.expected
+++ b/java/ql/test/library-tests/dataflow/lambda/flow.expected
@@ -1,8 +1,5 @@
| Executor.java:11:15:11:22 | source(...) | Executor.java:50:39:50:45 | command |
-| Executor.java:11:15:11:22 | source(...) | StringProcessor.java:23:39:23:45 | command |
| Executor.java:12:15:12:22 | source(...) | Executor.java:50:39:50:45 | command |
-| Executor.java:12:15:12:22 | source(...) | StringProcessor.java:23:39:23:45 | command |
| Executor.java:13:15:13:22 | source(...) | Executor.java:50:39:50:45 | command |
-| Executor.java:13:15:13:22 | source(...) | StringProcessor.java:23:39:23:45 | command |
+| Executor.java:14:15:14:22 | source(...) | Executor.java:58:39:58:45 | command |
| Executor.java:15:15:15:22 | source(...) | Executor.java:58:39:58:45 | command |
-| StringProcessor.java:8:26:8:29 | args | StringProcessor.java:23:39:23:45 | command |
From abe501c1af40d32eaf615326cd478f0d884f1012 Mon Sep 17 00:00:00 2001
From: Jami Cogswell
Date: Tue, 3 Jan 2023 17:15:50 -0500
Subject: [PATCH 108/381] Java: add change note
---
.../ql/lib/change-notes/2023-01-03-add-more-top-jdk-models.md | 4 ++++
1 file changed, 4 insertions(+)
create mode 100644 java/ql/lib/change-notes/2023-01-03-add-more-top-jdk-models.md
diff --git a/java/ql/lib/change-notes/2023-01-03-add-more-top-jdk-models.md b/java/ql/lib/change-notes/2023-01-03-add-more-top-jdk-models.md
new file mode 100644
index 00000000000..a74fb161e58
--- /dev/null
+++ b/java/ql/lib/change-notes/2023-01-03-add-more-top-jdk-models.md
@@ -0,0 +1,4 @@
+---
+category: minorAnalysis
+---
+* Added more dataflow models for frequently-used JDK APIs.
From d859e1e9a39042b1272e80bd3b558b6659d5c228 Mon Sep 17 00:00:00 2001
From: Sarita Iyer <66540150+saritai@users.noreply.github.com>
Date: Wed, 4 Jan 2023 16:43:17 -0500
Subject: [PATCH 109/381] add contributing info
---
README.md | 2 ++
docs/codeql/CONTRIBUTING.MD | 9 +++++++++
docs/codeql/README.rst | 2 ++
3 files changed, 13 insertions(+)
create mode 100644 docs/codeql/CONTRIBUTING.MD
diff --git a/README.md b/README.md
index a1a91f8e0af..e0c34b1a6ba 100644
--- a/README.md
+++ b/README.md
@@ -10,6 +10,8 @@ There is [extensive documentation](https://codeql.github.com/docs/) on getting s
We welcome contributions to our standard library and standard checks. Do you have an idea for a new check, or how to improve an existing query? Then please go ahead and open a pull request! Before you do, though, please take the time to read our [contributing guidelines](CONTRIBUTING.md). You can also consult our [style guides](https://github.com/github/codeql/tree/main/docs) to learn how to format your code for consistency and clarity, how to write query metadata, and how to write query help documentation for your query.
+For information on contributing to CodeQL documentation, see "[the contributing guide](https://github.com/github/codeql/blob/main/docs/codeql/CONTRIBUTING.md)" for docs.
+
## License
The code in this repository is licensed under the [MIT License](LICENSE) by [GitHub](https://github.com).
diff --git a/docs/codeql/CONTRIBUTING.MD b/docs/codeql/CONTRIBUTING.MD
new file mode 100644
index 00000000000..fca621030df
--- /dev/null
+++ b/docs/codeql/CONTRIBUTING.MD
@@ -0,0 +1,9 @@
+# Contributing to CodeQL docs
+
+We welcome contributions to our CodeQL docs. Want to improve existing docs or add new information you think would be helpful? Then please go ahead and open a pull request!
+
+**Note**: We have recently copied the CodeQL CLI documentation on [codeql.github.com](https://codeql.github.com/docs/codeql-cli/) to the public [github/docs](https://github.com/github/docs) repository so that they appear on the [GitHub Docs](https://docs.github.com/en/code-security/code-scanning) site. This includes all articles under "[Using the CodeQL CLI](https://codeql.github.com/docs/codeql-cli/using-the-codeql-cli/)" and "[CodeQL CLI reference](https://codeql.github.com/docs/codeql-cli/codeql-cli-reference/)" categories. To contribute to these docs, which are located in the [`code-security`](https://github.com/github/docs/tree/main/content/code-security/code-scanning) directory, please refer to the [CONTRIBUTING.md](https://github.com/github/docs/blob/main/CONTRIBUTING.md) file in the `docs` repository.
+
+## Contributing to docs on `codeql.github.com`
+
+To make changes to the remaining documentation on [codeql.github.com](https://codeql.github.com/docs/codeql-cli/), you can make changes to the documentation files using the GitHub UI, a codespace, or making changes locally, and then open a pull request for review. For more information about the format and structure of the CodeQL documentation on [codeql.github.com](https://codeql.github.com/docs/codeql-cli/), please see the [README](https://github.com/github/codeql/tree/main/docs/codeql#readme).
diff --git a/docs/codeql/README.rst b/docs/codeql/README.rst
index a07d15c27e1..1e8a55a9c24 100644
--- a/docs/codeql/README.rst
+++ b/docs/codeql/README.rst
@@ -12,6 +12,8 @@ see https://docutils.sourceforge.io/rst.html.
For more information on Sphinx, see https://www.sphinx-doc.org.
+For information on contributing to CodeQL documentation, see "[the contributing guide](/CONTRIBUTING.md)."
+
Project structure
*****************
From a62a8d9960c27e41faf003089216b9dc74165912 Mon Sep 17 00:00:00 2001
From: Sarita Iyer <66540150+saritai@users.noreply.github.com>
Date: Wed, 4 Jan 2023 16:47:34 -0500
Subject: [PATCH 110/381] Update CONTRIBUTING.MD
---
docs/codeql/CONTRIBUTING.MD | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/codeql/CONTRIBUTING.MD b/docs/codeql/CONTRIBUTING.MD
index fca621030df..5b8c94e927c 100644
--- a/docs/codeql/CONTRIBUTING.MD
+++ b/docs/codeql/CONTRIBUTING.MD
@@ -2,7 +2,7 @@
We welcome contributions to our CodeQL docs. Want to improve existing docs or add new information you think would be helpful? Then please go ahead and open a pull request!
-**Note**: We have recently copied the CodeQL CLI documentation on [codeql.github.com](https://codeql.github.com/docs/codeql-cli/) to the public [github/docs](https://github.com/github/docs) repository so that they appear on the [GitHub Docs](https://docs.github.com/en/code-security/code-scanning) site. This includes all articles under "[Using the CodeQL CLI](https://codeql.github.com/docs/codeql-cli/using-the-codeql-cli/)" and "[CodeQL CLI reference](https://codeql.github.com/docs/codeql-cli/codeql-cli-reference/)" categories. To contribute to these docs, which are located in the [`code-security`](https://github.com/github/docs/tree/main/content/code-security/code-scanning) directory, please refer to the [CONTRIBUTING.md](https://github.com/github/docs/blob/main/CONTRIBUTING.md) file in the `docs` repository.
+**Note**: We have recently copied the CodeQL CLI documentation on [codeql.github.com](https://codeql.github.com/docs/codeql-cli/) to the public [github/docs](https://github.com/github/docs) repository so that this documentation will appear on the [GitHub Docs](https://docs.github.com/en/code-security/code-scanning) site. This includes all articles under "[Using the CodeQL CLI](https://codeql.github.com/docs/codeql-cli/using-the-codeql-cli/)" and "[CodeQL CLI reference](https://codeql.github.com/docs/codeql-cli/codeql-cli-reference/)" categories. To contribute to these docs, which are located in the [`code-security`](https://github.com/github/docs/tree/main/content/code-security/code-scanning) directory, please refer to the [CONTRIBUTING.md](https://github.com/github/docs/blob/main/CONTRIBUTING.md) file in the `docs` repository.
## Contributing to docs on `codeql.github.com`
From 745d30252c54f93e365b03d7187c4e27af2966bc Mon Sep 17 00:00:00 2001
From: Sarita Iyer <66540150+saritai@users.noreply.github.com>
Date: Wed, 4 Jan 2023 16:49:27 -0500
Subject: [PATCH 111/381] Update CONTRIBUTING.MD
---
docs/codeql/CONTRIBUTING.MD | 10 ++++++++--
1 file changed, 8 insertions(+), 2 deletions(-)
diff --git a/docs/codeql/CONTRIBUTING.MD b/docs/codeql/CONTRIBUTING.MD
index 5b8c94e927c..0c1fe8f9532 100644
--- a/docs/codeql/CONTRIBUTING.MD
+++ b/docs/codeql/CONTRIBUTING.MD
@@ -2,8 +2,14 @@
We welcome contributions to our CodeQL docs. Want to improve existing docs or add new information you think would be helpful? Then please go ahead and open a pull request!
-**Note**: We have recently copied the CodeQL CLI documentation on [codeql.github.com](https://codeql.github.com/docs/codeql-cli/) to the public [github/docs](https://github.com/github/docs) repository so that this documentation will appear on the [GitHub Docs](https://docs.github.com/en/code-security/code-scanning) site. This includes all articles under "[Using the CodeQL CLI](https://codeql.github.com/docs/codeql-cli/using-the-codeql-cli/)" and "[CodeQL CLI reference](https://codeql.github.com/docs/codeql-cli/codeql-cli-reference/)" categories. To contribute to these docs, which are located in the [`code-security`](https://github.com/github/docs/tree/main/content/code-security/code-scanning) directory, please refer to the [CONTRIBUTING.md](https://github.com/github/docs/blob/main/CONTRIBUTING.md) file in the `docs` repository.
+## Contributing to CodeQL docs on `docs.github.com`
-## Contributing to docs on `codeql.github.com`
+**Note**: We have recently copied the CodeQL CLI documentation on [codeql.github.com](https://codeql.github.com/docs/codeql-cli/) to the public [github/docs](https://github.com/github/docs) repository so that this documentation will appear on the [GitHub Docs](https://docs.github.com/en/code-security/code-scanning) site. This includes all articles under "[Using the CodeQL CLI](https://codeql.github.com/docs/codeql-cli/using-the-codeql-cli/)" and "[CodeQL CLI reference](https://codeql.github.com/docs/codeql-cli/codeql-cli-reference/)" categories.
+
+To contribute to these docs, which are located in the [`code-scanning`](https://github.com/github/docs/tree/main/content/code-security/code-scanning) directory, please refer to the [CONTRIBUTING.md](https://github.com/github/docs/blob/main/CONTRIBUTING.md) file in the `docs` repository.
+
+## Contributing to CodeQL docs on `codeql.github.com`
To make changes to the remaining documentation on [codeql.github.com](https://codeql.github.com/docs/codeql-cli/), you can make changes to the documentation files using the GitHub UI, a codespace, or making changes locally, and then open a pull request for review. For more information about the format and structure of the CodeQL documentation on [codeql.github.com](https://codeql.github.com/docs/codeql-cli/), please see the [README](https://github.com/github/codeql/tree/main/docs/codeql#readme).
+
+
From d9176541c63639425155986462f91b67c7f7d083 Mon Sep 17 00:00:00 2001
From: Erik Krogh Kristensen
Date: Thu, 5 Jan 2023 20:02:54 +0100
Subject: [PATCH 112/381] Apply suggestions from code review
Co-authored-by: Alex Ford
---
.../ruby/security/UnsafeCodeConstructionCustomizations.qll | 4 ++--
.../src/queries/security/cwe-094/UnsafeCodeConstruction.qhelp | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/ruby/ql/lib/codeql/ruby/security/UnsafeCodeConstructionCustomizations.qll b/ruby/ql/lib/codeql/ruby/security/UnsafeCodeConstructionCustomizations.qll
index b6c9c3b5219..68c894f4705 100644
--- a/ruby/ql/lib/codeql/ruby/security/UnsafeCodeConstructionCustomizations.qll
+++ b/ruby/ql/lib/codeql/ruby/security/UnsafeCodeConstructionCustomizations.qll
@@ -81,10 +81,10 @@ module UnsafeCodeConstruction {
* A string constructed from a string-literal (e.g. `"foo #{sink}"`),
* where the resulting string ends up being executed as a code.
*/
- class StringFormatAsSink extends Sink {
+ class StringInterpolationAsSink extends Sink {
Concepts::CodeExecution s;
- StringFormatAsSink() {
+ StringInterpolationAsSink() {
exists(Ast::StringlikeLiteral lit |
any(DataFlow::Node n | n.asExpr().getExpr() = lit) = getANodeExecutedAsCode(s) and
this.asExpr().getExpr() = lit.getComponent(_)
diff --git a/ruby/ql/src/queries/security/cwe-094/UnsafeCodeConstruction.qhelp b/ruby/ql/src/queries/security/cwe-094/UnsafeCodeConstruction.qhelp
index 6936aee149d..f6dcb452661 100644
--- a/ruby/ql/src/queries/security/cwe-094/UnsafeCodeConstruction.qhelp
+++ b/ruby/ql/src/queries/security/cwe-094/UnsafeCodeConstruction.qhelp
@@ -69,7 +69,7 @@ to define the getter method.
This example dynamically registers a method on another class which
-forwards its arguments to a target class. This approach uses
+forwards its arguments to a target object. This approach uses
module_eval and string interpolation to construct class variables
and methods.
From f98ff65b11c1c07565283c05ba4b759c10d65832 Mon Sep 17 00:00:00 2001
From: erik-krogh
Date: Thu, 5 Jan 2023 20:03:51 +0100
Subject: [PATCH 113/381] use eval() instead of send() in test
---
.../security/cwe-094/UnsafeCodeConstruction/impl/unsafeCode.rb | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/impl/unsafeCode.rb b/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/impl/unsafeCode.rb
index 64bba0aadc6..27dd1d81f01 100644
--- a/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/impl/unsafeCode.rb
+++ b/ruby/ql/test/query-tests/security/cwe-094/UnsafeCodeConstruction/impl/unsafeCode.rb
@@ -22,7 +22,7 @@ class Foobar
end
def named_code(code)
- foo.send("def \n #{code} \n end") # OK - parameter is named code
+ eval("def \n #{code} \n end") # OK - parameter is named code
end
def joinStuff(my_arr)
From d42bb119fe0519e2632c7251229b091d1d5d8215 Mon Sep 17 00:00:00 2001
From: Rasmus Lerchedahl Petersen
Date: Thu, 5 Jan 2023 21:40:17 +0100
Subject: [PATCH 114/381] python: align annotations with Ruby use `result=BAD`
for expected alert and `result=OK` on sinks where alerts are not wanted.
---
.../dataflow/TestUtil/DataflowQueryTest.qll | 31 ++++++++++++++-----
.../command_injection.py | 26 ++++++++--------
2 files changed, 36 insertions(+), 21 deletions(-)
diff --git a/python/ql/test/experimental/dataflow/TestUtil/DataflowQueryTest.qll b/python/ql/test/experimental/dataflow/TestUtil/DataflowQueryTest.qll
index bb3a56160f3..0e6d6bf55bf 100644
--- a/python/ql/test/experimental/dataflow/TestUtil/DataflowQueryTest.qll
+++ b/python/ql/test/experimental/dataflow/TestUtil/DataflowQueryTest.qll
@@ -1,28 +1,43 @@
import python
-import experimental.dataflow.TestUtil.FlowTest
+import semmle.python.dataflow.new.DataFlow
+import TestUtilities.InlineExpectationsTest
private import semmle.python.dataflow.new.internal.PrintNode
-class DataFlowQueryTest extends FlowTest {
+class DataFlowQueryTest extends InlineExpectationsTest {
DataFlowQueryTest() { this = "DataFlowQueryTest" }
- override string flowTag() { result = "flow" }
+ override string getARelevantTag() { result = "result" }
- override predicate relevantFlow(DataFlow::Node source, DataFlow::Node sink) {
- exists(DataFlow::Configuration cfg | cfg.hasFlow(source, sink))
+ override predicate hasActualResult(Location location, string element, string tag, string value) {
+ exists(DataFlow::Configuration cfg, DataFlow::Node fromNode, DataFlow::Node toNode |
+ cfg.hasFlow(fromNode, toNode)
+ |
+ location = toNode.getLocation() and
+ tag = "result" and
+ value = "BAD" and
+ element = toNode.toString()
+ )
}
}
query predicate missingAnnotationOnSink(Location location, string error, string element) {
- error = "ERROR, you should add `# $ MISSING: flow` annotation" and
+ error = "ERROR, you should add `# $ MISSING: result=BAD` or `result=OK` annotation" and
exists(DataFlow::Node sink |
- exists(DataFlow::Configuration cfg | cfg.isSink(sink)) and
+ exists(DataFlow::Configuration cfg | cfg.isSink(sink) or cfg.isSink(sink, _)) and
location = sink.getLocation() and
element = prettyExpr(sink.asExpr()) and
not any(DataFlow::Configuration config).hasFlow(_, sink) and
not exists(FalseNegativeExpectation missingResult |
- missingResult.getTag() = "flow" and
+ missingResult.getTag() = "result" and
+ missingResult.getValue() = "BAD" and
missingResult.getLocation().getFile() = location.getFile() and
missingResult.getLocation().getStartLine() = location.getStartLine()
+ ) and
+ not exists(GoodExpectation okResult |
+ okResult.getTag() = "result" and
+ okResult.getValue() = "OK" and
+ okResult.getLocation().getFile() = location.getFile() and
+ okResult.getLocation().getStartLine() = location.getStartLine()
)
)
}
diff --git a/python/ql/test/query-tests/Security/CWE-078-CommandInjection/command_injection.py b/python/ql/test/query-tests/Security/CWE-078-CommandInjection/command_injection.py
index ef8cb221ea0..c969a1b1020 100644
--- a/python/ql/test/query-tests/Security/CWE-078-CommandInjection/command_injection.py
+++ b/python/ql/test/query-tests/Security/CWE-078-CommandInjection/command_injection.py
@@ -10,27 +10,27 @@ app = Flask(__name__)
def command_injection1():
files = request.args.get('files', '')
# Don't let files be `; rm -rf /`
- os.system("ls " + files) # $flow="ImportMember, l:-8 -> BinaryExpr"
+ os.system("ls " + files) # $result=BAD
@app.route("/command2")
def command_injection2():
files = request.args.get('files', '')
# Don't let files be `; rm -rf /`
- subprocess.Popen("ls " + files, shell=True) # $flow="ImportMember, l:-15 -> BinaryExpr"
+ subprocess.Popen("ls " + files, shell=True) # $result=BAD
@app.route("/command3")
def first_arg_injection():
cmd = request.args.get('cmd', '')
- subprocess.Popen([cmd, "param1"]) # $flow="ImportMember, l:-21 -> cmd"
+ subprocess.Popen([cmd, "param1"]) # $result=BAD
@app.route("/other_cases")
def others():
files = request.args.get('files', '')
# Don't let files be `; rm -rf /`
- os.popen("ls " + files) # $flow="ImportMember, l:-28 -> BinaryExpr"
+ os.popen("ls " + files) # $result=BAD
@app.route("/multiple")
@@ -38,8 +38,8 @@ def multiple():
command = request.args.get('command', '')
# We should mark flow to both calls here, which conflicts with removing flow out of
# a sink due to use-use flow.
- os.system(command) # $flow="ImportMember, l:-36 -> command"
- os.system(command) # $flow="ImportMember, l:-37 -> command"
+ os.system(command) # $result=BAD
+ os.system(command) # $result=BAD
@app.route("/not-into-sink-impl")
@@ -52,11 +52,11 @@ def not_into_sink_impl():
subprocess.call implementation: https://github.com/python/cpython/blob/fa7ce080175f65d678a7d5756c94f82887fc9803/Lib/subprocess.py#L341
"""
command = request.args.get('command', '')
- os.system(command) # $flow="ImportMember, l:-50 -> command"
- os.popen(command) # $flow="ImportMember, l:-51 -> command"
- subprocess.call(command) # $flow="ImportMember, l:-52 -> command"
- subprocess.check_call(command) # $flow="ImportMember, l:-53 -> command"
- subprocess.run(command) # $flow="ImportMember, l:-54 -> command"
+ os.system(command) # $result=BAD
+ os.popen(command) # $result=BAD
+ subprocess.call(command) # $result=BAD
+ subprocess.check_call(command) # $result=BAD
+ subprocess.run(command) # $result=BAD
@app.route("/path-exists-not-sanitizer")
@@ -70,11 +70,11 @@ def path_exists_not_sanitizer():
"""
path = request.args.get('path', '')
if os.path.exists(path):
- os.system("ls " + path) # $flow="ImportMember, l:-68 -> BinaryExpr"
+ os.system("ls " + path) # $result=BAD
@app.route("/restricted-characters")
def restricted_characters():
path = request.args.get('path', '')
if re.match(r'^[a-zA-Z0-9_-]+$', path):
- os.system("ls " + path) # $SPURIOUS: flow="ImportMember, l:-75 -> BinaryExpr"
+ os.system("ls " + path) # $SPURIOUS: result=BAD
From 03bd6cb414d066b85b00672966bb1fca3e365359 Mon Sep 17 00:00:00 2001
From: Rasmus Lerchedahl Petersen
Date: Fri, 6 Jan 2023 11:21:35 +0100
Subject: [PATCH 115/381] python: Allow optional `result=OK` Also add a further
test case
---
.../dataflow/TestUtil/DataflowQueryTest.qll | 29 +++++++++++++----
.../DataflowQueryTest.expected | 2 ++
.../DataflowQueryTest.ql | 3 ++
.../flask_path_injection.py | 4 +--
.../CWE-022-PathInjection/path_injection.py | 32 +++++++++----------
.../Security/CWE-022-PathInjection/test.py | 10 +++---
.../CWE-022-PathInjection/test_chaining.py | 6 ++--
7 files changed, 53 insertions(+), 33 deletions(-)
create mode 100644 python/ql/test/query-tests/Security/CWE-022-PathInjection/DataflowQueryTest.expected
create mode 100644 python/ql/test/query-tests/Security/CWE-022-PathInjection/DataflowQueryTest.ql
diff --git a/python/ql/test/experimental/dataflow/TestUtil/DataflowQueryTest.qll b/python/ql/test/experimental/dataflow/TestUtil/DataflowQueryTest.qll
index 0e6d6bf55bf..1c9259038bc 100644
--- a/python/ql/test/experimental/dataflow/TestUtil/DataflowQueryTest.qll
+++ b/python/ql/test/experimental/dataflow/TestUtil/DataflowQueryTest.qll
@@ -9,13 +9,27 @@ class DataFlowQueryTest extends InlineExpectationsTest {
override string getARelevantTag() { result = "result" }
override predicate hasActualResult(Location location, string element, string tag, string value) {
- exists(DataFlow::Configuration cfg, DataFlow::Node fromNode, DataFlow::Node toNode |
- cfg.hasFlow(fromNode, toNode)
- |
- location = toNode.getLocation() and
+ exists(DataFlow::Configuration cfg, DataFlow::Node sink | cfg.hasFlowTo(sink) |
+ location = sink.getLocation() and
tag = "result" and
value = "BAD" and
- element = toNode.toString()
+ element = sink.toString()
+ )
+ }
+
+ // We allow annotating any sink with `result=OK` to signal
+ // safe sinks.
+ // Sometimes a line contains both an alert and a safe sink.
+ // In this situation, the annotation form `OK(safe sink)`
+ // can be useful.
+ override predicate hasOptionalResult(Location location, string element, string tag, string value) {
+ exists(DataFlow::Configuration cfg, DataFlow::Node sink |
+ cfg.isSink(sink) or cfg.isSink(sink, _)
+ |
+ location = sink.getLocation() and
+ tag = "result" and
+ value in ["OK", "OK(" + prettyNode(sink) + ")"] and
+ element = sink.toString()
)
}
}
@@ -23,10 +37,11 @@ class DataFlowQueryTest extends InlineExpectationsTest {
query predicate missingAnnotationOnSink(Location location, string error, string element) {
error = "ERROR, you should add `# $ MISSING: result=BAD` or `result=OK` annotation" and
exists(DataFlow::Node sink |
+ exists(sink.getLocation().getFile().getRelativePath()) and
exists(DataFlow::Configuration cfg | cfg.isSink(sink) or cfg.isSink(sink, _)) and
location = sink.getLocation() and
element = prettyExpr(sink.asExpr()) and
- not any(DataFlow::Configuration config).hasFlow(_, sink) and
+ not exists(DataFlow::Configuration cfg | cfg.hasFlowTo(sink)) and
not exists(FalseNegativeExpectation missingResult |
missingResult.getTag() = "result" and
missingResult.getValue() = "BAD" and
@@ -35,7 +50,7 @@ query predicate missingAnnotationOnSink(Location location, string error, string
) and
not exists(GoodExpectation okResult |
okResult.getTag() = "result" and
- okResult.getValue() = "OK" and
+ okResult.getValue() in ["OK", "OK(" + prettyNode(sink) + ")"] and
okResult.getLocation().getFile() = location.getFile() and
okResult.getLocation().getStartLine() = location.getStartLine()
)
diff --git a/python/ql/test/query-tests/Security/CWE-022-PathInjection/DataflowQueryTest.expected b/python/ql/test/query-tests/Security/CWE-022-PathInjection/DataflowQueryTest.expected
new file mode 100644
index 00000000000..3875da4e143
--- /dev/null
+++ b/python/ql/test/query-tests/Security/CWE-022-PathInjection/DataflowQueryTest.expected
@@ -0,0 +1,2 @@
+missingAnnotationOnSink
+failures
diff --git a/python/ql/test/query-tests/Security/CWE-022-PathInjection/DataflowQueryTest.ql b/python/ql/test/query-tests/Security/CWE-022-PathInjection/DataflowQueryTest.ql
new file mode 100644
index 00000000000..c78e5a7c8c6
--- /dev/null
+++ b/python/ql/test/query-tests/Security/CWE-022-PathInjection/DataflowQueryTest.ql
@@ -0,0 +1,3 @@
+import python
+import experimental.dataflow.TestUtil.DataflowQueryTest
+import semmle.python.security.dataflow.PathInjectionQuery
diff --git a/python/ql/test/query-tests/Security/CWE-022-PathInjection/flask_path_injection.py b/python/ql/test/query-tests/Security/CWE-022-PathInjection/flask_path_injection.py
index ee531fead46..f64d76a3b4d 100644
--- a/python/ql/test/query-tests/Security/CWE-022-PathInjection/flask_path_injection.py
+++ b/python/ql/test/query-tests/Security/CWE-022-PathInjection/flask_path_injection.py
@@ -10,7 +10,7 @@ STATIC_DIR = "/server/static/"
def download_file():
filename = request.args.get('filename', '')
# ok since `send_from_directory` ensure this stays within `STATIC_DIR`
- return send_from_directory(STATIC_DIR, filename) # OK
+ return send_from_directory(STATIC_DIR, filename) # $result=OK
# see https://flask.palletsprojects.com/en/1.1.x/api/#flask.send_from_directory
@@ -18,4 +18,4 @@ def download_file():
def download_file():
dirname = request.args.get('dirname', '')
filename = request.args.get('filename', '')
- return send_from_directory(dirname, filename) # NOT OK
+ return send_from_directory(dirname, filename) # $result=BAD result=OK(filename)
diff --git a/python/ql/test/query-tests/Security/CWE-022-PathInjection/path_injection.py b/python/ql/test/query-tests/Security/CWE-022-PathInjection/path_injection.py
index 09c9fbcfbd1..39c17037480 100644
--- a/python/ql/test/query-tests/Security/CWE-022-PathInjection/path_injection.py
+++ b/python/ql/test/query-tests/Security/CWE-022-PathInjection/path_injection.py
@@ -10,7 +10,7 @@ STATIC_DIR = "/server/static/"
@app.route("/path1")
def path_injection():
filename = request.args.get('filename', '')
- f = open(os.path.join(STATIC_DIR, filename)) # NOT OK
+ f = open(os.path.join(STATIC_DIR, filename)) # $result=BAD
@app.route("/path2")
@@ -18,7 +18,7 @@ def path_injection():
# Normalized, but not checked
filename = request.args.get('filename', '')
npath = os.path.normpath(os.path.join(STATIC_DIR, filename))
- f = open(npath) # NOT OK
+ f = open(npath) # $result=BAD
@app.route("/path3")
@@ -28,7 +28,7 @@ def unsafe_path_normpath():
npath = os.path.normpath(os.path.join(STATIC_DIR, filename))
if npath.startswith(STATIC_DIR):
pass
- f = open(npath) # NOT OK
+ f = open(npath) # $result=BAD
@app.route("/path4")
@@ -37,7 +37,7 @@ def safe_path_normpath():
filename = request.args.get('filename', '')
npath = os.path.normpath(os.path.join(STATIC_DIR, filename))
if npath.startswith(STATIC_DIR):
- f = open(npath) # OK
+ f = open(npath) # $result=OK
@app.route("/path5")
@@ -45,7 +45,7 @@ def unsafe_path_realpath():
# Normalized (by `realpath` that also follows symlinks), but not checked properly
filename = request.args.get('filename', '')
npath = os.path.realpath(os.path.join(STATIC_DIR, filename))
- f = open(npath) # NOT OK
+ f = open(npath) # $result=BAD
@app.route("/path6")
@@ -54,7 +54,7 @@ def safe_path_realpath():
filename = request.args.get('filename', '')
npath = os.path.realpath(os.path.join(STATIC_DIR, filename))
if npath.startswith(STATIC_DIR):
- f = open(npath) # OK
+ f = open(npath) # $result=OK
@app.route("/path6")
@@ -62,7 +62,7 @@ def unsafe_path_abspath():
# Normalized (by `abspath`), but not checked properly
filename = request.args.get('filename', '')
npath = os.path.abspath(os.path.join(STATIC_DIR, filename))
- f = open(npath) # NOT OK
+ f = open(npath) # $result=BAD
@app.route("/path7")
@@ -71,7 +71,7 @@ def safe_path_abspath():
filename = request.args.get('filename', '')
npath = os.path.abspath(os.path.join(STATIC_DIR, filename))
if npath.startswith(STATIC_DIR):
- f = open(npath) # OK
+ f = open(npath) # $result=OK
@app.route("/abspath_tricky")
@@ -84,14 +84,14 @@ def safe_path_abspath_tricky():
filename = request.args.get('filename', '')
possibly_unsafe_path = os.path.join(STATIC_DIR, filename)
if os.path.abspath(possibly_unsafe_path).startswith(STATIC_DIR):
- f = open(possibly_unsafe_path) # OK
+ f = open(possibly_unsafe_path) # $SPURIOUS: result=BAD
@app.route("/int-only/")
def flask_int_only(foo_id):
# This is OK, since the flask routing ensures that `foo_id` MUST be an integer.
path = os.path.join(STATIC_DIR, foo_id)
- f = open(path) # OK TODO: FP
+ f = open(path) # $spurious: result=BAD
@app.route("/not-path/")
@@ -99,7 +99,7 @@ def flask_not_path(foo):
# On UNIX systems, this is OK, since without being marked as ``, flask
# routing ensures that `foo` cannot contain forward slashes (not by using %2F either).
path = os.path.join(STATIC_DIR, foo)
- f = open(path) # OK if only running on UNIX systems, NOT OK if could be running on windows
+ f = open(path) # $result=BAD // OK if only running on UNIX systems, NOT OK if could be running on windows
@app.route("/no-dot-dot")
@@ -110,7 +110,7 @@ def no_dot_dot():
# handle if `filename` is an absolute path
if '../' in path:
return "not this time"
- f = open(path) # NOT OK
+ f = open(path) # $result=BAD
@app.route("/no-dot-dot-with-prefix")
@@ -121,7 +121,7 @@ def no_dot_dot_with_prefix():
# Therefore, for UNIX-only programs, the `../` check is enough to stop path injections.
if '../' in path:
return "not this time"
- f = open(path) # OK if only running on UNIX systems, NOT OK if could be running on windows
+ f = open(path) # $result=BAD // OK if only running on UNIX systems, NOT OK if could be running on windows
@app.route("/replace-slash")
@@ -129,7 +129,7 @@ def replace_slash():
filename = request.args.get('filename', '')
path = os.path.join(STATIC_DIR, filename)
sanitized = path.replace("/", "_")
- f = open(sanitized) # OK if only running on UNIX systems, NOT OK if could be running on windows
+ f = open(sanitized) # $result=BAD // OK if only running on UNIX systems, NOT OK if could be running on windows
@app.route("/stackoverflow-solution")
@@ -139,7 +139,7 @@ def stackoverflow_solution():
path = os.path.join(STATIC_DIR, filename)
if os.path.commonprefix((os.path.realpath(path), STATIC_DIR)) != STATIC_DIR:
return "not this time"
- f = open(path) # OK TODO: FP
+ f = open(path) # $SPURIOUS: result=BAD
SAFE_FILES = ['foo', 'bar', 'baz']
@@ -149,4 +149,4 @@ def safe_set_of_files():
filename = request.args.get('filename', '')
if filename in SAFE_FILES:
path = os.path.join(STATIC_DIR, filename)
- f = open(path) # OK TODO: FP
+ f = open(path) # $SPURIOUS: result=BAD
diff --git a/python/ql/test/query-tests/Security/CWE-022-PathInjection/test.py b/python/ql/test/query-tests/Security/CWE-022-PathInjection/test.py
index a64241db099..7200cd78f45 100644
--- a/python/ql/test/query-tests/Security/CWE-022-PathInjection/test.py
+++ b/python/ql/test/query-tests/Security/CWE-022-PathInjection/test.py
@@ -16,21 +16,21 @@ def normalize(x):
@app.route("/path")
def simple():
x = source()
- open(x) # NOT OK
+ open(x) # $result=BAD
@app.route("/path")
def normalization():
x = source()
y = normalize(x)
- open(y) # NOT OK
+ open(y) # $result=BAD
@app.route("/path")
def check():
x = source()
if x.startswith("subfolder/"):
- open(x) # NOT OK
+ open(x) # $result=BAD
@app.route("/path")
@@ -38,7 +38,7 @@ def normalize_then_check():
x = source()
y = normalize(x)
if y.startswith("subfolder/"):
- open(y) # OK
+ open(y) # $result=OK
@app.route("/path")
@@ -46,4 +46,4 @@ def check_then_normalize():
x = source()
if x.startswith("subfolder/"):
y = normalize(x)
- open(y) # NOT OK
+ open(y) # $result=BAD
diff --git a/python/ql/test/query-tests/Security/CWE-022-PathInjection/test_chaining.py b/python/ql/test/query-tests/Security/CWE-022-PathInjection/test_chaining.py
index ad1126e0e65..05d8f2620b1 100644
--- a/python/ql/test/query-tests/Security/CWE-022-PathInjection/test_chaining.py
+++ b/python/ql/test/query-tests/Security/CWE-022-PathInjection/test_chaining.py
@@ -20,7 +20,7 @@ def normalize_then_check():
x = source()
y = normalize(x) # <--- this call...
if y.startswith("subfolder/"):
- open(y) # OK
+ open(y) # $result=OK
@app.route("/path")
@@ -29,7 +29,7 @@ def normalize_check_normalize():
y = normalize(x) # (...or this call...)
if y.startswith("subfolder/"):
z = normalize(y) # <--- ...can jump to here, resulting in FP
- open(z) # OK
+ open(z) # $result=OK
# The problem does not manifest if we simply define an alias
@@ -42,4 +42,4 @@ def normalize_check_normalize_alias():
y = normpath(x)
if y.startswith("subfolder/"):
z = normpath(y)
- open(z) # OK
+ open(z) # $result=OK
From d68cfc7d4f90b83c337e03eec56f4080e3903456 Mon Sep 17 00:00:00 2001
From: Sarita Iyer <66540150+saritai@users.noreply.github.com>
Date: Fri, 6 Jan 2023 11:17:02 -0500
Subject: [PATCH 116/381] codeql pack compatibility docs
---
docs/codeql/codeql-cli/about-codeql-packs.rst | 14 ++++++-
...creating-and-working-with-codeql-packs.rst | 16 +++++++-
.../publishing-and-using-codeql-packs.rst | 39 +++++++++++++++++++
3 files changed, 65 insertions(+), 4 deletions(-)
diff --git a/docs/codeql/codeql-cli/about-codeql-packs.rst b/docs/codeql/codeql-cli/about-codeql-packs.rst
index 68f67cb7ba9..8cfe072f2c9 100644
--- a/docs/codeql/codeql-cli/about-codeql-packs.rst
+++ b/docs/codeql/codeql-cli/about-codeql-packs.rst
@@ -9,8 +9,8 @@ CodeQL packs are used to create, share, depend on, and run CodeQL queries and li
There are two types of CodeQL packs: query packs and library packs.
-* Query packs are designed to be run. When a query pack is published, the bundle includes all the transitive dependencies and a compilation cache. This ensures consistent and efficient execution of the queries in the pack.
-* Library packs are designed to be used by query packs (or other library packs) and do not contain queries themselves. The libraries are not compiled and there is no compilation cache included when the pack is published.
+* Query packs are designed to be run. When a query pack is published, the bundle includes all the transitive dependencies and pre-compiled representations of each query, in addition to the query sources. This ensures consistent and efficient execution of the queries in the pack.
+* Library packs are designed to be used by query packs (or other library packs) and do not contain queries themselves. The libraries are not compiled separately.
You can use the package management commands in the CodeQL CLI to create CodeQL packs, add dependencies to packs, and install or update dependencies. For more information, see ":ref:`Creating and working with CodeQL packs `." You can also publish and download CodeQL packs using the CodeQL CLI. For more information, see ":doc:`Publishing and using CodeQL packs `."
@@ -31,6 +31,16 @@ The other files and directories within the pack should be logically organized. F
- Queries for specific products, libraries, and frameworks are organized into
their own top-level directories.
+About published packs
+--------------------------
+
+When a pack is published for use in analyses, the ``codeql pack create`` or ``codeql pack publish`` command verifies that the content is complete and also adds some additional pieces of content to it:
+
+* For query packs, a copy of each of the library packs it depends on, in the precise versions it has been developed with. Users of the query pack won't need to download these library packs separately.
+* For query packs, precompiled representations of each of the queries. These are faster to execute than it would be to compile the QL source for the query at each analysis.
+
+Most of this data is located in a directory named ``.codeql`` in the published pack, but precompiled queries are in files with a ``.qlx`` suffix next to the ``.ql`` source for each query. When analyzing a database with a query from a published pack, CodeQL will load these files instead of the ``.ql`` source. If you need to modify the content of a *published* pack, be sure to remove all of the ``.qlx`` files, since they may prevent modifications in the ``.ql`` files from taking effect.
+
About ``qlpack.yml`` files
--------------------------
diff --git a/docs/codeql/codeql-cli/creating-and-working-with-codeql-packs.rst b/docs/codeql/codeql-cli/creating-and-working-with-codeql-packs.rst
index 7d2001dded5..f19788f1afc 100644
--- a/docs/codeql/codeql-cli/creating-and-working-with-codeql-packs.rst
+++ b/docs/codeql/codeql-cli/creating-and-working-with-codeql-packs.rst
@@ -14,11 +14,13 @@ With CodeQL packs and the package management commands in the CodeQL CLI, you can
There are two types of CodeQL packs: query packs and library packs.
-* Query packs are designed to be run. When a query pack is published, the bundle includes all the transitive dependencies and a compilation cache. This ensures consistent and efficient execution of the queries in the pack.
-* Library packs are designed to be used by query packs (or other library packs) and do not contain queries themselves. The libraries are not compiled and there is no compilation cache included when the pack is published.
+* Query packs are designed to be run. When a query pack is published, the bundle includes all the transitive dependencies and pre-compiled representations of each query, in addition to the query sources. This ensures consistent and efficient execution of the queries in the pack.
+* Library packs are designed to be used by query packs (or other library packs) and do not contain queries themselves. The libraries are not compiled separately.
You can use the ``pack`` command in the CodeQL CLI to create CodeQL packs, add dependencies to packs, and install or update dependencies. You can also publish and download CodeQL packs using the ``pack`` command. For more information, see ":doc:`Publishing and using CodeQL packs `."
+For more information about compatibility between published query packs and different CodeQL releases, see ":ref:`About CodeQL pack compatibility `."
+
Creating a CodeQL pack
----------------------
You can create a CodeQL pack by running the following command from the checkout root of your project:
@@ -81,3 +83,13 @@ This command downloads all dependencies to the shared cache on the local disk.
By default ``codeql pack install`` will install dependencies from the Container registry on GitHub.com.
You can install dependencies from a GitHub Enterprise Server Container registry by creating a ``qlconfig.yml`` file.
For more information, see ":doc:`Publishing and using CodeQL packs `."
+
+Customizing a downloaded CodeQL pack
+---------------------------------------------------
+
+The recommended way to experiment with changes to a pack is to clone the repository containing its source code.
+
+If no source respository is available and you need to base modifications on a pack downloaded from the Container registry, be aware that these packs are not intended to be modified or customized after downloading, and their format may change in the future without much notice. We recommend taking the following steps after downloading a pack if you need to modify the content:
+
+- Change the pack *name* in ``qlpack.yml`` so you avoid confusion with results from the unmodified pack.
+- Remove all files named ``*.qlx`` anywhere in the unpacked directory structure. These files contain precompiled versions of the queries, and in some situations CodeQL will use them in preference to the QL source you have modified.
\ No newline at end of file
diff --git a/docs/codeql/codeql-cli/publishing-and-using-codeql-packs.rst b/docs/codeql/codeql-cli/publishing-and-using-codeql-packs.rst
index a91bc570768..93b27ea94aa 100644
--- a/docs/codeql/codeql-cli/publishing-and-using-codeql-packs.rst
+++ b/docs/codeql/codeql-cli/publishing-and-using-codeql-packs.rst
@@ -53,6 +53,9 @@ To run a pack that someone else has created, you must first download it by runni
This command accepts arguments for multiple packs.
+If you write scripts that specify a particular version number of a query pack to download, keep in mind that when you update your version of CodeQL to a newer one, you may also need to switch to a newer version of the query pack. Newer versions of CodeQL *may* provide
+degraded performance when used with query packs that have been pinned to a very old version. For more information, see ":ref:`About CodeQL pack compatibility `."
+
Using a CodeQL pack to analyze a CodeQL database
------------------------------------------------
@@ -74,6 +77,42 @@ The ``analyze`` command will run the default suite of any specified CodeQL packs
codeql analyze //
+.. pull-quote::
+
+ Note
+
+ The ``codeql pack download`` command stores the pack it downloads in an internal location that is not intended for local modification. Unexpected (and hard to troubleshoot) behavior may result if the pack is modified after downloading. For more information about customizing packs, see ":ref:`Creating and working with CodeQL packs `."
+
+About CodeQL pack compatibility
+-------------------------------
+
+When a query pack is published, it includes pre-compiled representations of all the queries in it. These pre-compiled queries are generally much faster to execute than it is to compile the QL source from scratch during the analysis. However, the pre-compiled queries also depend on certain internals of the QL evaluator, so if the version of CodeQL that performs the analysis is too different from the version that ran ``codeql pack publish``, it may be necessary to compile the queries from source instead during analysis. The recompilation happens automatically and will not affect the *results* of the analysis, but it can make the
+analysis significantly slower.
+
+It can generally be assumed that if a pack is published with one release of CodeQL, the precompiled queries in it can be used directly by *later* releases of CodeQL, as long as there is no more than 6 months between the release dates. We will make reasonable efforts to keep new releases compatible for longer than that, but make no promises.
+
+It can also be assumed that a pack published by the *latest* public release of CodeQL will be useable by the version of CodeQL that is used by code scanning and GitHub Actions, even though that is often a slightly older release.
+
+As an exception to the above, packs published with versions of CodeQL *earlier than 2.12.0* are not compatible with any earlier or later versions. These old versions did not write pre-compiled queries in a format that supported compatibility between releases. Packs published by these versions can still be *used* by newer versions, but the analysis will be slower because the queries have to be recompiled first.
+
+As a user of a published query pack, you can check that the CodeQL makes use of the precompiled queries in it by inspecting the terminal output from an analysis runs that uses the query pack. If it contains lines looking like the following, then the precompiled queries were used successfully:
+
+::
+
+ [42/108] Loaded /long/path/to/query/Filename.qlx.
+
+However, if they instead look like the following, then usage of the precompiled queries failed:
+
+::
+ Compiling query plan for /long/path/to/query/Filename.ql.
+ [42/108 comp 25s] Compiled /long/path/to/query/Filename.ql.
+
+The results of the analysis will still be good in this case, but to get optimal performance you may need to upgrade to a newer version of the CodeQL CLI and/or of the query pack.
+
+If you publish query packs on the Container registry on GitHub.com for others to use, we recommend that you use a recent release of CodeQL to run ``codeql pack publish``, and that you publish a fresh version of your pack with an updated CodeQL version before the version you used turns 6 months old. That way you can ensure that users of your pack who keep *their* CodeQL up to date will benefit from the pre-compiled queries in your pack.
+
+If you publish query packs with the intention of using them on a GitHub Enterprise Server installation that uses its bundled CodeQL binaries, use the same CodeQL version to run ``codeql pack publish``. Newer versions might produce pre-compiled queries that the one in GitHub Enterprise Server may not recognize. Your GitHub Enterprise Server administrator may choose to upgrade to a newer version of CodeQL periodically. If so, follow their lead.
+
.. _working-with-codeql-packs-on-ghes:
Working with CodeQL packs on GitHub Enterprise Server
From a9867a266e9cf4b789479e8b6ca55f567b2f2dfc Mon Sep 17 00:00:00 2001
From: Sarita Iyer <66540150+saritai@users.noreply.github.com>
Date: Fri, 6 Jan 2023 11:50:07 -0500
Subject: [PATCH 117/381] fixed link
---
docs/codeql/codeql-cli/publishing-and-using-codeql-packs.rst | 2 ++
1 file changed, 2 insertions(+)
diff --git a/docs/codeql/codeql-cli/publishing-and-using-codeql-packs.rst b/docs/codeql/codeql-cli/publishing-and-using-codeql-packs.rst
index 93b27ea94aa..afa851e4185 100644
--- a/docs/codeql/codeql-cli/publishing-and-using-codeql-packs.rst
+++ b/docs/codeql/codeql-cli/publishing-and-using-codeql-packs.rst
@@ -83,6 +83,8 @@ The ``analyze`` command will run the default suite of any specified CodeQL packs
The ``codeql pack download`` command stores the pack it downloads in an internal location that is not intended for local modification. Unexpected (and hard to troubleshoot) behavior may result if the pack is modified after downloading. For more information about customizing packs, see ":ref:`Creating and working with CodeQL packs `."
+.. _about-codeql-pack-compatibility:
+
About CodeQL pack compatibility
-------------------------------
From 04f87a26a951e39e5f73433c41b60e0f6e64bee7 Mon Sep 17 00:00:00 2001
From: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
Date: Fri, 6 Jan 2023 16:52:47 +0000
Subject: [PATCH 118/381] Swift: Test layout change.
---
.../dataflow/dataflow/DataFlow.expected | 84 +++++++++----------
.../dataflow/dataflow/LocalFlow.expected | 82 +++++++++---------
.../dataflow/dataflow/test.swift | 45 ++++++++--
3 files changed, 120 insertions(+), 91 deletions(-)
diff --git a/swift/ql/test/library-tests/dataflow/dataflow/DataFlow.expected b/swift/ql/test/library-tests/dataflow/dataflow/DataFlow.expected
index 1277d30cdc2..6a7fd737998 100644
--- a/swift/ql/test/library-tests/dataflow/dataflow/DataFlow.expected
+++ b/swift/ql/test/library-tests/dataflow/dataflow/DataFlow.expected
@@ -114,22 +114,22 @@ edges
| test.swift:271:15:271:25 | call to signum() : | test.swift:271:15:271:25 | OptionalEvaluationExpr |
| test.swift:280:31:280:38 | call to source() : | test.swift:280:15:280:38 | ... ? ... : ... |
| test.swift:282:31:282:38 | call to source() : | test.swift:282:15:282:38 | ... ? ... : ... |
-| test.swift:302:14:302:26 | (...) [Tuple element at index 1] : | test.swift:306:15:306:15 | t1 [Tuple element at index 1] : |
-| test.swift:302:18:302:25 | call to source() : | test.swift:302:14:302:26 | (...) [Tuple element at index 1] : |
-| test.swift:306:15:306:15 | t1 [Tuple element at index 1] : | test.swift:306:15:306:18 | .1 |
-| test.swift:314:5:314:5 | [post] t1 [Tuple element at index 0] : | test.swift:317:15:317:15 | t1 [Tuple element at index 0] : |
-| test.swift:314:12:314:19 | call to source() : | test.swift:314:5:314:5 | [post] t1 [Tuple element at index 0] : |
-| test.swift:317:15:317:15 | t1 [Tuple element at index 0] : | test.swift:317:15:317:18 | .0 |
-| test.swift:322:14:322:45 | (...) [Tuple element at index 0] : | test.swift:327:15:327:15 | t1 [Tuple element at index 0] : |
-| test.swift:322:14:322:45 | (...) [Tuple element at index 0] : | test.swift:331:15:331:15 | t2 [Tuple element at index 0] : |
-| test.swift:322:14:322:45 | (...) [Tuple element at index 1] : | test.swift:328:15:328:15 | t1 [Tuple element at index 1] : |
-| test.swift:322:14:322:45 | (...) [Tuple element at index 1] : | test.swift:332:15:332:15 | t2 [Tuple element at index 1] : |
-| test.swift:322:18:322:25 | call to source() : | test.swift:322:14:322:45 | (...) [Tuple element at index 0] : |
-| test.swift:322:31:322:38 | call to source() : | test.swift:322:14:322:45 | (...) [Tuple element at index 1] : |
-| test.swift:327:15:327:15 | t1 [Tuple element at index 0] : | test.swift:327:15:327:18 | .0 |
-| test.swift:328:15:328:15 | t1 [Tuple element at index 1] : | test.swift:328:15:328:18 | .1 |
-| test.swift:331:15:331:15 | t2 [Tuple element at index 0] : | test.swift:331:15:331:18 | .0 |
-| test.swift:332:15:332:15 | t2 [Tuple element at index 1] : | test.swift:332:15:332:18 | .1 |
+| test.swift:331:14:331:26 | (...) [Tuple element at index 1] : | test.swift:335:15:335:15 | t1 [Tuple element at index 1] : |
+| test.swift:331:18:331:25 | call to source() : | test.swift:331:14:331:26 | (...) [Tuple element at index 1] : |
+| test.swift:335:15:335:15 | t1 [Tuple element at index 1] : | test.swift:335:15:335:18 | .1 |
+| test.swift:343:5:343:5 | [post] t1 [Tuple element at index 0] : | test.swift:346:15:346:15 | t1 [Tuple element at index 0] : |
+| test.swift:343:12:343:19 | call to source() : | test.swift:343:5:343:5 | [post] t1 [Tuple element at index 0] : |
+| test.swift:346:15:346:15 | t1 [Tuple element at index 0] : | test.swift:346:15:346:18 | .0 |
+| test.swift:351:14:351:45 | (...) [Tuple element at index 0] : | test.swift:356:15:356:15 | t1 [Tuple element at index 0] : |
+| test.swift:351:14:351:45 | (...) [Tuple element at index 0] : | test.swift:360:15:360:15 | t2 [Tuple element at index 0] : |
+| test.swift:351:14:351:45 | (...) [Tuple element at index 1] : | test.swift:357:15:357:15 | t1 [Tuple element at index 1] : |
+| test.swift:351:14:351:45 | (...) [Tuple element at index 1] : | test.swift:361:15:361:15 | t2 [Tuple element at index 1] : |
+| test.swift:351:18:351:25 | call to source() : | test.swift:351:14:351:45 | (...) [Tuple element at index 0] : |
+| test.swift:351:31:351:38 | call to source() : | test.swift:351:14:351:45 | (...) [Tuple element at index 1] : |
+| test.swift:356:15:356:15 | t1 [Tuple element at index 0] : | test.swift:356:15:356:18 | .0 |
+| test.swift:357:15:357:15 | t1 [Tuple element at index 1] : | test.swift:357:15:357:18 | .1 |
+| test.swift:360:15:360:15 | t2 [Tuple element at index 0] : | test.swift:360:15:360:18 | .0 |
+| test.swift:361:15:361:15 | t2 [Tuple element at index 1] : | test.swift:361:15:361:18 | .1 |
nodes
| file://:0:0:0:0 | .a [x] : | semmle.label | .a [x] : |
| file://:0:0:0:0 | .x : | semmle.label | .x : |
@@ -258,26 +258,26 @@ nodes
| test.swift:280:31:280:38 | call to source() : | semmle.label | call to source() : |
| test.swift:282:15:282:38 | ... ? ... : ... | semmle.label | ... ? ... : ... |
| test.swift:282:31:282:38 | call to source() : | semmle.label | call to source() : |
-| test.swift:302:14:302:26 | (...) [Tuple element at index 1] : | semmle.label | (...) [Tuple element at index 1] : |
-| test.swift:302:18:302:25 | call to source() : | semmle.label | call to source() : |
-| test.swift:306:15:306:15 | t1 [Tuple element at index 1] : | semmle.label | t1 [Tuple element at index 1] : |
-| test.swift:306:15:306:18 | .1 | semmle.label | .1 |
-| test.swift:314:5:314:5 | [post] t1 [Tuple element at index 0] : | semmle.label | [post] t1 [Tuple element at index 0] : |
-| test.swift:314:12:314:19 | call to source() : | semmle.label | call to source() : |
-| test.swift:317:15:317:15 | t1 [Tuple element at index 0] : | semmle.label | t1 [Tuple element at index 0] : |
-| test.swift:317:15:317:18 | .0 | semmle.label | .0 |
-| test.swift:322:14:322:45 | (...) [Tuple element at index 0] : | semmle.label | (...) [Tuple element at index 0] : |
-| test.swift:322:14:322:45 | (...) [Tuple element at index 1] : | semmle.label | (...) [Tuple element at index 1] : |
-| test.swift:322:18:322:25 | call to source() : | semmle.label | call to source() : |
-| test.swift:322:31:322:38 | call to source() : | semmle.label | call to source() : |
-| test.swift:327:15:327:15 | t1 [Tuple element at index 0] : | semmle.label | t1 [Tuple element at index 0] : |
-| test.swift:327:15:327:18 | .0 | semmle.label | .0 |
-| test.swift:328:15:328:15 | t1 [Tuple element at index 1] : | semmle.label | t1 [Tuple element at index 1] : |
-| test.swift:328:15:328:18 | .1 | semmle.label | .1 |
-| test.swift:331:15:331:15 | t2 [Tuple element at index 0] : | semmle.label | t2 [Tuple element at index 0] : |
-| test.swift:331:15:331:18 | .0 | semmle.label | .0 |
-| test.swift:332:15:332:15 | t2 [Tuple element at index 1] : | semmle.label | t2 [Tuple element at index 1] : |
-| test.swift:332:15:332:18 | .1 | semmle.label | .1 |
+| test.swift:331:14:331:26 | (...) [Tuple element at index 1] : | semmle.label | (...) [Tuple element at index 1] : |
+| test.swift:331:18:331:25 | call to source() : | semmle.label | call to source() : |
+| test.swift:335:15:335:15 | t1 [Tuple element at index 1] : | semmle.label | t1 [Tuple element at index 1] : |
+| test.swift:335:15:335:18 | .1 | semmle.label | .1 |
+| test.swift:343:5:343:5 | [post] t1 [Tuple element at index 0] : | semmle.label | [post] t1 [Tuple element at index 0] : |
+| test.swift:343:12:343:19 | call to source() : | semmle.label | call to source() : |
+| test.swift:346:15:346:15 | t1 [Tuple element at index 0] : | semmle.label | t1 [Tuple element at index 0] : |
+| test.swift:346:15:346:18 | .0 | semmle.label | .0 |
+| test.swift:351:14:351:45 | (...) [Tuple element at index 0] : | semmle.label | (...) [Tuple element at index 0] : |
+| test.swift:351:14:351:45 | (...) [Tuple element at index 1] : | semmle.label | (...) [Tuple element at index 1] : |
+| test.swift:351:18:351:25 | call to source() : | semmle.label | call to source() : |
+| test.swift:351:31:351:38 | call to source() : | semmle.label | call to source() : |
+| test.swift:356:15:356:15 | t1 [Tuple element at index 0] : | semmle.label | t1 [Tuple element at index 0] : |
+| test.swift:356:15:356:18 | .0 | semmle.label | .0 |
+| test.swift:357:15:357:15 | t1 [Tuple element at index 1] : | semmle.label | t1 [Tuple element at index 1] : |
+| test.swift:357:15:357:18 | .1 | semmle.label | .1 |
+| test.swift:360:15:360:15 | t2 [Tuple element at index 0] : | semmle.label | t2 [Tuple element at index 0] : |
+| test.swift:360:15:360:18 | .0 | semmle.label | .0 |
+| test.swift:361:15:361:15 | t2 [Tuple element at index 1] : | semmle.label | t2 [Tuple element at index 1] : |
+| test.swift:361:15:361:18 | .1 | semmle.label | .1 |
subpaths
| test.swift:75:21:75:22 | &... : | test.swift:65:16:65:28 | arg1 : | test.swift:65:1:70:1 | arg2[return] : | test.swift:75:31:75:32 | [post] &... : |
| test.swift:114:19:114:19 | arg : | test.swift:109:9:109:14 | arg : | test.swift:110:12:110:12 | arg : | test.swift:114:12:114:22 | call to ... : |
@@ -345,9 +345,9 @@ subpaths
| test.swift:280:15:280:38 | ... ? ... : ... | test.swift:259:12:259:19 | call to source() : | test.swift:280:15:280:38 | ... ? ... : ... | result |
| test.swift:280:15:280:38 | ... ? ... : ... | test.swift:280:31:280:38 | call to source() : | test.swift:280:15:280:38 | ... ? ... : ... | result |
| test.swift:282:15:282:38 | ... ? ... : ... | test.swift:282:31:282:38 | call to source() : | test.swift:282:15:282:38 | ... ? ... : ... | result |
-| test.swift:306:15:306:18 | .1 | test.swift:302:18:302:25 | call to source() : | test.swift:306:15:306:18 | .1 | result |
-| test.swift:317:15:317:18 | .0 | test.swift:314:12:314:19 | call to source() : | test.swift:317:15:317:18 | .0 | result |
-| test.swift:327:15:327:18 | .0 | test.swift:322:18:322:25 | call to source() : | test.swift:327:15:327:18 | .0 | result |
-| test.swift:328:15:328:18 | .1 | test.swift:322:31:322:38 | call to source() : | test.swift:328:15:328:18 | .1 | result |
-| test.swift:331:15:331:18 | .0 | test.swift:322:18:322:25 | call to source() : | test.swift:331:15:331:18 | .0 | result |
-| test.swift:332:15:332:18 | .1 | test.swift:322:31:322:38 | call to source() : | test.swift:332:15:332:18 | .1 | result |
+| test.swift:335:15:335:18 | .1 | test.swift:331:18:331:25 | call to source() : | test.swift:335:15:335:18 | .1 | result |
+| test.swift:346:15:346:18 | .0 | test.swift:343:12:343:19 | call to source() : | test.swift:346:15:346:18 | .0 | result |
+| test.swift:356:15:356:18 | .0 | test.swift:351:18:351:25 | call to source() : | test.swift:356:15:356:18 | .0 | result |
+| test.swift:357:15:357:18 | .1 | test.swift:351:31:351:38 | call to source() : | test.swift:357:15:357:18 | .1 | result |
+| test.swift:360:15:360:18 | .0 | test.swift:351:18:351:25 | call to source() : | test.swift:360:15:360:18 | .0 | result |
+| test.swift:361:15:361:18 | .1 | test.swift:351:31:351:38 | call to source() : | test.swift:361:15:361:18 | .1 | result |
diff --git a/swift/ql/test/library-tests/dataflow/dataflow/LocalFlow.expected b/swift/ql/test/library-tests/dataflow/dataflow/LocalFlow.expected
index 9a0d359d371..b320e2cff84 100644
--- a/swift/ql/test/library-tests/dataflow/dataflow/LocalFlow.expected
+++ b/swift/ql/test/library-tests/dataflow/dataflow/LocalFlow.expected
@@ -247,44 +247,44 @@
| test.swift:290:16:290:26 | call to signum() | test.swift:290:16:290:26 | OptionalEvaluationExpr |
| test.swift:293:16:293:16 | y | test.swift:293:16:293:17 | ...? |
| test.swift:293:16:293:26 | call to signum() | test.swift:293:16:293:26 | OptionalEvaluationExpr |
-| test.swift:302:9:302:9 | SSA def(t1) | test.swift:304:15:304:15 | t1 |
-| test.swift:302:14:302:26 | (...) | test.swift:302:9:302:9 | SSA def(t1) |
-| test.swift:304:15:304:15 | t1 | test.swift:305:15:305:15 | t1 |
-| test.swift:305:15:305:15 | [post] t1 | test.swift:306:15:306:15 | t1 |
-| test.swift:305:15:305:15 | t1 | test.swift:306:15:306:15 | t1 |
-| test.swift:306:15:306:15 | [post] t1 | test.swift:308:5:308:5 | t1 |
-| test.swift:306:15:306:15 | t1 | test.swift:308:5:308:5 | t1 |
-| test.swift:308:5:308:5 | [post] t1 | test.swift:310:15:310:15 | t1 |
-| test.swift:308:5:308:5 | t1 | test.swift:310:15:310:15 | t1 |
-| test.swift:310:15:310:15 | t1 | test.swift:311:15:311:15 | t1 |
-| test.swift:311:15:311:15 | [post] t1 | test.swift:312:15:312:15 | t1 |
-| test.swift:311:15:311:15 | t1 | test.swift:312:15:312:15 | t1 |
-| test.swift:312:15:312:15 | [post] t1 | test.swift:314:5:314:5 | t1 |
-| test.swift:312:15:312:15 | t1 | test.swift:314:5:314:5 | t1 |
-| test.swift:314:5:314:5 | [post] t1 | test.swift:316:15:316:15 | t1 |
-| test.swift:314:5:314:5 | t1 | test.swift:316:15:316:15 | t1 |
-| test.swift:316:15:316:15 | t1 | test.swift:317:15:317:15 | t1 |
-| test.swift:317:15:317:15 | [post] t1 | test.swift:318:15:318:15 | t1 |
-| test.swift:317:15:317:15 | t1 | test.swift:318:15:318:15 | t1 |
-| test.swift:322:9:322:9 | SSA def(t1) | test.swift:323:14:323:14 | t1 |
-| test.swift:322:14:322:45 | (...) | test.swift:322:9:322:9 | SSA def(t1) |
-| test.swift:323:9:323:9 | SSA def(t2) | test.swift:330:15:330:15 | t2 |
-| test.swift:323:14:323:14 | t1 | test.swift:323:9:323:9 | SSA def(t2) |
-| test.swift:323:14:323:14 | t1 | test.swift:324:21:324:21 | t1 |
-| test.swift:324:9:324:17 | SSA def(a) | test.swift:334:15:334:15 | a |
-| test.swift:324:9:324:17 | SSA def(b) | test.swift:335:15:335:15 | b |
-| test.swift:324:9:324:17 | SSA def(c) | test.swift:336:15:336:15 | c |
-| test.swift:324:21:324:21 | t1 | test.swift:324:9:324:17 | SSA def(a) |
-| test.swift:324:21:324:21 | t1 | test.swift:324:9:324:17 | SSA def(b) |
-| test.swift:324:21:324:21 | t1 | test.swift:324:9:324:17 | SSA def(c) |
-| test.swift:324:21:324:21 | t1 | test.swift:326:15:326:15 | t1 |
-| test.swift:326:15:326:15 | t1 | test.swift:327:15:327:15 | t1 |
-| test.swift:327:15:327:15 | [post] t1 | test.swift:328:15:328:15 | t1 |
-| test.swift:327:15:327:15 | t1 | test.swift:328:15:328:15 | t1 |
-| test.swift:328:15:328:15 | [post] t1 | test.swift:329:15:329:15 | t1 |
-| test.swift:328:15:328:15 | t1 | test.swift:329:15:329:15 | t1 |
-| test.swift:330:15:330:15 | t2 | test.swift:331:15:331:15 | t2 |
-| test.swift:331:15:331:15 | [post] t2 | test.swift:332:15:332:15 | t2 |
-| test.swift:331:15:331:15 | t2 | test.swift:332:15:332:15 | t2 |
-| test.swift:332:15:332:15 | [post] t2 | test.swift:333:15:333:15 | t2 |
-| test.swift:332:15:332:15 | t2 | test.swift:333:15:333:15 | t2 |
+| test.swift:331:9:331:9 | SSA def(t1) | test.swift:333:15:333:15 | t1 |
+| test.swift:331:14:331:26 | (...) | test.swift:331:9:331:9 | SSA def(t1) |
+| test.swift:333:15:333:15 | t1 | test.swift:334:15:334:15 | t1 |
+| test.swift:334:15:334:15 | [post] t1 | test.swift:335:15:335:15 | t1 |
+| test.swift:334:15:334:15 | t1 | test.swift:335:15:335:15 | t1 |
+| test.swift:335:15:335:15 | [post] t1 | test.swift:337:5:337:5 | t1 |
+| test.swift:335:15:335:15 | t1 | test.swift:337:5:337:5 | t1 |
+| test.swift:337:5:337:5 | [post] t1 | test.swift:339:15:339:15 | t1 |
+| test.swift:337:5:337:5 | t1 | test.swift:339:15:339:15 | t1 |
+| test.swift:339:15:339:15 | t1 | test.swift:340:15:340:15 | t1 |
+| test.swift:340:15:340:15 | [post] t1 | test.swift:341:15:341:15 | t1 |
+| test.swift:340:15:340:15 | t1 | test.swift:341:15:341:15 | t1 |
+| test.swift:341:15:341:15 | [post] t1 | test.swift:343:5:343:5 | t1 |
+| test.swift:341:15:341:15 | t1 | test.swift:343:5:343:5 | t1 |
+| test.swift:343:5:343:5 | [post] t1 | test.swift:345:15:345:15 | t1 |
+| test.swift:343:5:343:5 | t1 | test.swift:345:15:345:15 | t1 |
+| test.swift:345:15:345:15 | t1 | test.swift:346:15:346:15 | t1 |
+| test.swift:346:15:346:15 | [post] t1 | test.swift:347:15:347:15 | t1 |
+| test.swift:346:15:346:15 | t1 | test.swift:347:15:347:15 | t1 |
+| test.swift:351:9:351:9 | SSA def(t1) | test.swift:352:14:352:14 | t1 |
+| test.swift:351:14:351:45 | (...) | test.swift:351:9:351:9 | SSA def(t1) |
+| test.swift:352:9:352:9 | SSA def(t2) | test.swift:359:15:359:15 | t2 |
+| test.swift:352:14:352:14 | t1 | test.swift:352:9:352:9 | SSA def(t2) |
+| test.swift:352:14:352:14 | t1 | test.swift:353:21:353:21 | t1 |
+| test.swift:353:9:353:17 | SSA def(a) | test.swift:363:15:363:15 | a |
+| test.swift:353:9:353:17 | SSA def(b) | test.swift:364:15:364:15 | b |
+| test.swift:353:9:353:17 | SSA def(c) | test.swift:365:15:365:15 | c |
+| test.swift:353:21:353:21 | t1 | test.swift:353:9:353:17 | SSA def(a) |
+| test.swift:353:21:353:21 | t1 | test.swift:353:9:353:17 | SSA def(b) |
+| test.swift:353:21:353:21 | t1 | test.swift:353:9:353:17 | SSA def(c) |
+| test.swift:353:21:353:21 | t1 | test.swift:355:15:355:15 | t1 |
+| test.swift:355:15:355:15 | t1 | test.swift:356:15:356:15 | t1 |
+| test.swift:356:15:356:15 | [post] t1 | test.swift:357:15:357:15 | t1 |
+| test.swift:356:15:356:15 | t1 | test.swift:357:15:357:15 | t1 |
+| test.swift:357:15:357:15 | [post] t1 | test.swift:358:15:358:15 | t1 |
+| test.swift:357:15:357:15 | t1 | test.swift:358:15:358:15 | t1 |
+| test.swift:359:15:359:15 | t2 | test.swift:360:15:360:15 | t2 |
+| test.swift:360:15:360:15 | [post] t2 | test.swift:361:15:361:15 | t2 |
+| test.swift:360:15:360:15 | t2 | test.swift:361:15:361:15 | t2 |
+| test.swift:361:15:361:15 | [post] t2 | test.swift:362:15:362:15 | t2 |
+| test.swift:361:15:361:15 | t2 | test.swift:362:15:362:15 | t2 |
diff --git a/swift/ql/test/library-tests/dataflow/dataflow/test.swift b/swift/ql/test/library-tests/dataflow/dataflow/test.swift
index 093e8c2db95..983d918a036 100644
--- a/swift/ql/test/library-tests/dataflow/dataflow/test.swift
+++ b/swift/ql/test/library-tests/dataflow/dataflow/test.swift
@@ -295,6 +295,35 @@ func test_optionals(y: Int?) {
}
}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
func sink(arg: (Int, Int)) {}
func sink(arg: (Int, Int, Int)) {}
@@ -303,7 +332,7 @@ func testTuples() {
sink(arg: t1)
sink(arg: t1.0)
- sink(arg: t1.1) // $ flow=302
+ sink(arg: t1.1) // $ flow=331
t1.1 = 2
@@ -314,7 +343,7 @@ func testTuples() {
t1.0 = source()
sink(arg: t1)
- sink(arg: t1.0) // $ flow=314
+ sink(arg: t1.0) // $ flow=343
sink(arg: t1.1)
}
@@ -324,14 +353,14 @@ func testTuples2() {
let (a, b, c) = t1
sink(arg: t1)
- sink(arg: t1.x) // $ flow=322
- sink(arg: t1.y) // $ flow=322
+ sink(arg: t1.x) // $ flow=351
+ sink(arg: t1.y) // $ flow=351
sink(arg: t1.z)
sink(arg: t2)
- sink(arg: t2.x) // $ flow=322
- sink(arg: t2.y) // $ flow=322
+ sink(arg: t2.x) // $ flow=351
+ sink(arg: t2.y) // $ flow=351
sink(arg: t2.z)
- sink(arg: a) // $ MISSING: flow=322
- sink(arg: b) // $ MISSING: flow=322
+ sink(arg: a) // $ MISSING: flow=351
+ sink(arg: b) // $ MISSING: flow=351
sink(arg: c)
}
From d7bf2d9375801885e08c71d9235ae8e6f2805e09 Mon Sep 17 00:00:00 2001
From: Sarita Iyer <66540150+saritai@users.noreply.github.com>
Date: Fri, 6 Jan 2023 12:07:24 -0500
Subject: [PATCH 119/381] docs for codeql pack compatibility
---
docs/codeql/codeql-cli/about-codeql-packs.rst | 2 +-
docs/codeql/codeql-cli/publishing-and-using-codeql-packs.rst | 1 +
2 files changed, 2 insertions(+), 1 deletion(-)
diff --git a/docs/codeql/codeql-cli/about-codeql-packs.rst b/docs/codeql/codeql-cli/about-codeql-packs.rst
index 8cfe072f2c9..9e67dd19140 100644
--- a/docs/codeql/codeql-cli/about-codeql-packs.rst
+++ b/docs/codeql/codeql-cli/about-codeql-packs.rst
@@ -32,7 +32,7 @@ The other files and directories within the pack should be logically organized. F
their own top-level directories.
About published packs
---------------------------
+~~~~~~~~~~~~~~~~~~~~~~~~~
When a pack is published for use in analyses, the ``codeql pack create`` or ``codeql pack publish`` command verifies that the content is complete and also adds some additional pieces of content to it:
diff --git a/docs/codeql/codeql-cli/publishing-and-using-codeql-packs.rst b/docs/codeql/codeql-cli/publishing-and-using-codeql-packs.rst
index afa851e4185..b8dbc4bd6e5 100644
--- a/docs/codeql/codeql-cli/publishing-and-using-codeql-packs.rst
+++ b/docs/codeql/codeql-cli/publishing-and-using-codeql-packs.rst
@@ -106,6 +106,7 @@ As a user of a published query pack, you can check that the CodeQL makes use of
However, if they instead look like the following, then usage of the precompiled queries failed:
::
+
Compiling query plan for /long/path/to/query/Filename.ql.
[42/108 comp 25s] Compiled /long/path/to/query/Filename.ql.
From 8a9a69fa00507fe06629df16c0b5633636ce2856 Mon Sep 17 00:00:00 2001
From: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
Date: Fri, 6 Jan 2023 16:37:29 +0000
Subject: [PATCH 120/381] Swift: Add more dataflow tests for of optionals,
patterns, enums.
---
.../dataflow/dataflow/DataFlow.expected | 7 +
.../dataflow/dataflow/LocalFlow.expected | 28 +++-
.../dataflow/dataflow/test.swift | 126 ++++++++++++++----
3 files changed, 126 insertions(+), 35 deletions(-)
diff --git a/swift/ql/test/library-tests/dataflow/dataflow/DataFlow.expected b/swift/ql/test/library-tests/dataflow/dataflow/DataFlow.expected
index 6a7fd737998..4676c63d995 100644
--- a/swift/ql/test/library-tests/dataflow/dataflow/DataFlow.expected
+++ b/swift/ql/test/library-tests/dataflow/dataflow/DataFlow.expected
@@ -107,6 +107,7 @@ edges
| test.swift:263:13:263:28 | call to optionalSource() : | test.swift:275:15:275:27 | ... ??(_:_:) ... |
| test.swift:263:13:263:28 | call to optionalSource() : | test.swift:279:15:279:31 | ... ? ... : ... |
| test.swift:263:13:263:28 | call to optionalSource() : | test.swift:280:15:280:38 | ... ? ... : ... |
+| test.swift:263:13:263:28 | call to optionalSource() : | test.swift:303:15:303:16 | ...! : |
| test.swift:270:15:270:22 | call to source() : | file://:0:0:0:0 | [summary param] this in signum() : |
| test.swift:270:15:270:22 | call to source() : | test.swift:270:15:270:31 | call to signum() |
| test.swift:271:15:271:16 | ...? : | file://:0:0:0:0 | [summary param] this in signum() : |
@@ -114,6 +115,8 @@ edges
| test.swift:271:15:271:25 | call to signum() : | test.swift:271:15:271:25 | OptionalEvaluationExpr |
| test.swift:280:31:280:38 | call to source() : | test.swift:280:15:280:38 | ... ? ... : ... |
| test.swift:282:31:282:38 | call to source() : | test.swift:282:15:282:38 | ... ? ... : ... |
+| test.swift:303:15:303:16 | ...! : | file://:0:0:0:0 | [summary param] this in signum() : |
+| test.swift:303:15:303:16 | ...! : | test.swift:303:15:303:25 | call to signum() |
| test.swift:331:14:331:26 | (...) [Tuple element at index 1] : | test.swift:335:15:335:15 | t1 [Tuple element at index 1] : |
| test.swift:331:18:331:25 | call to source() : | test.swift:331:14:331:26 | (...) [Tuple element at index 1] : |
| test.swift:335:15:335:15 | t1 [Tuple element at index 1] : | test.swift:335:15:335:18 | .1 |
@@ -258,6 +261,8 @@ nodes
| test.swift:280:31:280:38 | call to source() : | semmle.label | call to source() : |
| test.swift:282:15:282:38 | ... ? ... : ... | semmle.label | ... ? ... : ... |
| test.swift:282:31:282:38 | call to source() : | semmle.label | call to source() : |
+| test.swift:303:15:303:16 | ...! : | semmle.label | ...! : |
+| test.swift:303:15:303:25 | call to signum() | semmle.label | call to signum() |
| test.swift:331:14:331:26 | (...) [Tuple element at index 1] : | semmle.label | (...) [Tuple element at index 1] : |
| test.swift:331:18:331:25 | call to source() : | semmle.label | call to source() : |
| test.swift:335:15:335:15 | t1 [Tuple element at index 1] : | semmle.label | t1 [Tuple element at index 1] : |
@@ -306,6 +311,7 @@ subpaths
| test.swift:219:13:219:15 | .a [x] : | test.swift:163:7:163:7 | self [x] : | file://:0:0:0:0 | .x : | test.swift:219:13:219:17 | .x |
| test.swift:270:15:270:22 | call to source() : | file://:0:0:0:0 | [summary param] this in signum() : | file://:0:0:0:0 | [summary] to write: return (return) in signum() : | test.swift:270:15:270:31 | call to signum() |
| test.swift:271:15:271:16 | ...? : | file://:0:0:0:0 | [summary param] this in signum() : | file://:0:0:0:0 | [summary] to write: return (return) in signum() : | test.swift:271:15:271:25 | call to signum() : |
+| test.swift:303:15:303:16 | ...! : | file://:0:0:0:0 | [summary param] this in signum() : | file://:0:0:0:0 | [summary] to write: return (return) in signum() : | test.swift:303:15:303:25 | call to signum() |
#select
| test.swift:7:15:7:15 | t1 | test.swift:6:19:6:26 | call to source() : | test.swift:7:15:7:15 | t1 | result |
| test.swift:9:15:9:15 | t1 | test.swift:6:19:6:26 | call to source() : | test.swift:9:15:9:15 | t1 | result |
@@ -345,6 +351,7 @@ subpaths
| test.swift:280:15:280:38 | ... ? ... : ... | test.swift:259:12:259:19 | call to source() : | test.swift:280:15:280:38 | ... ? ... : ... | result |
| test.swift:280:15:280:38 | ... ? ... : ... | test.swift:280:31:280:38 | call to source() : | test.swift:280:15:280:38 | ... ? ... : ... | result |
| test.swift:282:15:282:38 | ... ? ... : ... | test.swift:282:31:282:38 | call to source() : | test.swift:282:15:282:38 | ... ? ... : ... | result |
+| test.swift:303:15:303:25 | call to signum() | test.swift:259:12:259:19 | call to source() : | test.swift:303:15:303:25 | call to signum() | result |
| test.swift:335:15:335:18 | .1 | test.swift:331:18:331:25 | call to source() : | test.swift:335:15:335:18 | .1 | result |
| test.swift:346:15:346:18 | .0 | test.swift:343:12:343:19 | call to source() : | test.swift:346:15:346:18 | .0 | result |
| test.swift:356:15:356:18 | .0 | test.swift:351:18:351:25 | call to source() : | test.swift:356:15:356:18 | .0 | result |
diff --git a/swift/ql/test/library-tests/dataflow/dataflow/LocalFlow.expected b/swift/ql/test/library-tests/dataflow/dataflow/LocalFlow.expected
index b320e2cff84..49cafa7d6b6 100644
--- a/swift/ql/test/library-tests/dataflow/dataflow/LocalFlow.expected
+++ b/swift/ql/test/library-tests/dataflow/dataflow/LocalFlow.expected
@@ -241,12 +241,22 @@
| test.swift:282:26:282:26 | y | test.swift:287:16:287:16 | y |
| test.swift:282:26:282:27 | ...! | test.swift:282:15:282:38 | ... ? ... : ... |
| test.swift:282:31:282:38 | call to source() | test.swift:282:15:282:38 | ... ? ... : ... |
-| test.swift:284:16:284:16 | x | test.swift:290:16:290:16 | x |
-| test.swift:287:16:287:16 | y | test.swift:293:16:293:16 | y |
-| test.swift:290:16:290:16 | x | test.swift:290:16:290:17 | ...? |
-| test.swift:290:16:290:26 | call to signum() | test.swift:290:16:290:26 | OptionalEvaluationExpr |
-| test.swift:293:16:293:16 | y | test.swift:293:16:293:17 | ...? |
-| test.swift:293:16:293:26 | call to signum() | test.swift:293:16:293:26 | OptionalEvaluationExpr |
+| test.swift:284:16:284:16 | x | test.swift:291:16:291:16 | x |
+| test.swift:287:16:287:16 | y | test.swift:294:16:294:16 | y |
+| test.swift:291:16:291:16 | x | test.swift:291:16:291:17 | ...? |
+| test.swift:291:16:291:16 | x | test.swift:298:20:298:20 | x |
+| test.swift:291:16:291:26 | call to signum() | test.swift:291:16:291:26 | OptionalEvaluationExpr |
+| test.swift:294:16:294:16 | y | test.swift:294:16:294:17 | ...? |
+| test.swift:294:16:294:16 | y | test.swift:299:20:299:20 | y |
+| test.swift:294:16:294:26 | call to signum() | test.swift:294:16:294:26 | OptionalEvaluationExpr |
+| test.swift:298:20:298:20 | x | test.swift:303:15:303:15 | x |
+| test.swift:299:20:299:20 | y | test.swift:304:15:304:15 | y |
+| test.swift:303:15:303:15 | x | test.swift:303:15:303:16 | ...! |
+| test.swift:303:15:303:15 | x | test.swift:306:28:306:28 | x |
+| test.swift:304:15:304:15 | y | test.swift:304:15:304:16 | ...! |
+| test.swift:304:15:304:15 | y | test.swift:309:28:309:28 | y |
+| test.swift:306:28:306:28 | x | test.swift:313:12:313:12 | x |
+| test.swift:309:28:309:28 | y | test.swift:319:12:319:12 | y |
| test.swift:331:9:331:9 | SSA def(t1) | test.swift:333:15:333:15 | t1 |
| test.swift:331:14:331:26 | (...) | test.swift:331:9:331:9 | SSA def(t1) |
| test.swift:333:15:333:15 | t1 | test.swift:334:15:334:15 | t1 |
@@ -288,3 +298,9 @@
| test.swift:360:15:360:15 | t2 | test.swift:361:15:361:15 | t2 |
| test.swift:361:15:361:15 | [post] t2 | test.swift:362:15:362:15 | t2 |
| test.swift:361:15:361:15 | t2 | test.swift:362:15:362:15 | t2 |
+| test.swift:375:9:375:13 | SSA def(a) | test.swift:377:12:377:12 | a |
+| test.swift:375:22:375:23 | .myNone | test.swift:375:9:375:13 | SSA def(a) |
+| test.swift:387:9:387:13 | SSA def(b) | test.swift:389:12:389:12 | b |
+| test.swift:387:22:387:40 | call to ... | test.swift:387:9:387:13 | SSA def(b) |
+| test.swift:399:9:399:9 | SSA def(c) | test.swift:401:12:401:12 | c |
+| test.swift:399:13:399:38 | call to ... | test.swift:399:9:399:9 | SSA def(c) |
diff --git a/swift/ql/test/library-tests/dataflow/dataflow/test.swift b/swift/ql/test/library-tests/dataflow/dataflow/test.swift
index 983d918a036..6ab6bb49d0f 100644
--- a/swift/ql/test/library-tests/dataflow/dataflow/test.swift
+++ b/swift/ql/test/library-tests/dataflow/dataflow/test.swift
@@ -287,43 +287,43 @@ func test_optionals(y: Int?) {
if let z = y {
sink(arg: z)
}
+
if let z = x?.signum() { // $ MISSING: flow=259
sink(arg: z)
}
if let z = y?.signum() {
sink(arg: z)
}
+
+ guard let z1 = x else { return }
+ guard let z2 = y else { return }
+ sink(arg: z1) // $ MISSING: flow=259
+ sink(arg: z2)
+
+ sink(arg: x!.signum()) // $ flow=259
+ sink(arg: y!.signum())
+
+ if case .some(let z) = x {
+ sink(arg: z) // $ MISSING: flow=259
+ }
+ if case .some(let z) = y {
+ sink(arg: z)
+ }
+
+ switch x {
+ case .some(let z):
+ sink(arg: z) // $ MISSING: flow=259
+ case .none:
+ ()
+ }
+ switch y {
+ case .some(let z):
+ sink(arg: z)
+ case .none:
+ ()
+ }
}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
func sink(arg: (Int, Int)) {}
func sink(arg: (Int, Int, Int)) {}
@@ -364,3 +364,71 @@ func testTuples2() {
sink(arg: b) // $ MISSING: flow=351
sink(arg: c)
}
+
+enum MyEnum {
+ case myNone
+ case mySingle(Int)
+ case myPair(Int, Int)
+}
+
+func testEnums() {
+ let a : MyEnum = .myNone
+
+ switch a {
+ case .myNone:
+ ()
+ case .mySingle(let a):
+ sink(arg: a)
+ case .myPair(let a, let b):
+ sink(arg: a)
+ sink(arg: b)
+ }
+
+ if case .mySingle(let x) = a {
+ sink(arg: x)
+ }
+ if case .myPair(let x, let y) = a {
+ sink(arg: x)
+ sink(arg: y)
+ }
+
+ let b : MyEnum = .mySingle(source())
+
+ switch b {
+ case .myNone:
+ ()
+ case .mySingle(let a):
+ sink(arg: a) // $ MISSING: flow=395
+ case .myPair(let a, let b):
+ sink(arg: a)
+ sink(arg: b)
+ }
+
+ if case .mySingle(let x) = a {
+ sink(arg: x) // $ MISSING: flow=395
+ }
+ if case .myPair(let x, let y) = a {
+ sink(arg: x)
+ sink(arg: y)
+ }
+
+ let c = MyEnum.myPair(0, source())
+
+ switch c {
+ case .myNone:
+ ()
+ case .mySingle(let a):
+ sink(arg: a)
+ case .myPair(let a, let b):
+ sink(arg: a)
+ sink(arg: b) // $ MISSING: flow=415
+ }
+
+ if case .mySingle(let x) = a {
+ sink(arg: x)
+ }
+ if case .myPair(let x, let y) = a {
+ sink(arg: x)
+ sink(arg: y) // $ MISSING: flow=415
+ }
+}
From c598d9b8828aba25e6d7ba5185ce8e8e6b49ffea Mon Sep 17 00:00:00 2001
From: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
Date: Fri, 16 Dec 2022 18:16:17 +0000
Subject: [PATCH 121/381] Swift: Generalize an SSA case for variables declared
in Patterns.
---
swift/ql/lib/codeql/swift/dataflow/Ssa.qll | 11 +++++++++--
.../dataflow/dataflow/LocalFlow.expected | 19 +++++++++++++++++++
.../dataflow/taint/LocalTaint.expected | 2 ++
3 files changed, 30 insertions(+), 2 deletions(-)
diff --git a/swift/ql/lib/codeql/swift/dataflow/Ssa.qll b/swift/ql/lib/codeql/swift/dataflow/Ssa.qll
index 17ba2d63a7c..c7cfab80398 100644
--- a/swift/ql/lib/codeql/swift/dataflow/Ssa.qll
+++ b/swift/ql/lib/codeql/swift/dataflow/Ssa.qll
@@ -30,9 +30,16 @@ module Ssa {
certain = true
)
or
- exists(PatternBindingDecl decl, Pattern pattern |
+ // Any variable initialization through pattern matching. For example each `x*` in:
+ // ```
+ // var x1 = v
+ // let x2 = v
+ // let (x3, x4) = tuple
+ // if let x5 = optional { ... }
+ // guard let x6 = optional else { ... }
+ // ```
+ exists(Pattern pattern |
bb.getNode(i).getNode().asAstNode() = pattern and
- decl.getAPattern() = pattern and
v.getParentPattern() = pattern and
certain = true
)
diff --git a/swift/ql/test/library-tests/dataflow/dataflow/LocalFlow.expected b/swift/ql/test/library-tests/dataflow/dataflow/LocalFlow.expected
index 49cafa7d6b6..18c40476aad 100644
--- a/swift/ql/test/library-tests/dataflow/dataflow/LocalFlow.expected
+++ b/swift/ql/test/library-tests/dataflow/dataflow/LocalFlow.expected
@@ -241,22 +241,32 @@
| test.swift:282:26:282:26 | y | test.swift:287:16:287:16 | y |
| test.swift:282:26:282:27 | ...! | test.swift:282:15:282:38 | ... ? ... : ... |
| test.swift:282:31:282:38 | call to source() | test.swift:282:15:282:38 | ... ? ... : ... |
+| test.swift:284:8:284:12 | SSA def(z) | test.swift:285:19:285:19 | z |
| test.swift:284:16:284:16 | x | test.swift:291:16:291:16 | x |
+| test.swift:287:8:287:12 | SSA def(z) | test.swift:288:19:288:19 | z |
| test.swift:287:16:287:16 | y | test.swift:294:16:294:16 | y |
+| test.swift:291:8:291:12 | SSA def(z) | test.swift:292:19:292:19 | z |
| test.swift:291:16:291:16 | x | test.swift:291:16:291:17 | ...? |
| test.swift:291:16:291:16 | x | test.swift:298:20:298:20 | x |
| test.swift:291:16:291:26 | call to signum() | test.swift:291:16:291:26 | OptionalEvaluationExpr |
+| test.swift:294:8:294:12 | SSA def(z) | test.swift:295:19:295:19 | z |
| test.swift:294:16:294:16 | y | test.swift:294:16:294:17 | ...? |
| test.swift:294:16:294:16 | y | test.swift:299:20:299:20 | y |
| test.swift:294:16:294:26 | call to signum() | test.swift:294:16:294:26 | OptionalEvaluationExpr |
+| test.swift:298:11:298:15 | SSA def(z1) | test.swift:300:15:300:15 | z1 |
| test.swift:298:20:298:20 | x | test.swift:303:15:303:15 | x |
+| test.swift:299:11:299:15 | SSA def(z2) | test.swift:301:15:301:15 | z2 |
| test.swift:299:20:299:20 | y | test.swift:304:15:304:15 | y |
| test.swift:303:15:303:15 | x | test.swift:303:15:303:16 | ...! |
| test.swift:303:15:303:15 | x | test.swift:306:28:306:28 | x |
| test.swift:304:15:304:15 | y | test.swift:304:15:304:16 | ...! |
| test.swift:304:15:304:15 | y | test.swift:309:28:309:28 | y |
+| test.swift:306:13:306:24 | SSA def(z) | test.swift:307:19:307:19 | z |
| test.swift:306:28:306:28 | x | test.swift:313:12:313:12 | x |
+| test.swift:309:13:309:24 | SSA def(z) | test.swift:310:19:310:19 | z |
| test.swift:309:28:309:28 | y | test.swift:319:12:319:12 | y |
+| test.swift:314:10:314:21 | SSA def(z) | test.swift:315:19:315:19 | z |
+| test.swift:320:10:320:21 | SSA def(z) | test.swift:321:19:321:19 | z |
| test.swift:331:9:331:9 | SSA def(t1) | test.swift:333:15:333:15 | t1 |
| test.swift:331:14:331:26 | (...) | test.swift:331:9:331:9 | SSA def(t1) |
| test.swift:333:15:333:15 | t1 | test.swift:334:15:334:15 | t1 |
@@ -300,7 +310,16 @@
| test.swift:361:15:361:15 | t2 | test.swift:362:15:362:15 | t2 |
| test.swift:375:9:375:13 | SSA def(a) | test.swift:377:12:377:12 | a |
| test.swift:375:22:375:23 | .myNone | test.swift:375:9:375:13 | SSA def(a) |
+| test.swift:380:10:380:25 | SSA def(a) | test.swift:381:19:381:19 | a |
+| test.swift:382:10:382:30 | SSA def(a) | test.swift:383:19:383:19 | a |
+| test.swift:382:10:382:30 | SSA def(b) | test.swift:384:19:384:19 | b |
| test.swift:387:9:387:13 | SSA def(b) | test.swift:389:12:389:12 | b |
| test.swift:387:22:387:40 | call to ... | test.swift:387:9:387:13 | SSA def(b) |
+| test.swift:392:10:392:25 | SSA def(a) | test.swift:393:19:393:19 | a |
+| test.swift:394:10:394:30 | SSA def(a) | test.swift:395:19:395:19 | a |
+| test.swift:394:10:394:30 | SSA def(b) | test.swift:396:19:396:19 | b |
| test.swift:399:9:399:9 | SSA def(c) | test.swift:401:12:401:12 | c |
| test.swift:399:13:399:38 | call to ... | test.swift:399:9:399:9 | SSA def(c) |
+| test.swift:404:10:404:25 | SSA def(a) | test.swift:405:19:405:19 | a |
+| test.swift:406:10:406:30 | SSA def(a) | test.swift:407:19:407:19 | a |
+| test.swift:406:10:406:30 | SSA def(b) | test.swift:408:19:408:19 | b |
diff --git a/swift/ql/test/library-tests/dataflow/taint/LocalTaint.expected b/swift/ql/test/library-tests/dataflow/taint/LocalTaint.expected
index 032a4669c71..dc17e269435 100644
--- a/swift/ql/test/library-tests/dataflow/taint/LocalTaint.expected
+++ b/swift/ql/test/library-tests/dataflow/taint/LocalTaint.expected
@@ -1276,9 +1276,11 @@
| url.swift:102:46:102:46 | [post] urlTainted | url.swift:120:46:120:46 | urlTainted |
| url.swift:102:46:102:46 | urlTainted | url.swift:102:15:102:56 | call to URL.init(string:relativeTo:) |
| url.swift:102:46:102:46 | urlTainted | url.swift:120:46:120:46 | urlTainted |
+| url.swift:104:5:104:9 | SSA def(x) | url.swift:105:13:105:13 | x |
| url.swift:104:25:104:25 | [post] clean | url.swift:113:26:113:26 | clean |
| url.swift:104:25:104:25 | clean | url.swift:104:13:104:30 | call to URL.init(string:) |
| url.swift:104:25:104:25 | clean | url.swift:113:26:113:26 | clean |
+| url.swift:108:5:108:9 | SSA def(y) | url.swift:109:13:109:13 | y |
| url.swift:108:25:108:25 | [post] tainted | url.swift:117:28:117:28 | tainted |
| url.swift:108:25:108:25 | tainted | url.swift:108:13:108:32 | call to URL.init(string:) |
| url.swift:108:25:108:25 | tainted | url.swift:117:28:117:28 | tainted |
From b5dd8152498c18de4fe7baa542693b3c0859f768 Mon Sep 17 00:00:00 2001
From: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
Date: Fri, 16 Dec 2022 18:16:17 +0000
Subject: [PATCH 122/381] Swift: Flow through optional binding.
---
.../dataflow/internal/DataFlowPrivate.qll | 8 ++++++++
.../dataflow/dataflow/DataFlow.expected | 18 ++++++++++++++++++
.../dataflow/dataflow/LocalFlow.expected | 8 ++++++++
.../library-tests/dataflow/dataflow/test.swift | 10 +++++-----
.../dataflow/taint/LocalTaint.expected | 2 ++
.../dataflow/taint/Taint.expected | 9 +++++++++
.../library-tests/dataflow/taint/url.swift | 2 +-
7 files changed, 51 insertions(+), 6 deletions(-)
diff --git a/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPrivate.qll b/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPrivate.qll
index 9a8b64af131..22226d8dfd7 100644
--- a/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPrivate.qll
+++ b/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPrivate.qll
@@ -153,6 +153,14 @@ private module Cached {
or
nodeFrom.asExpr() = nodeTo.asExpr().(OptionalEvaluationExpr).getSubExpr()
or
+ // flow through optional binding `if let`
+ exists(ConditionElement ce, ConcreteVarDecl v |
+ ce.getInitializer() = nodeFrom.asExpr() and
+ ce.getPattern() = v.getParentPattern() and
+ //.(OptionalSomePattern).getSubPattern().(BindingPattern).getSubPattern().(NamedPattern) ?
+ nodeTo.asDefinition().getSourceVariable() = v
+ )
+ or
// flow through nil-coalescing operator `??`
exists(BinaryExpr nco |
nco.getOperator().(FreeFunctionDecl).getName() = "??(_:_:)" and
diff --git a/swift/ql/test/library-tests/dataflow/dataflow/DataFlow.expected b/swift/ql/test/library-tests/dataflow/dataflow/DataFlow.expected
index 4676c63d995..b0d6edfcf91 100644
--- a/swift/ql/test/library-tests/dataflow/dataflow/DataFlow.expected
+++ b/swift/ql/test/library-tests/dataflow/dataflow/DataFlow.expected
@@ -107,7 +107,11 @@ edges
| test.swift:263:13:263:28 | call to optionalSource() : | test.swift:275:15:275:27 | ... ??(_:_:) ... |
| test.swift:263:13:263:28 | call to optionalSource() : | test.swift:279:15:279:31 | ... ? ... : ... |
| test.swift:263:13:263:28 | call to optionalSource() : | test.swift:280:15:280:38 | ... ? ... : ... |
+| test.swift:263:13:263:28 | call to optionalSource() : | test.swift:285:19:285:19 | z |
+| test.swift:263:13:263:28 | call to optionalSource() : | test.swift:291:16:291:17 | ...? : |
+| test.swift:263:13:263:28 | call to optionalSource() : | test.swift:300:15:300:15 | z1 |
| test.swift:263:13:263:28 | call to optionalSource() : | test.swift:303:15:303:16 | ...! : |
+| test.swift:263:13:263:28 | call to optionalSource() : | test.swift:307:19:307:19 | z |
| test.swift:270:15:270:22 | call to source() : | file://:0:0:0:0 | [summary param] this in signum() : |
| test.swift:270:15:270:22 | call to source() : | test.swift:270:15:270:31 | call to signum() |
| test.swift:271:15:271:16 | ...? : | file://:0:0:0:0 | [summary param] this in signum() : |
@@ -115,6 +119,9 @@ edges
| test.swift:271:15:271:25 | call to signum() : | test.swift:271:15:271:25 | OptionalEvaluationExpr |
| test.swift:280:31:280:38 | call to source() : | test.swift:280:15:280:38 | ... ? ... : ... |
| test.swift:282:31:282:38 | call to source() : | test.swift:282:15:282:38 | ... ? ... : ... |
+| test.swift:291:16:291:17 | ...? : | file://:0:0:0:0 | [summary param] this in signum() : |
+| test.swift:291:16:291:17 | ...? : | test.swift:291:16:291:26 | call to signum() : |
+| test.swift:291:16:291:26 | call to signum() : | test.swift:292:19:292:19 | z |
| test.swift:303:15:303:16 | ...! : | file://:0:0:0:0 | [summary param] this in signum() : |
| test.swift:303:15:303:16 | ...! : | test.swift:303:15:303:25 | call to signum() |
| test.swift:331:14:331:26 | (...) [Tuple element at index 1] : | test.swift:335:15:335:15 | t1 [Tuple element at index 1] : |
@@ -261,8 +268,14 @@ nodes
| test.swift:280:31:280:38 | call to source() : | semmle.label | call to source() : |
| test.swift:282:15:282:38 | ... ? ... : ... | semmle.label | ... ? ... : ... |
| test.swift:282:31:282:38 | call to source() : | semmle.label | call to source() : |
+| test.swift:285:19:285:19 | z | semmle.label | z |
+| test.swift:291:16:291:17 | ...? : | semmle.label | ...? : |
+| test.swift:291:16:291:26 | call to signum() : | semmle.label | call to signum() : |
+| test.swift:292:19:292:19 | z | semmle.label | z |
+| test.swift:300:15:300:15 | z1 | semmle.label | z1 |
| test.swift:303:15:303:16 | ...! : | semmle.label | ...! : |
| test.swift:303:15:303:25 | call to signum() | semmle.label | call to signum() |
+| test.swift:307:19:307:19 | z | semmle.label | z |
| test.swift:331:14:331:26 | (...) [Tuple element at index 1] : | semmle.label | (...) [Tuple element at index 1] : |
| test.swift:331:18:331:25 | call to source() : | semmle.label | call to source() : |
| test.swift:335:15:335:15 | t1 [Tuple element at index 1] : | semmle.label | t1 [Tuple element at index 1] : |
@@ -311,6 +324,7 @@ subpaths
| test.swift:219:13:219:15 | .a [x] : | test.swift:163:7:163:7 | self [x] : | file://:0:0:0:0 | .x : | test.swift:219:13:219:17 | .x |
| test.swift:270:15:270:22 | call to source() : | file://:0:0:0:0 | [summary param] this in signum() : | file://:0:0:0:0 | [summary] to write: return (return) in signum() : | test.swift:270:15:270:31 | call to signum() |
| test.swift:271:15:271:16 | ...? : | file://:0:0:0:0 | [summary param] this in signum() : | file://:0:0:0:0 | [summary] to write: return (return) in signum() : | test.swift:271:15:271:25 | call to signum() : |
+| test.swift:291:16:291:17 | ...? : | file://:0:0:0:0 | [summary param] this in signum() : | file://:0:0:0:0 | [summary] to write: return (return) in signum() : | test.swift:291:16:291:26 | call to signum() : |
| test.swift:303:15:303:16 | ...! : | file://:0:0:0:0 | [summary param] this in signum() : | file://:0:0:0:0 | [summary] to write: return (return) in signum() : | test.swift:303:15:303:25 | call to signum() |
#select
| test.swift:7:15:7:15 | t1 | test.swift:6:19:6:26 | call to source() : | test.swift:7:15:7:15 | t1 | result |
@@ -351,7 +365,11 @@ subpaths
| test.swift:280:15:280:38 | ... ? ... : ... | test.swift:259:12:259:19 | call to source() : | test.swift:280:15:280:38 | ... ? ... : ... | result |
| test.swift:280:15:280:38 | ... ? ... : ... | test.swift:280:31:280:38 | call to source() : | test.swift:280:15:280:38 | ... ? ... : ... | result |
| test.swift:282:15:282:38 | ... ? ... : ... | test.swift:282:31:282:38 | call to source() : | test.swift:282:15:282:38 | ... ? ... : ... | result |
+| test.swift:285:19:285:19 | z | test.swift:259:12:259:19 | call to source() : | test.swift:285:19:285:19 | z | result |
+| test.swift:292:19:292:19 | z | test.swift:259:12:259:19 | call to source() : | test.swift:292:19:292:19 | z | result |
+| test.swift:300:15:300:15 | z1 | test.swift:259:12:259:19 | call to source() : | test.swift:300:15:300:15 | z1 | result |
| test.swift:303:15:303:25 | call to signum() | test.swift:259:12:259:19 | call to source() : | test.swift:303:15:303:25 | call to signum() | result |
+| test.swift:307:19:307:19 | z | test.swift:259:12:259:19 | call to source() : | test.swift:307:19:307:19 | z | result |
| test.swift:335:15:335:18 | .1 | test.swift:331:18:331:25 | call to source() : | test.swift:335:15:335:18 | .1 | result |
| test.swift:346:15:346:18 | .0 | test.swift:343:12:343:19 | call to source() : | test.swift:346:15:346:18 | .0 | result |
| test.swift:356:15:356:18 | .0 | test.swift:351:18:351:25 | call to source() : | test.swift:356:15:356:18 | .0 | result |
diff --git a/swift/ql/test/library-tests/dataflow/dataflow/LocalFlow.expected b/swift/ql/test/library-tests/dataflow/dataflow/LocalFlow.expected
index 18c40476aad..9f87f10d8c8 100644
--- a/swift/ql/test/library-tests/dataflow/dataflow/LocalFlow.expected
+++ b/swift/ql/test/library-tests/dataflow/dataflow/LocalFlow.expected
@@ -242,28 +242,36 @@
| test.swift:282:26:282:27 | ...! | test.swift:282:15:282:38 | ... ? ... : ... |
| test.swift:282:31:282:38 | call to source() | test.swift:282:15:282:38 | ... ? ... : ... |
| test.swift:284:8:284:12 | SSA def(z) | test.swift:285:19:285:19 | z |
+| test.swift:284:16:284:16 | x | test.swift:284:8:284:12 | SSA def(z) |
| test.swift:284:16:284:16 | x | test.swift:291:16:291:16 | x |
| test.swift:287:8:287:12 | SSA def(z) | test.swift:288:19:288:19 | z |
+| test.swift:287:16:287:16 | y | test.swift:287:8:287:12 | SSA def(z) |
| test.swift:287:16:287:16 | y | test.swift:294:16:294:16 | y |
| test.swift:291:8:291:12 | SSA def(z) | test.swift:292:19:292:19 | z |
| test.swift:291:16:291:16 | x | test.swift:291:16:291:17 | ...? |
| test.swift:291:16:291:16 | x | test.swift:298:20:298:20 | x |
+| test.swift:291:16:291:26 | OptionalEvaluationExpr | test.swift:291:8:291:12 | SSA def(z) |
| test.swift:291:16:291:26 | call to signum() | test.swift:291:16:291:26 | OptionalEvaluationExpr |
| test.swift:294:8:294:12 | SSA def(z) | test.swift:295:19:295:19 | z |
| test.swift:294:16:294:16 | y | test.swift:294:16:294:17 | ...? |
| test.swift:294:16:294:16 | y | test.swift:299:20:299:20 | y |
+| test.swift:294:16:294:26 | OptionalEvaluationExpr | test.swift:294:8:294:12 | SSA def(z) |
| test.swift:294:16:294:26 | call to signum() | test.swift:294:16:294:26 | OptionalEvaluationExpr |
| test.swift:298:11:298:15 | SSA def(z1) | test.swift:300:15:300:15 | z1 |
+| test.swift:298:20:298:20 | x | test.swift:298:11:298:15 | SSA def(z1) |
| test.swift:298:20:298:20 | x | test.swift:303:15:303:15 | x |
| test.swift:299:11:299:15 | SSA def(z2) | test.swift:301:15:301:15 | z2 |
+| test.swift:299:20:299:20 | y | test.swift:299:11:299:15 | SSA def(z2) |
| test.swift:299:20:299:20 | y | test.swift:304:15:304:15 | y |
| test.swift:303:15:303:15 | x | test.swift:303:15:303:16 | ...! |
| test.swift:303:15:303:15 | x | test.swift:306:28:306:28 | x |
| test.swift:304:15:304:15 | y | test.swift:304:15:304:16 | ...! |
| test.swift:304:15:304:15 | y | test.swift:309:28:309:28 | y |
| test.swift:306:13:306:24 | SSA def(z) | test.swift:307:19:307:19 | z |
+| test.swift:306:28:306:28 | x | test.swift:306:13:306:24 | SSA def(z) |
| test.swift:306:28:306:28 | x | test.swift:313:12:313:12 | x |
| test.swift:309:13:309:24 | SSA def(z) | test.swift:310:19:310:19 | z |
+| test.swift:309:28:309:28 | y | test.swift:309:13:309:24 | SSA def(z) |
| test.swift:309:28:309:28 | y | test.swift:319:12:319:12 | y |
| test.swift:314:10:314:21 | SSA def(z) | test.swift:315:19:315:19 | z |
| test.swift:320:10:320:21 | SSA def(z) | test.swift:321:19:321:19 | z |
diff --git a/swift/ql/test/library-tests/dataflow/dataflow/test.swift b/swift/ql/test/library-tests/dataflow/dataflow/test.swift
index 6ab6bb49d0f..f6721d3bb61 100644
--- a/swift/ql/test/library-tests/dataflow/dataflow/test.swift
+++ b/swift/ql/test/library-tests/dataflow/dataflow/test.swift
@@ -282,14 +282,14 @@ func test_optionals(y: Int?) {
sink(arg: y != nil ? y! : source()) // $ flow=282
if let z = x {
- sink(arg: z) // $ MISSING: flow=259
+ sink(arg: z) // $ flow=259
}
if let z = y {
sink(arg: z)
}
- if let z = x?.signum() { // $ MISSING: flow=259
- sink(arg: z)
+ if let z = x?.signum() {
+ sink(arg: z) // $ flow=259
}
if let z = y?.signum() {
sink(arg: z)
@@ -297,14 +297,14 @@ func test_optionals(y: Int?) {
guard let z1 = x else { return }
guard let z2 = y else { return }
- sink(arg: z1) // $ MISSING: flow=259
+ sink(arg: z1) // $ flow=259
sink(arg: z2)
sink(arg: x!.signum()) // $ flow=259
sink(arg: y!.signum())
if case .some(let z) = x {
- sink(arg: z) // $ MISSING: flow=259
+ sink(arg: z) // $ flow=259
}
if case .some(let z) = y {
sink(arg: z)
diff --git a/swift/ql/test/library-tests/dataflow/taint/LocalTaint.expected b/swift/ql/test/library-tests/dataflow/taint/LocalTaint.expected
index dc17e269435..0b2727f4da6 100644
--- a/swift/ql/test/library-tests/dataflow/taint/LocalTaint.expected
+++ b/swift/ql/test/library-tests/dataflow/taint/LocalTaint.expected
@@ -1277,10 +1277,12 @@
| url.swift:102:46:102:46 | urlTainted | url.swift:102:15:102:56 | call to URL.init(string:relativeTo:) |
| url.swift:102:46:102:46 | urlTainted | url.swift:120:46:120:46 | urlTainted |
| url.swift:104:5:104:9 | SSA def(x) | url.swift:105:13:105:13 | x |
+| url.swift:104:13:104:30 | call to URL.init(string:) | url.swift:104:5:104:9 | SSA def(x) |
| url.swift:104:25:104:25 | [post] clean | url.swift:113:26:113:26 | clean |
| url.swift:104:25:104:25 | clean | url.swift:104:13:104:30 | call to URL.init(string:) |
| url.swift:104:25:104:25 | clean | url.swift:113:26:113:26 | clean |
| url.swift:108:5:108:9 | SSA def(y) | url.swift:109:13:109:13 | y |
+| url.swift:108:13:108:32 | call to URL.init(string:) | url.swift:108:5:108:9 | SSA def(y) |
| url.swift:108:25:108:25 | [post] tainted | url.swift:117:28:117:28 | tainted |
| url.swift:108:25:108:25 | tainted | url.swift:108:13:108:32 | call to URL.init(string:) |
| url.swift:108:25:108:25 | tainted | url.swift:117:28:117:28 | tainted |
diff --git a/swift/ql/test/library-tests/dataflow/taint/Taint.expected b/swift/ql/test/library-tests/dataflow/taint/Taint.expected
index 3080ba03d15..659a3a91e68 100644
--- a/swift/ql/test/library-tests/dataflow/taint/Taint.expected
+++ b/swift/ql/test/library-tests/dataflow/taint/Taint.expected
@@ -326,6 +326,7 @@ edges
| url.swift:43:2:46:55 | [summary param] 0 in dataTask(with:completionHandler:) : | file://:0:0:0:0 | [summary] to write: argument 1.parameter 0 in dataTask(with:completionHandler:) : |
| url.swift:57:16:57:23 | call to source() : | url.swift:59:31:59:31 | tainted : |
| url.swift:57:16:57:23 | call to source() : | url.swift:83:24:83:24 | tainted : |
+| url.swift:57:16:57:23 | call to source() : | url.swift:108:25:108:25 | tainted : |
| url.swift:57:16:57:23 | call to source() : | url.swift:117:28:117:28 | tainted : |
| url.swift:59:19:59:38 | call to URL.init(string:) : | url.swift:62:12:62:12 | urlTainted |
| url.swift:59:19:59:38 | call to URL.init(string:) : | url.swift:64:12:64:23 | .absoluteURL |
@@ -419,6 +420,9 @@ edges
| url.swift:102:15:102:56 | call to URL.init(string:relativeTo:) : | url.swift:102:15:102:67 | ...! |
| url.swift:102:46:102:46 | urlTainted : | url.swift:9:2:9:43 | [summary param] 1 in URL.init(string:relativeTo:) : |
| url.swift:102:46:102:46 | urlTainted : | url.swift:102:15:102:56 | call to URL.init(string:relativeTo:) : |
+| url.swift:108:13:108:32 | call to URL.init(string:) : | url.swift:109:13:109:13 | y |
+| url.swift:108:25:108:25 | tainted : | url.swift:8:2:8:25 | [summary param] 0 in URL.init(string:) : |
+| url.swift:108:25:108:25 | tainted : | url.swift:108:13:108:32 | call to URL.init(string:) : |
| url.swift:117:16:117:35 | call to URL.init(string:) : | url.swift:118:12:118:12 | ...! |
| url.swift:117:28:117:28 | tainted : | url.swift:8:2:8:25 | [summary param] 0 in URL.init(string:) : |
| url.swift:117:28:117:28 | tainted : | url.swift:117:16:117:35 | call to URL.init(string:) : |
@@ -1061,6 +1065,9 @@ nodes
| url.swift:102:15:102:56 | call to URL.init(string:relativeTo:) : | semmle.label | call to URL.init(string:relativeTo:) : |
| url.swift:102:15:102:67 | ...! | semmle.label | ...! |
| url.swift:102:46:102:46 | urlTainted : | semmle.label | urlTainted : |
+| url.swift:108:13:108:32 | call to URL.init(string:) : | semmle.label | call to URL.init(string:) : |
+| url.swift:108:25:108:25 | tainted : | semmle.label | tainted : |
+| url.swift:109:13:109:13 | y | semmle.label | y |
| url.swift:117:16:117:35 | call to URL.init(string:) : | semmle.label | call to URL.init(string:) : |
| url.swift:117:28:117:28 | tainted : | semmle.label | tainted : |
| url.swift:118:12:118:12 | ...! | semmle.label | ...! |
@@ -1261,6 +1268,7 @@ subpaths
| url.swift:100:43:100:43 | urlTainted : | url.swift:9:2:9:43 | [summary param] 1 in URL.init(string:relativeTo:) : | file://:0:0:0:0 | [summary] to write: return (return) in URL.init(string:relativeTo:) : | url.swift:100:12:100:53 | call to URL.init(string:relativeTo:) : |
| url.swift:101:46:101:46 | urlTainted : | url.swift:9:2:9:43 | [summary param] 1 in URL.init(string:relativeTo:) : | file://:0:0:0:0 | [summary] to write: return (return) in URL.init(string:relativeTo:) : | url.swift:101:15:101:56 | call to URL.init(string:relativeTo:) : |
| url.swift:102:46:102:46 | urlTainted : | url.swift:9:2:9:43 | [summary param] 1 in URL.init(string:relativeTo:) : | file://:0:0:0:0 | [summary] to write: return (return) in URL.init(string:relativeTo:) : | url.swift:102:15:102:56 | call to URL.init(string:relativeTo:) : |
+| url.swift:108:25:108:25 | tainted : | url.swift:8:2:8:25 | [summary param] 0 in URL.init(string:) : | file://:0:0:0:0 | [summary] to write: return (return) in URL.init(string:) : | url.swift:108:13:108:32 | call to URL.init(string:) : |
| url.swift:117:28:117:28 | tainted : | url.swift:8:2:8:25 | [summary param] 0 in URL.init(string:) : | file://:0:0:0:0 | [summary] to write: return (return) in URL.init(string:) : | url.swift:117:16:117:35 | call to URL.init(string:) : |
| webview.swift:84:10:84:10 | source : | webview.swift:36:5:36:41 | [summary param] this in toObject() : | file://:0:0:0:0 | [summary] to write: return (return) in toObject() : | webview.swift:84:10:84:26 | call to toObject() |
| webview.swift:85:10:85:10 | source : | webview.swift:37:5:37:55 | [summary param] this in toObjectOf(_:) : | file://:0:0:0:0 | [summary] to write: return (return) in toObjectOf(_:) : | webview.swift:85:10:85:41 | call to toObjectOf(_:) |
@@ -1422,6 +1430,7 @@ subpaths
| url.swift:100:12:100:56 | .standardizedFileURL | url.swift:57:16:57:23 | call to source() : | url.swift:100:12:100:56 | .standardizedFileURL | result |
| url.swift:101:15:101:63 | ...! | url.swift:57:16:57:23 | call to source() : | url.swift:101:15:101:63 | ...! | result |
| url.swift:102:15:102:67 | ...! | url.swift:57:16:57:23 | call to source() : | url.swift:102:15:102:67 | ...! | result |
+| url.swift:109:13:109:13 | y | url.swift:57:16:57:23 | call to source() : | url.swift:109:13:109:13 | y | result |
| url.swift:118:12:118:12 | ...! | url.swift:57:16:57:23 | call to source() : | url.swift:118:12:118:12 | ...! | result |
| url.swift:121:15:121:19 | ...! | url.swift:57:16:57:23 | call to source() : | url.swift:121:15:121:19 | ...! | result |
| webview.swift:77:10:77:41 | .body | webview.swift:77:11:77:18 | call to source() : | webview.swift:77:10:77:41 | .body | result |
diff --git a/swift/ql/test/library-tests/dataflow/taint/url.swift b/swift/ql/test/library-tests/dataflow/taint/url.swift
index ecabb4e0cfb..aa7f00695fd 100644
--- a/swift/ql/test/library-tests/dataflow/taint/url.swift
+++ b/swift/ql/test/library-tests/dataflow/taint/url.swift
@@ -106,7 +106,7 @@ func taintThroughURL() {
}
if let y = URL(string: tainted) {
- sink(arg: y) // $ MISSING: tainted=57
+ sink(arg: y) // $ tainted=57
}
var urlClean2 : URL!
From bb50a99b369a5f29cf4f593ec03182f8fa522820 Mon Sep 17 00:00:00 2001
From: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
Date: Fri, 6 Jan 2023 18:11:32 +0000
Subject: [PATCH 123/381] Swift: Additional test cases.
---
.../dataflow/internal/DataFlowPrivate.qll | 1 -
.../dataflow/dataflow/DataFlow.expected | 5 ++
.../dataflow/dataflow/LocalFlow.expected | 59 +++++++++++++++----
.../dataflow/dataflow/test.swift | 18 ++++++
4 files changed, 72 insertions(+), 11 deletions(-)
diff --git a/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPrivate.qll b/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPrivate.qll
index 22226d8dfd7..36eda5c0055 100644
--- a/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPrivate.qll
+++ b/swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPrivate.qll
@@ -157,7 +157,6 @@ private module Cached {
exists(ConditionElement ce, ConcreteVarDecl v |
ce.getInitializer() = nodeFrom.asExpr() and
ce.getPattern() = v.getParentPattern() and
- //.(OptionalSomePattern).getSubPattern().(BindingPattern).getSubPattern().(NamedPattern) ?
nodeTo.asDefinition().getSourceVariable() = v
)
or
diff --git a/swift/ql/test/library-tests/dataflow/dataflow/DataFlow.expected b/swift/ql/test/library-tests/dataflow/dataflow/DataFlow.expected
index b0d6edfcf91..d95be652a64 100644
--- a/swift/ql/test/library-tests/dataflow/dataflow/DataFlow.expected
+++ b/swift/ql/test/library-tests/dataflow/dataflow/DataFlow.expected
@@ -100,6 +100,7 @@ edges
| test.swift:225:14:225:21 | call to source() : | test.swift:235:13:235:15 | .source_value |
| test.swift:225:14:225:21 | call to source() : | test.swift:238:13:238:15 | .source_value |
| test.swift:259:12:259:19 | call to source() : | test.swift:263:13:263:28 | call to optionalSource() : |
+| test.swift:259:12:259:19 | call to source() : | test.swift:437:13:437:28 | call to optionalSource() : |
| test.swift:263:13:263:28 | call to optionalSource() : | test.swift:265:15:265:15 | x |
| test.swift:263:13:263:28 | call to optionalSource() : | test.swift:267:15:267:16 | ...! |
| test.swift:263:13:263:28 | call to optionalSource() : | test.swift:271:15:271:16 | ...? : |
@@ -140,6 +141,7 @@ edges
| test.swift:357:15:357:15 | t1 [Tuple element at index 1] : | test.swift:357:15:357:18 | .1 |
| test.swift:360:15:360:15 | t2 [Tuple element at index 0] : | test.swift:360:15:360:18 | .0 |
| test.swift:361:15:361:15 | t2 [Tuple element at index 1] : | test.swift:361:15:361:18 | .1 |
+| test.swift:437:13:437:28 | call to optionalSource() : | test.swift:440:19:440:19 | a |
nodes
| file://:0:0:0:0 | .a [x] : | semmle.label | .a [x] : |
| file://:0:0:0:0 | .x : | semmle.label | .x : |
@@ -296,6 +298,8 @@ nodes
| test.swift:360:15:360:18 | .0 | semmle.label | .0 |
| test.swift:361:15:361:15 | t2 [Tuple element at index 1] : | semmle.label | t2 [Tuple element at index 1] : |
| test.swift:361:15:361:18 | .1 | semmle.label | .1 |
+| test.swift:437:13:437:28 | call to optionalSource() : | semmle.label | call to optionalSource() : |
+| test.swift:440:19:440:19 | a | semmle.label | a |
subpaths
| test.swift:75:21:75:22 | &... : | test.swift:65:16:65:28 | arg1 : | test.swift:65:1:70:1 | arg2[return] : | test.swift:75:31:75:32 | [post] &... : |
| test.swift:114:19:114:19 | arg : | test.swift:109:9:109:14 | arg : | test.swift:110:12:110:12 | arg : | test.swift:114:12:114:22 | call to ... : |
@@ -376,3 +380,4 @@ subpaths
| test.swift:357:15:357:18 | .1 | test.swift:351:31:351:38 | call to source() : | test.swift:357:15:357:18 | .1 | result |
| test.swift:360:15:360:18 | .0 | test.swift:351:18:351:25 | call to source() : | test.swift:360:15:360:18 | .0 | result |
| test.swift:361:15:361:18 | .1 | test.swift:351:31:351:38 | call to source() : | test.swift:361:15:361:18 | .1 | result |
+| test.swift:440:19:440:19 | a | test.swift:259:12:259:19 | call to source() : | test.swift:440:19:440:19 | a | result |
diff --git a/swift/ql/test/library-tests/dataflow/dataflow/LocalFlow.expected b/swift/ql/test/library-tests/dataflow/dataflow/LocalFlow.expected
index 9f87f10d8c8..88f69288dfb 100644
--- a/swift/ql/test/library-tests/dataflow/dataflow/LocalFlow.expected
+++ b/swift/ql/test/library-tests/dataflow/dataflow/LocalFlow.expected
@@ -318,16 +318,55 @@
| test.swift:361:15:361:15 | t2 | test.swift:362:15:362:15 | t2 |
| test.swift:375:9:375:13 | SSA def(a) | test.swift:377:12:377:12 | a |
| test.swift:375:22:375:23 | .myNone | test.swift:375:9:375:13 | SSA def(a) |
+| test.swift:377:12:377:12 | a | test.swift:387:32:387:32 | a |
| test.swift:380:10:380:25 | SSA def(a) | test.swift:381:19:381:19 | a |
| test.swift:382:10:382:30 | SSA def(a) | test.swift:383:19:383:19 | a |
| test.swift:382:10:382:30 | SSA def(b) | test.swift:384:19:384:19 | b |
-| test.swift:387:9:387:13 | SSA def(b) | test.swift:389:12:389:12 | b |
-| test.swift:387:22:387:40 | call to ... | test.swift:387:9:387:13 | SSA def(b) |
-| test.swift:392:10:392:25 | SSA def(a) | test.swift:393:19:393:19 | a |
-| test.swift:394:10:394:30 | SSA def(a) | test.swift:395:19:395:19 | a |
-| test.swift:394:10:394:30 | SSA def(b) | test.swift:396:19:396:19 | b |
-| test.swift:399:9:399:9 | SSA def(c) | test.swift:401:12:401:12 | c |
-| test.swift:399:13:399:38 | call to ... | test.swift:399:9:399:9 | SSA def(c) |
-| test.swift:404:10:404:25 | SSA def(a) | test.swift:405:19:405:19 | a |
-| test.swift:406:10:406:30 | SSA def(a) | test.swift:407:19:407:19 | a |
-| test.swift:406:10:406:30 | SSA def(b) | test.swift:408:19:408:19 | b |
+| test.swift:387:13:387:28 | SSA def(x) | test.swift:388:19:388:19 | x |
+| test.swift:387:32:387:32 | a | test.swift:387:13:387:28 | SSA def(x) |
+| test.swift:387:32:387:32 | a | test.swift:390:37:390:37 | a |
+| test.swift:390:13:390:33 | SSA def(x) | test.swift:391:19:391:19 | x |
+| test.swift:390:13:390:33 | SSA def(y) | test.swift:392:19:392:19 | y |
+| test.swift:390:37:390:37 | a | test.swift:390:13:390:33 | SSA def(x) |
+| test.swift:390:37:390:37 | a | test.swift:390:13:390:33 | SSA def(y) |
+| test.swift:390:37:390:37 | a | test.swift:407:32:407:32 | a |
+| test.swift:395:9:395:13 | SSA def(b) | test.swift:397:12:397:12 | b |
+| test.swift:395:22:395:40 | call to ... | test.swift:395:9:395:13 | SSA def(b) |
+| test.swift:400:10:400:25 | SSA def(a) | test.swift:401:19:401:19 | a |
+| test.swift:402:10:402:30 | SSA def(a) | test.swift:403:19:403:19 | a |
+| test.swift:402:10:402:30 | SSA def(b) | test.swift:404:19:404:19 | b |
+| test.swift:407:13:407:28 | SSA def(x) | test.swift:408:19:408:19 | x |
+| test.swift:407:32:407:32 | a | test.swift:407:13:407:28 | SSA def(x) |
+| test.swift:407:32:407:32 | a | test.swift:410:37:410:37 | a |
+| test.swift:410:13:410:33 | SSA def(x) | test.swift:411:19:411:19 | x |
+| test.swift:410:13:410:33 | SSA def(y) | test.swift:412:19:412:19 | y |
+| test.swift:410:37:410:37 | a | test.swift:410:13:410:33 | SSA def(x) |
+| test.swift:410:37:410:37 | a | test.swift:410:13:410:33 | SSA def(y) |
+| test.swift:410:37:410:37 | a | test.swift:427:32:427:32 | a |
+| test.swift:415:9:415:9 | SSA def(c) | test.swift:417:12:417:12 | c |
+| test.swift:415:13:415:38 | call to ... | test.swift:415:9:415:9 | SSA def(c) |
+| test.swift:420:10:420:25 | SSA def(a) | test.swift:421:19:421:19 | a |
+| test.swift:422:10:422:30 | SSA def(a) | test.swift:423:19:423:19 | a |
+| test.swift:422:10:422:30 | SSA def(b) | test.swift:424:19:424:19 | b |
+| test.swift:427:13:427:28 | SSA def(x) | test.swift:428:19:428:19 | x |
+| test.swift:427:32:427:32 | a | test.swift:427:13:427:28 | SSA def(x) |
+| test.swift:427:32:427:32 | a | test.swift:430:37:430:37 | a |
+| test.swift:430:13:430:33 | SSA def(x) | test.swift:431:19:431:19 | x |
+| test.swift:430:13:430:33 | SSA def(y) | test.swift:432:19:432:19 | y |
+| test.swift:430:37:430:37 | a | test.swift:430:13:430:33 | SSA def(x) |
+| test.swift:430:37:430:37 | a | test.swift:430:13:430:33 | SSA def(y) |
+| test.swift:436:21:436:27 | SSA def(y) | test.swift:439:27:439:27 | y |
+| test.swift:436:21:436:27 | SSA def(y) | test.swift:444:22:444:22 | y |
+| test.swift:436:21:436:27 | y | test.swift:436:21:436:27 | SSA def(y) |
+| test.swift:437:9:437:9 | SSA def(x) | test.swift:439:16:439:16 | x |
+| test.swift:437:13:437:28 | call to optionalSource() | test.swift:437:9:437:9 | SSA def(x) |
+| test.swift:439:8:439:12 | SSA def(a) | test.swift:440:19:440:19 | a |
+| test.swift:439:16:439:16 | x | test.swift:439:8:439:12 | SSA def(a) |
+| test.swift:439:16:439:16 | x | test.swift:444:19:444:19 | x |
+| test.swift:439:19:439:23 | SSA def(b) | test.swift:441:19:441:19 | b |
+| test.swift:439:27:439:27 | y | test.swift:439:19:439:23 | SSA def(b) |
+| test.swift:439:27:439:27 | y | test.swift:444:22:444:22 | y |
+| test.swift:444:9:444:9 | SSA def(tuple1) | test.swift:445:12:445:12 | tuple1 |
+| test.swift:444:18:444:23 | (...) | test.swift:444:9:444:9 | SSA def(tuple1) |
+| test.swift:446:10:446:37 | SSA def(a) | test.swift:447:19:447:19 | a |
+| test.swift:446:10:446:37 | SSA def(b) | test.swift:448:19:448:19 | b |
diff --git a/swift/ql/test/library-tests/dataflow/dataflow/test.swift b/swift/ql/test/library-tests/dataflow/dataflow/test.swift
index f6721d3bb61..7692dc05e68 100644
--- a/swift/ql/test/library-tests/dataflow/dataflow/test.swift
+++ b/swift/ql/test/library-tests/dataflow/dataflow/test.swift
@@ -432,3 +432,21 @@ func testEnums() {
sink(arg: y) // $ MISSING: flow=415
}
}
+
+func testOptionals2(y: Int?) {
+ let x = optionalSource()
+
+ if let a = x, let b = y {
+ sink(arg: a) // $ flow=259
+ sink(arg: b)
+ }
+
+ let tuple1 = (x, y)
+ switch tuple1 {
+ case (.some(let a), .some(let b)):
+ sink(arg: a) // $ MISSING: flow=259
+ sink(arg: b)
+ default:
+ ()
+ }
+}
From a3c7b2c3a2d1cbed1b7f17113a32fc0c18a2fb38 Mon Sep 17 00:00:00 2001
From: Jami Cogswell
Date: Fri, 6 Jan 2023 14:34:25 -0500
Subject: [PATCH 124/381] Java: move java.lang.Math.min to the correct file
---
java/ql/lib/ext/java.lang.model.yml | 1 +
java/ql/lib/ext/java.math.model.yml | 1 -
2 files changed, 1 insertion(+), 1 deletion(-)
diff --git a/java/ql/lib/ext/java.lang.model.yml b/java/ql/lib/ext/java.lang.model.yml
index 02699c278d1..259c5bcaf06 100644
--- a/java/ql/lib/ext/java.lang.model.yml
+++ b/java/ql/lib/ext/java.lang.model.yml
@@ -51,6 +51,7 @@ extensions:
- ["java.lang", "Long", False, "longValue", "()", "", "Argument[-1]", "ReturnValue", "taint", "manual"]
- ["java.lang", "Long", False, "parseLong", "(String)", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["java.lang", "Long", False, "toString", "()", "", "Argument[-1]", "ReturnValue", "taint", "manual"]
+ - ["java.lang", "Math", False, "min", "(int,int)", "", "Argument[0..1]", "ReturnValue", "value", "manual"]
- ["java.lang", "Object", True, "clone", "", "", "Argument[-1].Element", "ReturnValue.Element", "value", "manual"]
- ["java.lang", "Object", True, "clone", "", "", "Argument[-1].MapKey", "ReturnValue.MapKey", "value", "manual"]
- ["java.lang", "Object", True, "clone", "", "", "Argument[-1].MapValue", "ReturnValue.MapValue", "value", "manual"]
diff --git a/java/ql/lib/ext/java.math.model.yml b/java/ql/lib/ext/java.math.model.yml
index c1e23e4204a..3056e04182a 100644
--- a/java/ql/lib/ext/java.math.model.yml
+++ b/java/ql/lib/ext/java.math.model.yml
@@ -6,7 +6,6 @@ extensions:
- ["java.math", "BigDecimal", False, "BigDecimal", "(String)", "", "Argument[0]", "Argument[-1]", "taint", "manual"]
- ["java.math", "BigDecimal", False, "valueOf", "(double)", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["java.math", "BigDecimal", False, "valueOf", "(long)", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- - ["java.lang", "Math", False, "min", "(int,int)", "", "Argument[0..1]", "ReturnValue", "value", "manual"]
- addsTo:
pack: codeql/java-all
From d079c7a5efb8493956e2570264513344ead10d04 Mon Sep 17 00:00:00 2001
From: Sarita Iyer <66540150+saritai@users.noreply.github.com>
Date: Fri, 6 Jan 2023 14:57:24 -0500
Subject: [PATCH 125/381] Apply suggestions from code review
Co-authored-by: Felicity Chapman
---
docs/codeql/CONTRIBUTING.MD | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/docs/codeql/CONTRIBUTING.MD b/docs/codeql/CONTRIBUTING.MD
index 0c1fe8f9532..052d816787c 100644
--- a/docs/codeql/CONTRIBUTING.MD
+++ b/docs/codeql/CONTRIBUTING.MD
@@ -2,14 +2,17 @@
We welcome contributions to our CodeQL docs. Want to improve existing docs or add new information you think would be helpful? Then please go ahead and open a pull request!
-## Contributing to CodeQL docs on `docs.github.com`
+## Contributing to CodeQL CLI docs on `docs.github.com`
-**Note**: We have recently copied the CodeQL CLI documentation on [codeql.github.com](https://codeql.github.com/docs/codeql-cli/) to the public [github/docs](https://github.com/github/docs) repository so that this documentation will appear on the [GitHub Docs](https://docs.github.com/en/code-security/code-scanning) site. This includes all articles under "[Using the CodeQL CLI](https://codeql.github.com/docs/codeql-cli/using-the-codeql-cli/)" and "[CodeQL CLI reference](https://codeql.github.com/docs/codeql-cli/codeql-cli-reference/)" categories.
+
+We are in the process of moving all documentation about the CodeQL CLI from [codeql.github.com](https://codeql.github.com/docs/codeql-cli/) to the public [github/docs](https://github.com/github/docs) repository so that this documentation is published on the [GitHub Docs](https://docs.github.com/en/code-security/code-scanning) site. This includes all articles under "[Using the CodeQL CLI](https://codeql.github.com/docs/codeql-cli/using-the-codeql-cli/)" and "[CodeQL CLI reference](https://codeql.github.com/docs/codeql-cli/codeql-cli-reference/)" categories. This will make it easier for code scanning users to find information about using CodeQL to query their codebases.
+
+**Note**: For a brief time, we will have source files for CodeQL CLI documentation in two locations. During this period we will not accept changes to the old files in the `codeql` repository, only to the new files in the `docs` repository.
To contribute to these docs, which are located in the [`code-scanning`](https://github.com/github/docs/tree/main/content/code-security/code-scanning) directory, please refer to the [CONTRIBUTING.md](https://github.com/github/docs/blob/main/CONTRIBUTING.md) file in the `docs` repository.
## Contributing to CodeQL docs on `codeql.github.com`
-To make changes to the remaining documentation on [codeql.github.com](https://codeql.github.com/docs/codeql-cli/), you can make changes to the documentation files using the GitHub UI, a codespace, or making changes locally, and then open a pull request for review. For more information about the format and structure of the CodeQL documentation on [codeql.github.com](https://codeql.github.com/docs/codeql-cli/), please see the [README](https://github.com/github/codeql/tree/main/docs/codeql#readme).
+To make changes to the documentation on [codeql.github.com](https://codeql.github.com/docs/codeql-overview/), you can make changes to the documentation files using the GitHub UI, a codespace, or a local text editor, and then open a pull request for review. For more information about the format and structure of the CodeQL documentation on [codeql.github.com](https://codeql.github.com/docs/codeql-overview/), please see the [README](https://github.com/github/codeql/blob/main/docs/codeql/README.rst).
From f15291a9deff443874a5ab4c851d722fdcd0ea74 Mon Sep 17 00:00:00 2001
From: Sarita Iyer <66540150+saritai@users.noreply.github.com>
Date: Fri, 6 Jan 2023 15:00:43 -0500
Subject: [PATCH 126/381] Change the order of sections
---
docs/codeql/CONTRIBUTING.MD | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/docs/codeql/CONTRIBUTING.MD b/docs/codeql/CONTRIBUTING.MD
index 052d816787c..478c2d28ac5 100644
--- a/docs/codeql/CONTRIBUTING.MD
+++ b/docs/codeql/CONTRIBUTING.MD
@@ -2,8 +2,11 @@
We welcome contributions to our CodeQL docs. Want to improve existing docs or add new information you think would be helpful? Then please go ahead and open a pull request!
-## Contributing to CodeQL CLI docs on `docs.github.com`
+## Contributing to CodeQL docs on `codeql.github.com`
+To make changes to the documentation on [codeql.github.com](https://codeql.github.com/docs/codeql-overview/), you can make changes to the documentation files using the GitHub UI, a codespace, or a local text editor, and then open a pull request for review. For more information about the format and structure of the CodeQL documentation on [codeql.github.com](https://codeql.github.com/docs/codeql-overview/), please see the [README](https://github.com/github/codeql/blob/main/docs/codeql/README.rst).
+
+## Contributing to CodeQL CLI docs on `docs.github.com`
We are in the process of moving all documentation about the CodeQL CLI from [codeql.github.com](https://codeql.github.com/docs/codeql-cli/) to the public [github/docs](https://github.com/github/docs) repository so that this documentation is published on the [GitHub Docs](https://docs.github.com/en/code-security/code-scanning) site. This includes all articles under "[Using the CodeQL CLI](https://codeql.github.com/docs/codeql-cli/using-the-codeql-cli/)" and "[CodeQL CLI reference](https://codeql.github.com/docs/codeql-cli/codeql-cli-reference/)" categories. This will make it easier for code scanning users to find information about using CodeQL to query their codebases.
@@ -11,8 +14,5 @@ We are in the process of moving all documentation about the CodeQL CLI from [cod
To contribute to these docs, which are located in the [`code-scanning`](https://github.com/github/docs/tree/main/content/code-security/code-scanning) directory, please refer to the [CONTRIBUTING.md](https://github.com/github/docs/blob/main/CONTRIBUTING.md) file in the `docs` repository.
-## Contributing to CodeQL docs on `codeql.github.com`
-
-To make changes to the documentation on [codeql.github.com](https://codeql.github.com/docs/codeql-overview/), you can make changes to the documentation files using the GitHub UI, a codespace, or a local text editor, and then open a pull request for review. For more information about the format and structure of the CodeQL documentation on [codeql.github.com](https://codeql.github.com/docs/codeql-overview/), please see the [README](https://github.com/github/codeql/blob/main/docs/codeql/README.rst).
From 6bb09ef289e39b0da3a9df35c80488c34f42f65a Mon Sep 17 00:00:00 2001
From: Mathias Vorreiter Pedersen
Date: Mon, 9 Jan 2023 09:43:09 +0000
Subject: [PATCH 127/381] Swift: Add integral type classes.
---
.../swift/elements/type/FloatingPointType.qll | 12 +++++++
.../swift/elements/type/NumericOrCharType.qll | 35 +++++++++++++++++++
swift/ql/lib/swift.qll | 1 +
3 files changed, 48 insertions(+)
create mode 100644 swift/ql/lib/codeql/swift/elements/type/FloatingPointType.qll
create mode 100644 swift/ql/lib/codeql/swift/elements/type/NumericOrCharType.qll
diff --git a/swift/ql/lib/codeql/swift/elements/type/FloatingPointType.qll b/swift/ql/lib/codeql/swift/elements/type/FloatingPointType.qll
new file mode 100644
index 00000000000..e5ae0ac3e7a
--- /dev/null
+++ b/swift/ql/lib/codeql/swift/elements/type/FloatingPointType.qll
@@ -0,0 +1,12 @@
+private import swift
+
+/**
+ * A floating-point type. This includes the `Float` type, the `Double`, and
+ * builtin floating-point types.
+ */
+class FloatingPointType extends Type {
+ FloatingPointType() {
+ this.getName() = ["Float", "Double"] or
+ this instanceof BuiltinFloatType
+ }
+}
diff --git a/swift/ql/lib/codeql/swift/elements/type/NumericOrCharType.qll b/swift/ql/lib/codeql/swift/elements/type/NumericOrCharType.qll
new file mode 100644
index 00000000000..9718ebe764b
--- /dev/null
+++ b/swift/ql/lib/codeql/swift/elements/type/NumericOrCharType.qll
@@ -0,0 +1,35 @@
+private import swift
+
+/** The `Character` type. */
+class CharacterType extends StructType {
+ CharacterType() { this.getName() = "Character" }
+}
+
+/**
+ * An integer-like type. For example, `Int`, `Int16`, `Uint16`, etc.
+ */
+class IntegerType extends Type {
+ IntegerType() {
+ this.getName() =
+ ["Int", "Int8", "Int16", "Int32", "Int64", "UInt", "UInt8", "Uint16", "Uint32", "UInt64"]
+ or
+ this instanceof BuiltinIntegerType
+ }
+}
+
+/** The `Bool` type. */
+class BooleanType extends Type {
+ BooleanType() { this.getName() = "Bool" }
+}
+
+/**
+ * A numeric-like type. This includes the types `Character`, `Bool`, and all
+ * the integer-like types.
+ */
+class NumericOrCharType extends Type {
+ NumericOrCharType() {
+ this instanceof CharacterType or
+ this instanceof IntegerType or
+ this instanceof BooleanType
+ }
+}
diff --git a/swift/ql/lib/swift.qll b/swift/ql/lib/swift.qll
index b72ce008427..4d79e4b73eb 100644
--- a/swift/ql/lib/swift.qll
+++ b/swift/ql/lib/swift.qll
@@ -10,4 +10,5 @@ import codeql.swift.elements.expr.InitializerCallExpr
import codeql.swift.elements.expr.SelfRefExpr
import codeql.swift.elements.decl.MethodDecl
import codeql.swift.elements.decl.ClassOrStructDecl
+import codeql.swift.elements.type.NumericOrCharType
import codeql.swift.Unit
From 9333e80def52d290f9d5231b763db23e90388165 Mon Sep 17 00:00:00 2001
From: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
Date: Mon, 9 Jan 2023 10:29:37 +0000
Subject: [PATCH 128/381] Swift: Add getVaList stub to the test.
---
.../CWE-134/UncontrolledFormatString.expected | 52 +++++++++----------
.../CWE-134/UncontrolledFormatString.swift | 2 +
2 files changed, 28 insertions(+), 26 deletions(-)
diff --git a/swift/ql/test/query-tests/Security/CWE-134/UncontrolledFormatString.expected b/swift/ql/test/query-tests/Security/CWE-134/UncontrolledFormatString.expected
index 4895b075e6f..8bb76e27b44 100644
--- a/swift/ql/test/query-tests/Security/CWE-134/UncontrolledFormatString.expected
+++ b/swift/ql/test/query-tests/Security/CWE-134/UncontrolledFormatString.expected
@@ -1,32 +1,32 @@
edges
-| UncontrolledFormatString.swift:62:24:62:77 | call to String.init(contentsOf:) : | UncontrolledFormatString.swift:68:28:68:28 | tainted |
-| UncontrolledFormatString.swift:62:24:62:77 | call to String.init(contentsOf:) : | UncontrolledFormatString.swift:71:28:71:28 | tainted |
-| UncontrolledFormatString.swift:62:24:62:77 | call to String.init(contentsOf:) : | UncontrolledFormatString.swift:72:28:72:28 | tainted |
-| UncontrolledFormatString.swift:62:24:62:77 | call to String.init(contentsOf:) : | UncontrolledFormatString.swift:74:28:74:28 | tainted |
-| UncontrolledFormatString.swift:62:24:62:77 | call to String.init(contentsOf:) : | UncontrolledFormatString.swift:75:28:75:28 | tainted |
-| UncontrolledFormatString.swift:62:24:62:77 | call to String.init(contentsOf:) : | UncontrolledFormatString.swift:76:28:76:28 | tainted |
-| UncontrolledFormatString.swift:62:24:62:77 | call to String.init(contentsOf:) : | UncontrolledFormatString.swift:77:46:77:46 | tainted |
-| UncontrolledFormatString.swift:62:24:62:77 | call to String.init(contentsOf:) : | UncontrolledFormatString.swift:86:11:86:11 | tainted |
-| UncontrolledFormatString.swift:62:24:62:77 | call to String.init(contentsOf:) : | UncontrolledFormatString.swift:89:61:89:61 | tainted |
+| UncontrolledFormatString.swift:64:24:64:77 | call to String.init(contentsOf:) : | UncontrolledFormatString.swift:70:28:70:28 | tainted |
+| UncontrolledFormatString.swift:64:24:64:77 | call to String.init(contentsOf:) : | UncontrolledFormatString.swift:73:28:73:28 | tainted |
+| UncontrolledFormatString.swift:64:24:64:77 | call to String.init(contentsOf:) : | UncontrolledFormatString.swift:74:28:74:28 | tainted |
+| UncontrolledFormatString.swift:64:24:64:77 | call to String.init(contentsOf:) : | UncontrolledFormatString.swift:76:28:76:28 | tainted |
+| UncontrolledFormatString.swift:64:24:64:77 | call to String.init(contentsOf:) : | UncontrolledFormatString.swift:77:28:77:28 | tainted |
+| UncontrolledFormatString.swift:64:24:64:77 | call to String.init(contentsOf:) : | UncontrolledFormatString.swift:78:28:78:28 | tainted |
+| UncontrolledFormatString.swift:64:24:64:77 | call to String.init(contentsOf:) : | UncontrolledFormatString.swift:79:46:79:46 | tainted |
+| UncontrolledFormatString.swift:64:24:64:77 | call to String.init(contentsOf:) : | UncontrolledFormatString.swift:88:11:88:11 | tainted |
+| UncontrolledFormatString.swift:64:24:64:77 | call to String.init(contentsOf:) : | UncontrolledFormatString.swift:91:61:91:61 | tainted |
nodes
-| UncontrolledFormatString.swift:62:24:62:77 | call to String.init(contentsOf:) : | semmle.label | call to String.init(contentsOf:) : |
-| UncontrolledFormatString.swift:68:28:68:28 | tainted | semmle.label | tainted |
-| UncontrolledFormatString.swift:71:28:71:28 | tainted | semmle.label | tainted |
-| UncontrolledFormatString.swift:72:28:72:28 | tainted | semmle.label | tainted |
+| UncontrolledFormatString.swift:64:24:64:77 | call to String.init(contentsOf:) : | semmle.label | call to String.init(contentsOf:) : |
+| UncontrolledFormatString.swift:70:28:70:28 | tainted | semmle.label | tainted |
+| UncontrolledFormatString.swift:73:28:73:28 | tainted | semmle.label | tainted |
| UncontrolledFormatString.swift:74:28:74:28 | tainted | semmle.label | tainted |
-| UncontrolledFormatString.swift:75:28:75:28 | tainted | semmle.label | tainted |
| UncontrolledFormatString.swift:76:28:76:28 | tainted | semmle.label | tainted |
-| UncontrolledFormatString.swift:77:46:77:46 | tainted | semmle.label | tainted |
-| UncontrolledFormatString.swift:86:11:86:11 | tainted | semmle.label | tainted |
-| UncontrolledFormatString.swift:89:61:89:61 | tainted | semmle.label | tainted |
+| UncontrolledFormatString.swift:77:28:77:28 | tainted | semmle.label | tainted |
+| UncontrolledFormatString.swift:78:28:78:28 | tainted | semmle.label | tainted |
+| UncontrolledFormatString.swift:79:46:79:46 | tainted | semmle.label | tainted |
+| UncontrolledFormatString.swift:88:11:88:11 | tainted | semmle.label | tainted |
+| UncontrolledFormatString.swift:91:61:91:61 | tainted | semmle.label | tainted |
subpaths
#select
-| UncontrolledFormatString.swift:68:28:68:28 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to String.init(contentsOf:) : | UncontrolledFormatString.swift:68:28:68:28 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:62:24:62:77 | call to String.init(contentsOf:) | this user-provided value |
-| UncontrolledFormatString.swift:71:28:71:28 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to String.init(contentsOf:) : | UncontrolledFormatString.swift:71:28:71:28 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:62:24:62:77 | call to String.init(contentsOf:) | this user-provided value |
-| UncontrolledFormatString.swift:72:28:72:28 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to String.init(contentsOf:) : | UncontrolledFormatString.swift:72:28:72:28 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:62:24:62:77 | call to String.init(contentsOf:) | this user-provided value |
-| UncontrolledFormatString.swift:74:28:74:28 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to String.init(contentsOf:) : | UncontrolledFormatString.swift:74:28:74:28 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:62:24:62:77 | call to String.init(contentsOf:) | this user-provided value |
-| UncontrolledFormatString.swift:75:28:75:28 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to String.init(contentsOf:) : | UncontrolledFormatString.swift:75:28:75:28 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:62:24:62:77 | call to String.init(contentsOf:) | this user-provided value |
-| UncontrolledFormatString.swift:76:28:76:28 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to String.init(contentsOf:) : | UncontrolledFormatString.swift:76:28:76:28 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:62:24:62:77 | call to String.init(contentsOf:) | this user-provided value |
-| UncontrolledFormatString.swift:77:46:77:46 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to String.init(contentsOf:) : | UncontrolledFormatString.swift:77:46:77:46 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:62:24:62:77 | call to String.init(contentsOf:) | this user-provided value |
-| UncontrolledFormatString.swift:86:11:86:11 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to String.init(contentsOf:) : | UncontrolledFormatString.swift:86:11:86:11 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:62:24:62:77 | call to String.init(contentsOf:) | this user-provided value |
-| UncontrolledFormatString.swift:89:61:89:61 | tainted | UncontrolledFormatString.swift:62:24:62:77 | call to String.init(contentsOf:) : | UncontrolledFormatString.swift:89:61:89:61 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:62:24:62:77 | call to String.init(contentsOf:) | this user-provided value |
+| UncontrolledFormatString.swift:70:28:70:28 | tainted | UncontrolledFormatString.swift:64:24:64:77 | call to String.init(contentsOf:) : | UncontrolledFormatString.swift:70:28:70:28 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:64:24:64:77 | call to String.init(contentsOf:) | this user-provided value |
+| UncontrolledFormatString.swift:73:28:73:28 | tainted | UncontrolledFormatString.swift:64:24:64:77 | call to String.init(contentsOf:) : | UncontrolledFormatString.swift:73:28:73:28 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:64:24:64:77 | call to String.init(contentsOf:) | this user-provided value |
+| UncontrolledFormatString.swift:74:28:74:28 | tainted | UncontrolledFormatString.swift:64:24:64:77 | call to String.init(contentsOf:) : | UncontrolledFormatString.swift:74:28:74:28 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:64:24:64:77 | call to String.init(contentsOf:) | this user-provided value |
+| UncontrolledFormatString.swift:76:28:76:28 | tainted | UncontrolledFormatString.swift:64:24:64:77 | call to String.init(contentsOf:) : | UncontrolledFormatString.swift:76:28:76:28 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:64:24:64:77 | call to String.init(contentsOf:) | this user-provided value |
+| UncontrolledFormatString.swift:77:28:77:28 | tainted | UncontrolledFormatString.swift:64:24:64:77 | call to String.init(contentsOf:) : | UncontrolledFormatString.swift:77:28:77:28 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:64:24:64:77 | call to String.init(contentsOf:) | this user-provided value |
+| UncontrolledFormatString.swift:78:28:78:28 | tainted | UncontrolledFormatString.swift:64:24:64:77 | call to String.init(contentsOf:) : | UncontrolledFormatString.swift:78:28:78:28 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:64:24:64:77 | call to String.init(contentsOf:) | this user-provided value |
+| UncontrolledFormatString.swift:79:46:79:46 | tainted | UncontrolledFormatString.swift:64:24:64:77 | call to String.init(contentsOf:) : | UncontrolledFormatString.swift:79:46:79:46 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:64:24:64:77 | call to String.init(contentsOf:) | this user-provided value |
+| UncontrolledFormatString.swift:88:11:88:11 | tainted | UncontrolledFormatString.swift:64:24:64:77 | call to String.init(contentsOf:) : | UncontrolledFormatString.swift:88:11:88:11 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:64:24:64:77 | call to String.init(contentsOf:) | this user-provided value |
+| UncontrolledFormatString.swift:91:61:91:61 | tainted | UncontrolledFormatString.swift:64:24:64:77 | call to String.init(contentsOf:) : | UncontrolledFormatString.swift:91:61:91:61 | tainted | This format string depends on $@. | UncontrolledFormatString.swift:64:24:64:77 | call to String.init(contentsOf:) | this user-provided value |
diff --git a/swift/ql/test/query-tests/Security/CWE-134/UncontrolledFormatString.swift b/swift/ql/test/query-tests/Security/CWE-134/UncontrolledFormatString.swift
index e6d1d8a2646..ff675f1249e 100644
--- a/swift/ql/test/query-tests/Security/CWE-134/UncontrolledFormatString.swift
+++ b/swift/ql/test/query-tests/Security/CWE-134/UncontrolledFormatString.swift
@@ -50,6 +50,8 @@ func NSLog(_ format: String, _ args: CVarArg...) {}
func NSLogv(_ format: String, _ args: CVaListPointer) {}
+func getVaList(_ args: [CVarArg]) -> CVaListPointer { return (nil as CVaListPointer?)! }
+
// --- tests ---
func MyLog(_ format: String, _ args: CVarArg...) {
From 381301e552933662b10ebf0632aa56abcdd28ae7 Mon Sep 17 00:00:00 2001
From: Mathias Vorreiter Pedersen
Date: Mon, 9 Jan 2023 10:32:52 +0000
Subject: [PATCH 129/381] Update swift/ql/lib/swift.qll
Co-authored-by: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
---
swift/ql/lib/swift.qll | 1 +
1 file changed, 1 insertion(+)
diff --git a/swift/ql/lib/swift.qll b/swift/ql/lib/swift.qll
index 4d79e4b73eb..552f2c99828 100644
--- a/swift/ql/lib/swift.qll
+++ b/swift/ql/lib/swift.qll
@@ -10,5 +10,6 @@ import codeql.swift.elements.expr.InitializerCallExpr
import codeql.swift.elements.expr.SelfRefExpr
import codeql.swift.elements.decl.MethodDecl
import codeql.swift.elements.decl.ClassOrStructDecl
+import codeql.swift.elements.type.FloatingPointType
import codeql.swift.elements.type.NumericOrCharType
import codeql.swift.Unit
From 2ec73c50f999ff01ba01a0e2e659b544e0e71918 Mon Sep 17 00:00:00 2001
From: Ed Minnix
Date: Mon, 9 Jan 2023 09:55:09 -0500
Subject: [PATCH 130/381] Mention WebView in alert message
---
.../CWE/CWE-200/AndroidWebViewSettingsPermitsContentAccess.ql | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/java/ql/src/Security/CWE/CWE-200/AndroidWebViewSettingsPermitsContentAccess.ql b/java/ql/src/Security/CWE/CWE-200/AndroidWebViewSettingsPermitsContentAccess.ql
index 7ccf23cc3ae..52c81dc1069 100644
--- a/java/ql/src/Security/CWE/CWE-200/AndroidWebViewSettingsPermitsContentAccess.ql
+++ b/java/ql/src/Security/CWE/CWE-200/AndroidWebViewSettingsPermitsContentAccess.ql
@@ -109,4 +109,4 @@ where
not any(WebViewDisallowContentAccessConfiguration cfg).hasFlow(source, _)
)
select e,
- "Sensitive information may be exposed via a malicious link due to access of content:// links being permitted."
+ "Sensitive information may be exposed via a malicious link due to access to content:// links being allowed in this WebView."
From 64668883a466e2e16127bb01a250df9e9e705bd0 Mon Sep 17 00:00:00 2001
From: Ed Minnix
Date: Mon, 9 Jan 2023 09:59:38 -0500
Subject: [PATCH 131/381] Add good example to documentation
---
.../CWE-200/AndroidWebViewSettingsPermitsContentAccess.qhelp | 3 +++
java/ql/src/Security/CWE/CWE-200/ContentAccessDisabled.java | 3 +++
2 files changed, 6 insertions(+)
create mode 100644 java/ql/src/Security/CWE/CWE-200/ContentAccessDisabled.java
diff --git a/java/ql/src/Security/CWE/CWE-200/AndroidWebViewSettingsPermitsContentAccess.qhelp b/java/ql/src/Security/CWE/CWE-200/AndroidWebViewSettingsPermitsContentAccess.qhelp
index 6f4dbb3505a..13439bf585d 100644
--- a/java/ql/src/Security/CWE/CWE-200/AndroidWebViewSettingsPermitsContentAccess.qhelp
+++ b/java/ql/src/Security/CWE/CWE-200/AndroidWebViewSettingsPermitsContentAccess.qhelp
@@ -24,6 +24,9 @@
+
In the following (good) example, access to content:// URLs is explicitly denied.
+
+
diff --git a/java/ql/src/Security/CWE/CWE-200/ContentAccessDisabled.java b/java/ql/src/Security/CWE/CWE-200/ContentAccessDisabled.java
new file mode 100644
index 00000000000..25214a69afe
--- /dev/null
+++ b/java/ql/src/Security/CWE/CWE-200/ContentAccessDisabled.java
@@ -0,0 +1,3 @@
+WebSettings settings = webview.getSettings();
+
+settings.setAllowContentAccess(false);
From 972b4629c83c26c30873920592b300b26ad47808 Mon Sep 17 00:00:00 2001
From: Ed Minnix
Date: Mon, 9 Jan 2023 10:01:38 -0500
Subject: [PATCH 132/381] Fix typo in change note
---
java/ql/lib/change-notes/2022-12-21-allowcontentaccessmethod.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/java/ql/lib/change-notes/2022-12-21-allowcontentaccessmethod.md b/java/ql/lib/change-notes/2022-12-21-allowcontentaccessmethod.md
index 1f67c159788..292bc418459 100644
--- a/java/ql/lib/change-notes/2022-12-21-allowcontentaccessmethod.md
+++ b/java/ql/lib/change-notes/2022-12-21-allowcontentaccessmethod.md
@@ -1,4 +1,4 @@
---
category: minorAnalysis
---
-* Added `AllowContentAccessMethod` to represent the `allowContentAccess` method of the `android.webkit.WebSettings` class.
+* Added `AllowContentAccessMethod` to represent the `setAllowContentAccess` method of the `android.webkit.WebSettings` class.
From f626d4794ad1ebb5ff0e3150cef924b9a2073733 Mon Sep 17 00:00:00 2001
From: Ed Minnix
Date: Mon, 9 Jan 2023 10:03:12 -0500
Subject: [PATCH 133/381] Change wording from "permit" to "allow" in id and
name
---
.../CWE-200/AndroidWebViewSettingsPermitsContentAccess.ql | 6 +++---
.../2022-12-21-android-allowcontentaccess-query.md | 2 +-
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/java/ql/src/Security/CWE/CWE-200/AndroidWebViewSettingsPermitsContentAccess.ql b/java/ql/src/Security/CWE/CWE-200/AndroidWebViewSettingsPermitsContentAccess.ql
index 52c81dc1069..d1f4f33917a 100644
--- a/java/ql/src/Security/CWE/CWE-200/AndroidWebViewSettingsPermitsContentAccess.ql
+++ b/java/ql/src/Security/CWE/CWE-200/AndroidWebViewSettingsPermitsContentAccess.ql
@@ -1,7 +1,7 @@
/**
- * @name Android WebView settings permits content access
- * @id java/android/websettings-permit-contentacces
- * @description Access to content providers in a WebView can permit access to protected information by loading content:// links.
+ * @name Android WebView settings allows access to content links
+ * @id java/android/websettings-allow-content-access
+ * @description Access to content providers in a WebView can allow access to protected information by loading content:// links.
* @kind problem
* @problem.severity warning
* @precision medium
diff --git a/java/ql/src/change-notes/2022-12-21-android-allowcontentaccess-query.md b/java/ql/src/change-notes/2022-12-21-android-allowcontentaccess-query.md
index 854da87eb54..ebd6a7b5dd5 100644
--- a/java/ql/src/change-notes/2022-12-21-android-allowcontentaccess-query.md
+++ b/java/ql/src/change-notes/2022-12-21-android-allowcontentaccess-query.md
@@ -1,4 +1,4 @@
---
category: newQuery
---
-* Added a new query `java/android/websettings-permit-contentacces` to detect Android WebViews which do not disable access to `content://` urls.
+* Added a new query `java/android/websettings-allow-content-access` to detect Android WebViews which do not disable access to `content://` urls.
From c723df3ca744ab756526f06471f5e75e45f7ba7d Mon Sep 17 00:00:00 2001
From: Ed Minnix
Date: Mon, 9 Jan 2023 10:08:19 -0500
Subject: [PATCH 134/381] Fix alert message in expected file
---
.../tests/WebViewContentAccess.expected | 20 +++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/java/ql/test/query-tests/security/CWE-200/semmle/tests/WebViewContentAccess.expected b/java/ql/test/query-tests/security/CWE-200/semmle/tests/WebViewContentAccess.expected
index 317f847279f..8116323de32 100644
--- a/java/ql/test/query-tests/security/CWE-200/semmle/tests/WebViewContentAccess.expected
+++ b/java/ql/test/query-tests/security/CWE-200/semmle/tests/WebViewContentAccess.expected
@@ -1,10 +1,10 @@
-| WebViewContentAccess.java:15:9:15:57 | setAllowContentAccess(...) | Sensitive information may be exposed via a malicious link due to access of content:// links being permitted. |
-| WebViewContentAccess.java:38:9:38:55 | setAllowContentAccess(...) | Sensitive information may be exposed via a malicious link due to access of content:// links being permitted. |
-| WebViewContentAccess.java:41:25:41:49 | (...)... | Sensitive information may be exposed via a malicious link due to access of content:// links being permitted. |
-| WebViewContentAccess.java:43:9:43:44 | setAllowContentAccess(...) | Sensitive information may be exposed via a malicious link due to access of content:// links being permitted. |
-| WebViewContentAccess.java:46:25:46:41 | new WebView(...) | Sensitive information may be exposed via a malicious link due to access of content:// links being permitted. |
-| WebViewContentAccess.java:48:9:48:44 | setAllowContentAccess(...) | Sensitive information may be exposed via a malicious link due to access of content:// links being permitted. |
-| WebViewContentAccess.java:51:25:51:44 | getAWebView(...) | Sensitive information may be exposed via a malicious link due to access of content:// links being permitted. |
-| WebViewContentAccess.java:53:9:53:44 | setAllowContentAccess(...) | Sensitive information may be exposed via a malicious link due to access of content:// links being permitted. |
-| WebViewContentAccess.java:55:29:55:48 | getAWebView(...) | Sensitive information may be exposed via a malicious link due to access of content:// links being permitted. |
-| WebViewContentAccess.java:57:25:57:44 | getAWebView(...) | Sensitive information may be exposed via a malicious link due to access of content:// links being permitted. |
+| WebViewContentAccess.java:15:9:15:57 | setAllowContentAccess(...) | Sensitive information may be exposed via a malicious link due to access to content:// links being allowed in this WebView. |
+| WebViewContentAccess.java:38:9:38:55 | setAllowContentAccess(...) | Sensitive information may be exposed via a malicious link due to access to content:// links being allowed in this WebView. |
+| WebViewContentAccess.java:41:25:41:49 | (...)... | Sensitive information may be exposed via a malicious link due to access to content:// links being allowed in this WebView. |
+| WebViewContentAccess.java:43:9:43:44 | setAllowContentAccess(...) | Sensitive information may be exposed via a malicious link due to access to content:// links being allowed in this WebView. |
+| WebViewContentAccess.java:46:25:46:41 | new WebView(...) | Sensitive information may be exposed via a malicious link due to access to content:// links being allowed in this WebView. |
+| WebViewContentAccess.java:48:9:48:44 | setAllowContentAccess(...) | Sensitive information may be exposed via a malicious link due to access to content:// links being allowed in this WebView. |
+| WebViewContentAccess.java:51:25:51:44 | getAWebView(...) | Sensitive information may be exposed via a malicious link due to access to content:// links being allowed in this WebView. |
+| WebViewContentAccess.java:53:9:53:44 | setAllowContentAccess(...) | Sensitive information may be exposed via a malicious link due to access to content:// links being allowed in this WebView. |
+| WebViewContentAccess.java:55:29:55:48 | getAWebView(...) | Sensitive information may be exposed via a malicious link due to access to content:// links being allowed in this WebView. |
+| WebViewContentAccess.java:57:25:57:44 | getAWebView(...) | Sensitive information may be exposed via a malicious link due to access to content:// links being allowed in this WebView. |
From 909b1d70d92de02e644df3fd14bc9d9ac26dfaaa Mon Sep 17 00:00:00 2001
From: Ed Minnix
Date: Mon, 9 Jan 2023 10:11:03 -0500
Subject: [PATCH 135/381] Rename files to say "Allow" instead of "Permit"
---
...ss.qhelp => AndroidWebViewSettingsAllowsContentAccess.qhelp} | 0
...ntAccess.ql => AndroidWebViewSettingsAllowsContentAccess.ql} | 0
.../security/CWE-200/semmle/tests/WebViewContentAccess.qlref | 2 +-
3 files changed, 1 insertion(+), 1 deletion(-)
rename java/ql/src/Security/CWE/CWE-200/{AndroidWebViewSettingsPermitsContentAccess.qhelp => AndroidWebViewSettingsAllowsContentAccess.qhelp} (100%)
rename java/ql/src/Security/CWE/CWE-200/{AndroidWebViewSettingsPermitsContentAccess.ql => AndroidWebViewSettingsAllowsContentAccess.ql} (100%)
diff --git a/java/ql/src/Security/CWE/CWE-200/AndroidWebViewSettingsPermitsContentAccess.qhelp b/java/ql/src/Security/CWE/CWE-200/AndroidWebViewSettingsAllowsContentAccess.qhelp
similarity index 100%
rename from java/ql/src/Security/CWE/CWE-200/AndroidWebViewSettingsPermitsContentAccess.qhelp
rename to java/ql/src/Security/CWE/CWE-200/AndroidWebViewSettingsAllowsContentAccess.qhelp
diff --git a/java/ql/src/Security/CWE/CWE-200/AndroidWebViewSettingsPermitsContentAccess.ql b/java/ql/src/Security/CWE/CWE-200/AndroidWebViewSettingsAllowsContentAccess.ql
similarity index 100%
rename from java/ql/src/Security/CWE/CWE-200/AndroidWebViewSettingsPermitsContentAccess.ql
rename to java/ql/src/Security/CWE/CWE-200/AndroidWebViewSettingsAllowsContentAccess.ql
diff --git a/java/ql/test/query-tests/security/CWE-200/semmle/tests/WebViewContentAccess.qlref b/java/ql/test/query-tests/security/CWE-200/semmle/tests/WebViewContentAccess.qlref
index 8ea25a487de..7c9eba28b6e 100644
--- a/java/ql/test/query-tests/security/CWE-200/semmle/tests/WebViewContentAccess.qlref
+++ b/java/ql/test/query-tests/security/CWE-200/semmle/tests/WebViewContentAccess.qlref
@@ -1 +1 @@
-Security/CWE/CWE-200/AndroidWebViewSettingsPermitsContentAccess.ql
\ No newline at end of file
+Security/CWE/CWE-200/AndroidWebViewSettingsAllowsContentAccess.ql
\ No newline at end of file
From eb78661c1f3b022f6c5eaa26df860ac6a5b7bdce Mon Sep 17 00:00:00 2001
From: Tony Torralba
Date: Mon, 9 Jan 2023 17:36:54 +0100
Subject: [PATCH 136/381] Add missing SQL injection tests for the GRDB SQL
class
---
.../query-tests/Security/CWE-089/GRDB.swift | 21 +
.../Security/CWE-089/SqlInjection.expected | 373 +++++++++---------
2 files changed, 217 insertions(+), 177 deletions(-)
diff --git a/swift/ql/test/query-tests/Security/CWE-089/GRDB.swift b/swift/ql/test/query-tests/Security/CWE-089/GRDB.swift
index a680176bf89..b0319c84eb5 100644
--- a/swift/ql/test/query-tests/Security/CWE-089/GRDB.swift
+++ b/swift/ql/test/query-tests/Security/CWE-089/GRDB.swift
@@ -159,6 +159,27 @@ func testSqlRequest() throws {
let _ = SQLRequest(sql: localString, cached: false) // GOOD
}
+func testSql() throws {
+ let localString = "user"
+ let remoteString = try String(contentsOf: URL(string: "http://example.com/")!)
+
+ let _ = SQL(stringLiteral: remoteString) // BAD
+ let _ = SQL(unicodeScalarLiteral: remoteString) // BAD
+ let _ = SQL(extendedGraphemeClusterLiteral: remoteString) // BAD
+ let _ = SQL(stringInterpolation: remoteString) // BAD
+ let _ = SQL(sql: remoteString) // BAD
+ let sql1 = SQL(stringLiteral: "")
+ sql1.append(sql: remoteString) // BAD
+
+ let _ = SQL(stringLiteral: localString) // GOOD
+ let _ = SQL(unicodeScalarLiteral: localString) // GOOD
+ let _ = SQL(extendedGraphemeClusterLiteral: localString) // GOOD
+ let _ = SQL(stringInterpolation: localString) // GOOD
+ let _ = SQL(sql: localString) // GOOD
+ let sql2 = SQL(stringLiteral: "")
+ sql2.append(sql: localString) // GOOD
+}
+
func test(tableDefinition: TableDefinition) throws {
let localString = "user"
let remoteString = try String(contentsOf: URL(string: "http://example.com/")!)
diff --git a/swift/ql/test/query-tests/Security/CWE-089/SqlInjection.expected b/swift/ql/test/query-tests/Security/CWE-089/SqlInjection.expected
index bc60c3508ff..a88b40ccccd 100644
--- a/swift/ql/test/query-tests/Security/CWE-089/SqlInjection.expected
+++ b/swift/ql/test/query-tests/Security/CWE-089/SqlInjection.expected
@@ -19,63 +19,69 @@ edges
| GRDB.swift:130:26:130:80 | call to String.init(contentsOf:) : | GRDB.swift:149:29:149:29 | remoteString |
| GRDB.swift:130:26:130:80 | call to String.init(contentsOf:) : | GRDB.swift:150:29:150:29 | remoteString |
| GRDB.swift:130:26:130:80 | call to String.init(contentsOf:) : | GRDB.swift:151:29:151:29 | remoteString |
-| GRDB.swift:164:26:164:80 | call to String.init(contentsOf:) : | GRDB.swift:166:33:166:33 | remoteString |
-| GRDB.swift:164:26:164:80 | call to String.init(contentsOf:) : | GRDB.swift:169:32:169:32 | remoteString |
-| GRDB.swift:164:26:164:80 | call to String.init(contentsOf:) : | GRDB.swift:172:37:172:37 | remoteString |
-| GRDB.swift:178:26:178:80 | call to String.init(contentsOf:) : | GRDB.swift:180:36:180:36 | remoteString |
-| GRDB.swift:186:26:186:80 | call to String.init(contentsOf:) : | GRDB.swift:188:41:188:41 | remoteString |
-| GRDB.swift:186:26:186:80 | call to String.init(contentsOf:) : | GRDB.swift:189:44:189:44 | remoteString |
-| GRDB.swift:186:26:186:80 | call to String.init(contentsOf:) : | GRDB.swift:190:47:190:47 | remoteString |
-| GRDB.swift:186:26:186:80 | call to String.init(contentsOf:) : | GRDB.swift:191:47:191:47 | remoteString |
-| GRDB.swift:201:26:201:80 | call to String.init(contentsOf:) : | GRDB.swift:203:37:203:37 | remoteString |
-| GRDB.swift:201:26:201:80 | call to String.init(contentsOf:) : | GRDB.swift:204:37:204:37 | remoteString |
-| GRDB.swift:201:26:201:80 | call to String.init(contentsOf:) : | GRDB.swift:208:37:208:37 | remoteString |
-| GRDB.swift:201:26:201:80 | call to String.init(contentsOf:) : | GRDB.swift:209:37:209:37 | remoteString |
-| GRDB.swift:201:26:201:80 | call to String.init(contentsOf:) : | GRDB.swift:213:36:213:36 | remoteString |
-| GRDB.swift:201:26:201:80 | call to String.init(contentsOf:) : | GRDB.swift:214:36:214:36 | remoteString |
-| GRDB.swift:221:26:221:80 | call to String.init(contentsOf:) : | GRDB.swift:223:38:223:38 | remoteString |
-| GRDB.swift:229:26:229:80 | call to String.init(contentsOf:) : | GRDB.swift:231:32:231:32 | remoteString |
-| GRDB.swift:229:26:229:80 | call to String.init(contentsOf:) : | GRDB.swift:232:32:232:32 | remoteString |
-| GRDB.swift:229:26:229:80 | call to String.init(contentsOf:) : | GRDB.swift:233:32:233:32 | remoteString |
-| GRDB.swift:229:26:229:80 | call to String.init(contentsOf:) : | GRDB.swift:234:32:234:32 | remoteString |
-| GRDB.swift:229:26:229:80 | call to String.init(contentsOf:) : | GRDB.swift:240:29:240:29 | remoteString |
-| GRDB.swift:229:26:229:80 | call to String.init(contentsOf:) : | GRDB.swift:241:29:241:29 | remoteString |
-| GRDB.swift:229:26:229:80 | call to String.init(contentsOf:) : | GRDB.swift:242:29:242:29 | remoteString |
-| GRDB.swift:229:26:229:80 | call to String.init(contentsOf:) : | GRDB.swift:243:29:243:29 | remoteString |
-| GRDB.swift:229:26:229:80 | call to String.init(contentsOf:) : | GRDB.swift:249:29:249:29 | remoteString |
-| GRDB.swift:229:26:229:80 | call to String.init(contentsOf:) : | GRDB.swift:250:29:250:29 | remoteString |
-| GRDB.swift:229:26:229:80 | call to String.init(contentsOf:) : | GRDB.swift:251:29:251:29 | remoteString |
-| GRDB.swift:229:26:229:80 | call to String.init(contentsOf:) : | GRDB.swift:252:29:252:29 | remoteString |
-| GRDB.swift:229:26:229:80 | call to String.init(contentsOf:) : | GRDB.swift:258:29:258:29 | remoteString |
-| GRDB.swift:229:26:229:80 | call to String.init(contentsOf:) : | GRDB.swift:259:29:259:29 | remoteString |
-| GRDB.swift:229:26:229:80 | call to String.init(contentsOf:) : | GRDB.swift:260:29:260:29 | remoteString |
-| GRDB.swift:229:26:229:80 | call to String.init(contentsOf:) : | GRDB.swift:261:29:261:29 | remoteString |
-| GRDB.swift:270:26:270:80 | call to String.init(contentsOf:) : | GRDB.swift:272:53:272:53 | remoteString |
-| GRDB.swift:270:26:270:80 | call to String.init(contentsOf:) : | GRDB.swift:273:53:273:53 | remoteString |
-| GRDB.swift:270:26:270:80 | call to String.init(contentsOf:) : | GRDB.swift:274:53:274:53 | remoteString |
-| GRDB.swift:270:26:270:80 | call to String.init(contentsOf:) : | GRDB.swift:275:53:275:53 | remoteString |
-| GRDB.swift:270:26:270:80 | call to String.init(contentsOf:) : | GRDB.swift:281:50:281:50 | remoteString |
-| GRDB.swift:270:26:270:80 | call to String.init(contentsOf:) : | GRDB.swift:282:50:282:50 | remoteString |
-| GRDB.swift:270:26:270:80 | call to String.init(contentsOf:) : | GRDB.swift:283:50:283:50 | remoteString |
-| GRDB.swift:270:26:270:80 | call to String.init(contentsOf:) : | GRDB.swift:284:50:284:50 | remoteString |
-| GRDB.swift:270:26:270:80 | call to String.init(contentsOf:) : | GRDB.swift:290:50:290:50 | remoteString |
-| GRDB.swift:270:26:270:80 | call to String.init(contentsOf:) : | GRDB.swift:291:50:291:50 | remoteString |
-| GRDB.swift:270:26:270:80 | call to String.init(contentsOf:) : | GRDB.swift:292:50:292:50 | remoteString |
-| GRDB.swift:270:26:270:80 | call to String.init(contentsOf:) : | GRDB.swift:293:50:293:50 | remoteString |
-| GRDB.swift:270:26:270:80 | call to String.init(contentsOf:) : | GRDB.swift:299:50:299:50 | remoteString |
-| GRDB.swift:270:26:270:80 | call to String.init(contentsOf:) : | GRDB.swift:300:50:300:50 | remoteString |
-| GRDB.swift:270:26:270:80 | call to String.init(contentsOf:) : | GRDB.swift:301:50:301:50 | remoteString |
-| GRDB.swift:270:26:270:80 | call to String.init(contentsOf:) : | GRDB.swift:302:50:302:50 | remoteString |
-| GRDB.swift:311:26:311:80 | call to String.init(contentsOf:) : | GRDB.swift:313:57:313:57 | remoteString |
-| GRDB.swift:311:26:311:80 | call to String.init(contentsOf:) : | GRDB.swift:314:57:314:57 | remoteString |
-| GRDB.swift:321:26:321:80 | call to String.init(contentsOf:) : | GRDB.swift:323:51:323:51 | remoteString |
-| GRDB.swift:321:26:321:80 | call to String.init(contentsOf:) : | GRDB.swift:324:51:324:51 | remoteString |
-| GRDB.swift:321:26:321:80 | call to String.init(contentsOf:) : | GRDB.swift:325:66:325:66 | remoteString |
-| GRDB.swift:321:26:321:80 | call to String.init(contentsOf:) : | GRDB.swift:326:66:326:66 | remoteString |
-| GRDB.swift:321:26:321:80 | call to String.init(contentsOf:) : | GRDB.swift:327:69:327:69 | remoteString |
-| GRDB.swift:321:26:321:80 | call to String.init(contentsOf:) : | GRDB.swift:328:84:328:84 | remoteString |
-| GRDB.swift:321:26:321:80 | call to String.init(contentsOf:) : | GRDB.swift:329:69:329:69 | remoteString |
-| GRDB.swift:321:26:321:80 | call to String.init(contentsOf:) : | GRDB.swift:330:84:330:84 | remoteString |
+| GRDB.swift:164:26:164:80 | call to String.init(contentsOf:) : | GRDB.swift:166:32:166:32 | remoteString |
+| GRDB.swift:164:26:164:80 | call to String.init(contentsOf:) : | GRDB.swift:167:39:167:39 | remoteString |
+| GRDB.swift:164:26:164:80 | call to String.init(contentsOf:) : | GRDB.swift:168:49:168:49 | remoteString |
+| GRDB.swift:164:26:164:80 | call to String.init(contentsOf:) : | GRDB.swift:169:38:169:38 | remoteString |
+| GRDB.swift:164:26:164:80 | call to String.init(contentsOf:) : | GRDB.swift:170:22:170:22 | remoteString |
+| GRDB.swift:164:26:164:80 | call to String.init(contentsOf:) : | GRDB.swift:172:22:172:22 | remoteString |
+| GRDB.swift:185:26:185:80 | call to String.init(contentsOf:) : | GRDB.swift:187:33:187:33 | remoteString |
+| GRDB.swift:185:26:185:80 | call to String.init(contentsOf:) : | GRDB.swift:190:32:190:32 | remoteString |
+| GRDB.swift:185:26:185:80 | call to String.init(contentsOf:) : | GRDB.swift:193:37:193:37 | remoteString |
+| GRDB.swift:199:26:199:80 | call to String.init(contentsOf:) : | GRDB.swift:201:36:201:36 | remoteString |
+| GRDB.swift:207:26:207:80 | call to String.init(contentsOf:) : | GRDB.swift:209:41:209:41 | remoteString |
+| GRDB.swift:207:26:207:80 | call to String.init(contentsOf:) : | GRDB.swift:210:44:210:44 | remoteString |
+| GRDB.swift:207:26:207:80 | call to String.init(contentsOf:) : | GRDB.swift:211:47:211:47 | remoteString |
+| GRDB.swift:207:26:207:80 | call to String.init(contentsOf:) : | GRDB.swift:212:47:212:47 | remoteString |
+| GRDB.swift:222:26:222:80 | call to String.init(contentsOf:) : | GRDB.swift:224:37:224:37 | remoteString |
+| GRDB.swift:222:26:222:80 | call to String.init(contentsOf:) : | GRDB.swift:225:37:225:37 | remoteString |
+| GRDB.swift:222:26:222:80 | call to String.init(contentsOf:) : | GRDB.swift:229:37:229:37 | remoteString |
+| GRDB.swift:222:26:222:80 | call to String.init(contentsOf:) : | GRDB.swift:230:37:230:37 | remoteString |
+| GRDB.swift:222:26:222:80 | call to String.init(contentsOf:) : | GRDB.swift:234:36:234:36 | remoteString |
+| GRDB.swift:222:26:222:80 | call to String.init(contentsOf:) : | GRDB.swift:235:36:235:36 | remoteString |
+| GRDB.swift:242:26:242:80 | call to String.init(contentsOf:) : | GRDB.swift:244:38:244:38 | remoteString |
+| GRDB.swift:250:26:250:80 | call to String.init(contentsOf:) : | GRDB.swift:252:32:252:32 | remoteString |
+| GRDB.swift:250:26:250:80 | call to String.init(contentsOf:) : | GRDB.swift:253:32:253:32 | remoteString |
+| GRDB.swift:250:26:250:80 | call to String.init(contentsOf:) : | GRDB.swift:254:32:254:32 | remoteString |
+| GRDB.swift:250:26:250:80 | call to String.init(contentsOf:) : | GRDB.swift:255:32:255:32 | remoteString |
+| GRDB.swift:250:26:250:80 | call to String.init(contentsOf:) : | GRDB.swift:261:29:261:29 | remoteString |
+| GRDB.swift:250:26:250:80 | call to String.init(contentsOf:) : | GRDB.swift:262:29:262:29 | remoteString |
+| GRDB.swift:250:26:250:80 | call to String.init(contentsOf:) : | GRDB.swift:263:29:263:29 | remoteString |
+| GRDB.swift:250:26:250:80 | call to String.init(contentsOf:) : | GRDB.swift:264:29:264:29 | remoteString |
+| GRDB.swift:250:26:250:80 | call to String.init(contentsOf:) : | GRDB.swift:270:29:270:29 | remoteString |
+| GRDB.swift:250:26:250:80 | call to String.init(contentsOf:) : | GRDB.swift:271:29:271:29 | remoteString |
+| GRDB.swift:250:26:250:80 | call to String.init(contentsOf:) : | GRDB.swift:272:29:272:29 | remoteString |
+| GRDB.swift:250:26:250:80 | call to String.init(contentsOf:) : | GRDB.swift:273:29:273:29 | remoteString |
+| GRDB.swift:250:26:250:80 | call to String.init(contentsOf:) : | GRDB.swift:279:29:279:29 | remoteString |
+| GRDB.swift:250:26:250:80 | call to String.init(contentsOf:) : | GRDB.swift:280:29:280:29 | remoteString |
+| GRDB.swift:250:26:250:80 | call to String.init(contentsOf:) : | GRDB.swift:281:29:281:29 | remoteString |
+| GRDB.swift:250:26:250:80 | call to String.init(contentsOf:) : | GRDB.swift:282:29:282:29 | remoteString |
+| GRDB.swift:291:26:291:80 | call to String.init(contentsOf:) : | GRDB.swift:293:53:293:53 | remoteString |
+| GRDB.swift:291:26:291:80 | call to String.init(contentsOf:) : | GRDB.swift:294:53:294:53 | remoteString |
+| GRDB.swift:291:26:291:80 | call to String.init(contentsOf:) : | GRDB.swift:295:53:295:53 | remoteString |
+| GRDB.swift:291:26:291:80 | call to String.init(contentsOf:) : | GRDB.swift:296:53:296:53 | remoteString |
+| GRDB.swift:291:26:291:80 | call to String.init(contentsOf:) : | GRDB.swift:302:50:302:50 | remoteString |
+| GRDB.swift:291:26:291:80 | call to String.init(contentsOf:) : | GRDB.swift:303:50:303:50 | remoteString |
+| GRDB.swift:291:26:291:80 | call to String.init(contentsOf:) : | GRDB.swift:304:50:304:50 | remoteString |
+| GRDB.swift:291:26:291:80 | call to String.init(contentsOf:) : | GRDB.swift:305:50:305:50 | remoteString |
+| GRDB.swift:291:26:291:80 | call to String.init(contentsOf:) : | GRDB.swift:311:50:311:50 | remoteString |
+| GRDB.swift:291:26:291:80 | call to String.init(contentsOf:) : | GRDB.swift:312:50:312:50 | remoteString |
+| GRDB.swift:291:26:291:80 | call to String.init(contentsOf:) : | GRDB.swift:313:50:313:50 | remoteString |
+| GRDB.swift:291:26:291:80 | call to String.init(contentsOf:) : | GRDB.swift:314:50:314:50 | remoteString |
+| GRDB.swift:291:26:291:80 | call to String.init(contentsOf:) : | GRDB.swift:320:50:320:50 | remoteString |
+| GRDB.swift:291:26:291:80 | call to String.init(contentsOf:) : | GRDB.swift:321:50:321:50 | remoteString |
+| GRDB.swift:291:26:291:80 | call to String.init(contentsOf:) : | GRDB.swift:322:50:322:50 | remoteString |
+| GRDB.swift:291:26:291:80 | call to String.init(contentsOf:) : | GRDB.swift:323:50:323:50 | remoteString |
+| GRDB.swift:332:26:332:80 | call to String.init(contentsOf:) : | GRDB.swift:334:57:334:57 | remoteString |
+| GRDB.swift:332:26:332:80 | call to String.init(contentsOf:) : | GRDB.swift:335:57:335:57 | remoteString |
+| GRDB.swift:342:26:342:80 | call to String.init(contentsOf:) : | GRDB.swift:344:51:344:51 | remoteString |
+| GRDB.swift:342:26:342:80 | call to String.init(contentsOf:) : | GRDB.swift:345:51:345:51 | remoteString |
+| GRDB.swift:342:26:342:80 | call to String.init(contentsOf:) : | GRDB.swift:346:66:346:66 | remoteString |
+| GRDB.swift:342:26:342:80 | call to String.init(contentsOf:) : | GRDB.swift:347:66:347:66 | remoteString |
+| GRDB.swift:342:26:342:80 | call to String.init(contentsOf:) : | GRDB.swift:348:69:348:69 | remoteString |
+| GRDB.swift:342:26:342:80 | call to String.init(contentsOf:) : | GRDB.swift:349:84:349:84 | remoteString |
+| GRDB.swift:342:26:342:80 | call to String.init(contentsOf:) : | GRDB.swift:350:69:350:69 | remoteString |
+| GRDB.swift:342:26:342:80 | call to String.init(contentsOf:) : | GRDB.swift:351:84:351:84 | remoteString |
| SQLite.swift:62:25:62:79 | call to String.init(contentsOf:) : | SQLite.swift:73:17:73:17 | unsafeQuery1 |
| SQLite.swift:62:25:62:79 | call to String.init(contentsOf:) : | SQLite.swift:74:17:74:17 | unsafeQuery2 |
| SQLite.swift:62:25:62:79 | call to String.init(contentsOf:) : | SQLite.swift:75:17:75:17 | unsafeQuery3 |
@@ -121,71 +127,78 @@ nodes
| GRDB.swift:150:29:150:29 | remoteString | semmle.label | remoteString |
| GRDB.swift:151:29:151:29 | remoteString | semmle.label | remoteString |
| GRDB.swift:164:26:164:80 | call to String.init(contentsOf:) : | semmle.label | call to String.init(contentsOf:) : |
-| GRDB.swift:166:33:166:33 | remoteString | semmle.label | remoteString |
-| GRDB.swift:169:32:169:32 | remoteString | semmle.label | remoteString |
-| GRDB.swift:172:37:172:37 | remoteString | semmle.label | remoteString |
-| GRDB.swift:178:26:178:80 | call to String.init(contentsOf:) : | semmle.label | call to String.init(contentsOf:) : |
-| GRDB.swift:180:36:180:36 | remoteString | semmle.label | remoteString |
-| GRDB.swift:186:26:186:80 | call to String.init(contentsOf:) : | semmle.label | call to String.init(contentsOf:) : |
-| GRDB.swift:188:41:188:41 | remoteString | semmle.label | remoteString |
-| GRDB.swift:189:44:189:44 | remoteString | semmle.label | remoteString |
-| GRDB.swift:190:47:190:47 | remoteString | semmle.label | remoteString |
-| GRDB.swift:191:47:191:47 | remoteString | semmle.label | remoteString |
-| GRDB.swift:201:26:201:80 | call to String.init(contentsOf:) : | semmle.label | call to String.init(contentsOf:) : |
-| GRDB.swift:203:37:203:37 | remoteString | semmle.label | remoteString |
-| GRDB.swift:204:37:204:37 | remoteString | semmle.label | remoteString |
-| GRDB.swift:208:37:208:37 | remoteString | semmle.label | remoteString |
-| GRDB.swift:209:37:209:37 | remoteString | semmle.label | remoteString |
-| GRDB.swift:213:36:213:36 | remoteString | semmle.label | remoteString |
-| GRDB.swift:214:36:214:36 | remoteString | semmle.label | remoteString |
-| GRDB.swift:221:26:221:80 | call to String.init(contentsOf:) : | semmle.label | call to String.init(contentsOf:) : |
-| GRDB.swift:223:38:223:38 | remoteString | semmle.label | remoteString |
-| GRDB.swift:229:26:229:80 | call to String.init(contentsOf:) : | semmle.label | call to String.init(contentsOf:) : |
-| GRDB.swift:231:32:231:32 | remoteString | semmle.label | remoteString |
-| GRDB.swift:232:32:232:32 | remoteString | semmle.label | remoteString |
-| GRDB.swift:233:32:233:32 | remoteString | semmle.label | remoteString |
-| GRDB.swift:234:32:234:32 | remoteString | semmle.label | remoteString |
-| GRDB.swift:240:29:240:29 | remoteString | semmle.label | remoteString |
-| GRDB.swift:241:29:241:29 | remoteString | semmle.label | remoteString |
-| GRDB.swift:242:29:242:29 | remoteString | semmle.label | remoteString |
-| GRDB.swift:243:29:243:29 | remoteString | semmle.label | remoteString |
-| GRDB.swift:249:29:249:29 | remoteString | semmle.label | remoteString |
-| GRDB.swift:250:29:250:29 | remoteString | semmle.label | remoteString |
-| GRDB.swift:251:29:251:29 | remoteString | semmle.label | remoteString |
-| GRDB.swift:252:29:252:29 | remoteString | semmle.label | remoteString |
-| GRDB.swift:258:29:258:29 | remoteString | semmle.label | remoteString |
-| GRDB.swift:259:29:259:29 | remoteString | semmle.label | remoteString |
-| GRDB.swift:260:29:260:29 | remoteString | semmle.label | remoteString |
+| GRDB.swift:166:32:166:32 | remoteString | semmle.label | remoteString |
+| GRDB.swift:167:39:167:39 | remoteString | semmle.label | remoteString |
+| GRDB.swift:168:49:168:49 | remoteString | semmle.label | remoteString |
+| GRDB.swift:169:38:169:38 | remoteString | semmle.label | remoteString |
+| GRDB.swift:170:22:170:22 | remoteString | semmle.label | remoteString |
+| GRDB.swift:172:22:172:22 | remoteString | semmle.label | remoteString |
+| GRDB.swift:185:26:185:80 | call to String.init(contentsOf:) : | semmle.label | call to String.init(contentsOf:) : |
+| GRDB.swift:187:33:187:33 | remoteString | semmle.label | remoteString |
+| GRDB.swift:190:32:190:32 | remoteString | semmle.label | remoteString |
+| GRDB.swift:193:37:193:37 | remoteString | semmle.label | remoteString |
+| GRDB.swift:199:26:199:80 | call to String.init(contentsOf:) : | semmle.label | call to String.init(contentsOf:) : |
+| GRDB.swift:201:36:201:36 | remoteString | semmle.label | remoteString |
+| GRDB.swift:207:26:207:80 | call to String.init(contentsOf:) : | semmle.label | call to String.init(contentsOf:) : |
+| GRDB.swift:209:41:209:41 | remoteString | semmle.label | remoteString |
+| GRDB.swift:210:44:210:44 | remoteString | semmle.label | remoteString |
+| GRDB.swift:211:47:211:47 | remoteString | semmle.label | remoteString |
+| GRDB.swift:212:47:212:47 | remoteString | semmle.label | remoteString |
+| GRDB.swift:222:26:222:80 | call to String.init(contentsOf:) : | semmle.label | call to String.init(contentsOf:) : |
+| GRDB.swift:224:37:224:37 | remoteString | semmle.label | remoteString |
+| GRDB.swift:225:37:225:37 | remoteString | semmle.label | remoteString |
+| GRDB.swift:229:37:229:37 | remoteString | semmle.label | remoteString |
+| GRDB.swift:230:37:230:37 | remoteString | semmle.label | remoteString |
+| GRDB.swift:234:36:234:36 | remoteString | semmle.label | remoteString |
+| GRDB.swift:235:36:235:36 | remoteString | semmle.label | remoteString |
+| GRDB.swift:242:26:242:80 | call to String.init(contentsOf:) : | semmle.label | call to String.init(contentsOf:) : |
+| GRDB.swift:244:38:244:38 | remoteString | semmle.label | remoteString |
+| GRDB.swift:250:26:250:80 | call to String.init(contentsOf:) : | semmle.label | call to String.init(contentsOf:) : |
+| GRDB.swift:252:32:252:32 | remoteString | semmle.label | remoteString |
+| GRDB.swift:253:32:253:32 | remoteString | semmle.label | remoteString |
+| GRDB.swift:254:32:254:32 | remoteString | semmle.label | remoteString |
+| GRDB.swift:255:32:255:32 | remoteString | semmle.label | remoteString |
| GRDB.swift:261:29:261:29 | remoteString | semmle.label | remoteString |
-| GRDB.swift:270:26:270:80 | call to String.init(contentsOf:) : | semmle.label | call to String.init(contentsOf:) : |
-| GRDB.swift:272:53:272:53 | remoteString | semmle.label | remoteString |
-| GRDB.swift:273:53:273:53 | remoteString | semmle.label | remoteString |
-| GRDB.swift:274:53:274:53 | remoteString | semmle.label | remoteString |
-| GRDB.swift:275:53:275:53 | remoteString | semmle.label | remoteString |
-| GRDB.swift:281:50:281:50 | remoteString | semmle.label | remoteString |
-| GRDB.swift:282:50:282:50 | remoteString | semmle.label | remoteString |
-| GRDB.swift:283:50:283:50 | remoteString | semmle.label | remoteString |
-| GRDB.swift:284:50:284:50 | remoteString | semmle.label | remoteString |
-| GRDB.swift:290:50:290:50 | remoteString | semmle.label | remoteString |
-| GRDB.swift:291:50:291:50 | remoteString | semmle.label | remoteString |
-| GRDB.swift:292:50:292:50 | remoteString | semmle.label | remoteString |
-| GRDB.swift:293:50:293:50 | remoteString | semmle.label | remoteString |
-| GRDB.swift:299:50:299:50 | remoteString | semmle.label | remoteString |
-| GRDB.swift:300:50:300:50 | remoteString | semmle.label | remoteString |
-| GRDB.swift:301:50:301:50 | remoteString | semmle.label | remoteString |
+| GRDB.swift:262:29:262:29 | remoteString | semmle.label | remoteString |
+| GRDB.swift:263:29:263:29 | remoteString | semmle.label | remoteString |
+| GRDB.swift:264:29:264:29 | remoteString | semmle.label | remoteString |
+| GRDB.swift:270:29:270:29 | remoteString | semmle.label | remoteString |
+| GRDB.swift:271:29:271:29 | remoteString | semmle.label | remoteString |
+| GRDB.swift:272:29:272:29 | remoteString | semmle.label | remoteString |
+| GRDB.swift:273:29:273:29 | remoteString | semmle.label | remoteString |
+| GRDB.swift:279:29:279:29 | remoteString | semmle.label | remoteString |
+| GRDB.swift:280:29:280:29 | remoteString | semmle.label | remoteString |
+| GRDB.swift:281:29:281:29 | remoteString | semmle.label | remoteString |
+| GRDB.swift:282:29:282:29 | remoteString | semmle.label | remoteString |
+| GRDB.swift:291:26:291:80 | call to String.init(contentsOf:) : | semmle.label | call to String.init(contentsOf:) : |
+| GRDB.swift:293:53:293:53 | remoteString | semmle.label | remoteString |
+| GRDB.swift:294:53:294:53 | remoteString | semmle.label | remoteString |
+| GRDB.swift:295:53:295:53 | remoteString | semmle.label | remoteString |
+| GRDB.swift:296:53:296:53 | remoteString | semmle.label | remoteString |
| GRDB.swift:302:50:302:50 | remoteString | semmle.label | remoteString |
-| GRDB.swift:311:26:311:80 | call to String.init(contentsOf:) : | semmle.label | call to String.init(contentsOf:) : |
-| GRDB.swift:313:57:313:57 | remoteString | semmle.label | remoteString |
-| GRDB.swift:314:57:314:57 | remoteString | semmle.label | remoteString |
-| GRDB.swift:321:26:321:80 | call to String.init(contentsOf:) : | semmle.label | call to String.init(contentsOf:) : |
-| GRDB.swift:323:51:323:51 | remoteString | semmle.label | remoteString |
-| GRDB.swift:324:51:324:51 | remoteString | semmle.label | remoteString |
-| GRDB.swift:325:66:325:66 | remoteString | semmle.label | remoteString |
-| GRDB.swift:326:66:326:66 | remoteString | semmle.label | remoteString |
-| GRDB.swift:327:69:327:69 | remoteString | semmle.label | remoteString |
-| GRDB.swift:328:84:328:84 | remoteString | semmle.label | remoteString |
-| GRDB.swift:329:69:329:69 | remoteString | semmle.label | remoteString |
-| GRDB.swift:330:84:330:84 | remoteString | semmle.label | remoteString |
+| GRDB.swift:303:50:303:50 | remoteString | semmle.label | remoteString |
+| GRDB.swift:304:50:304:50 | remoteString | semmle.label | remoteString |
+| GRDB.swift:305:50:305:50 | remoteString | semmle.label | remoteString |
+| GRDB.swift:311:50:311:50 | remoteString | semmle.label | remoteString |
+| GRDB.swift:312:50:312:50 | remoteString | semmle.label | remoteString |
+| GRDB.swift:313:50:313:50 | remoteString | semmle.label | remoteString |
+| GRDB.swift:314:50:314:50 | remoteString | semmle.label | remoteString |
+| GRDB.swift:320:50:320:50 | remoteString | semmle.label | remoteString |
+| GRDB.swift:321:50:321:50 | remoteString | semmle.label | remoteString |
+| GRDB.swift:322:50:322:50 | remoteString | semmle.label | remoteString |
+| GRDB.swift:323:50:323:50 | remoteString | semmle.label | remoteString |
+| GRDB.swift:332:26:332:80 | call to String.init(contentsOf:) : | semmle.label | call to String.init(contentsOf:) : |
+| GRDB.swift:334:57:334:57 | remoteString | semmle.label | remoteString |
+| GRDB.swift:335:57:335:57 | remoteString | semmle.label | remoteString |
+| GRDB.swift:342:26:342:80 | call to String.init(contentsOf:) : | semmle.label | call to String.init(contentsOf:) : |
+| GRDB.swift:344:51:344:51 | remoteString | semmle.label | remoteString |
+| GRDB.swift:345:51:345:51 | remoteString | semmle.label | remoteString |
+| GRDB.swift:346:66:346:66 | remoteString | semmle.label | remoteString |
+| GRDB.swift:347:66:347:66 | remoteString | semmle.label | remoteString |
+| GRDB.swift:348:69:348:69 | remoteString | semmle.label | remoteString |
+| GRDB.swift:349:84:349:84 | remoteString | semmle.label | remoteString |
+| GRDB.swift:350:69:350:69 | remoteString | semmle.label | remoteString |
+| GRDB.swift:351:84:351:84 | remoteString | semmle.label | remoteString |
| SQLite.swift:62:25:62:79 | call to String.init(contentsOf:) : | semmle.label | call to String.init(contentsOf:) : |
| SQLite.swift:73:17:73:17 | unsafeQuery1 | semmle.label | unsafeQuery1 |
| SQLite.swift:74:17:74:17 | unsafeQuery2 | semmle.label | unsafeQuery2 |
@@ -231,63 +244,69 @@ subpaths
| GRDB.swift:149:29:149:29 | remoteString | GRDB.swift:130:26:130:80 | call to String.init(contentsOf:) : | GRDB.swift:149:29:149:29 | remoteString | This query depends on a $@. | GRDB.swift:130:26:130:80 | call to String.init(contentsOf:) | user-provided value |
| GRDB.swift:150:29:150:29 | remoteString | GRDB.swift:130:26:130:80 | call to String.init(contentsOf:) : | GRDB.swift:150:29:150:29 | remoteString | This query depends on a $@. | GRDB.swift:130:26:130:80 | call to String.init(contentsOf:) | user-provided value |
| GRDB.swift:151:29:151:29 | remoteString | GRDB.swift:130:26:130:80 | call to String.init(contentsOf:) : | GRDB.swift:151:29:151:29 | remoteString | This query depends on a $@. | GRDB.swift:130:26:130:80 | call to String.init(contentsOf:) | user-provided value |
-| GRDB.swift:166:33:166:33 | remoteString | GRDB.swift:164:26:164:80 | call to String.init(contentsOf:) : | GRDB.swift:166:33:166:33 | remoteString | This query depends on a $@. | GRDB.swift:164:26:164:80 | call to String.init(contentsOf:) | user-provided value |
-| GRDB.swift:169:32:169:32 | remoteString | GRDB.swift:164:26:164:80 | call to String.init(contentsOf:) : | GRDB.swift:169:32:169:32 | remoteString | This query depends on a $@. | GRDB.swift:164:26:164:80 | call to String.init(contentsOf:) | user-provided value |
-| GRDB.swift:172:37:172:37 | remoteString | GRDB.swift:164:26:164:80 | call to String.init(contentsOf:) : | GRDB.swift:172:37:172:37 | remoteString | This query depends on a $@. | GRDB.swift:164:26:164:80 | call to String.init(contentsOf:) | user-provided value |
-| GRDB.swift:180:36:180:36 | remoteString | GRDB.swift:178:26:178:80 | call to String.init(contentsOf:) : | GRDB.swift:180:36:180:36 | remoteString | This query depends on a $@. | GRDB.swift:178:26:178:80 | call to String.init(contentsOf:) | user-provided value |
-| GRDB.swift:188:41:188:41 | remoteString | GRDB.swift:186:26:186:80 | call to String.init(contentsOf:) : | GRDB.swift:188:41:188:41 | remoteString | This query depends on a $@. | GRDB.swift:186:26:186:80 | call to String.init(contentsOf:) | user-provided value |
-| GRDB.swift:189:44:189:44 | remoteString | GRDB.swift:186:26:186:80 | call to String.init(contentsOf:) : | GRDB.swift:189:44:189:44 | remoteString | This query depends on a $@. | GRDB.swift:186:26:186:80 | call to String.init(contentsOf:) | user-provided value |
-| GRDB.swift:190:47:190:47 | remoteString | GRDB.swift:186:26:186:80 | call to String.init(contentsOf:) : | GRDB.swift:190:47:190:47 | remoteString | This query depends on a $@. | GRDB.swift:186:26:186:80 | call to String.init(contentsOf:) | user-provided value |
-| GRDB.swift:191:47:191:47 | remoteString | GRDB.swift:186:26:186:80 | call to String.init(contentsOf:) : | GRDB.swift:191:47:191:47 | remoteString | This query depends on a $@. | GRDB.swift:186:26:186:80 | call to String.init(contentsOf:) | user-provided value |
-| GRDB.swift:203:37:203:37 | remoteString | GRDB.swift:201:26:201:80 | call to String.init(contentsOf:) : | GRDB.swift:203:37:203:37 | remoteString | This query depends on a $@. | GRDB.swift:201:26:201:80 | call to String.init(contentsOf:) | user-provided value |
-| GRDB.swift:204:37:204:37 | remoteString | GRDB.swift:201:26:201:80 | call to String.init(contentsOf:) : | GRDB.swift:204:37:204:37 | remoteString | This query depends on a $@. | GRDB.swift:201:26:201:80 | call to String.init(contentsOf:) | user-provided value |
-| GRDB.swift:208:37:208:37 | remoteString | GRDB.swift:201:26:201:80 | call to String.init(contentsOf:) : | GRDB.swift:208:37:208:37 | remoteString | This query depends on a $@. | GRDB.swift:201:26:201:80 | call to String.init(contentsOf:) | user-provided value |
-| GRDB.swift:209:37:209:37 | remoteString | GRDB.swift:201:26:201:80 | call to String.init(contentsOf:) : | GRDB.swift:209:37:209:37 | remoteString | This query depends on a $@. | GRDB.swift:201:26:201:80 | call to String.init(contentsOf:) | user-provided value |
-| GRDB.swift:213:36:213:36 | remoteString | GRDB.swift:201:26:201:80 | call to String.init(contentsOf:) : | GRDB.swift:213:36:213:36 | remoteString | This query depends on a $@. | GRDB.swift:201:26:201:80 | call to String.init(contentsOf:) | user-provided value |
-| GRDB.swift:214:36:214:36 | remoteString | GRDB.swift:201:26:201:80 | call to String.init(contentsOf:) : | GRDB.swift:214:36:214:36 | remoteString | This query depends on a $@. | GRDB.swift:201:26:201:80 | call to String.init(contentsOf:) | user-provided value |
-| GRDB.swift:223:38:223:38 | remoteString | GRDB.swift:221:26:221:80 | call to String.init(contentsOf:) : | GRDB.swift:223:38:223:38 | remoteString | This query depends on a $@. | GRDB.swift:221:26:221:80 | call to String.init(contentsOf:) | user-provided value |
-| GRDB.swift:231:32:231:32 | remoteString | GRDB.swift:229:26:229:80 | call to String.init(contentsOf:) : | GRDB.swift:231:32:231:32 | remoteString | This query depends on a $@. | GRDB.swift:229:26:229:80 | call to String.init(contentsOf:) | user-provided value |
-| GRDB.swift:232:32:232:32 | remoteString | GRDB.swift:229:26:229:80 | call to String.init(contentsOf:) : | GRDB.swift:232:32:232:32 | remoteString | This query depends on a $@. | GRDB.swift:229:26:229:80 | call to String.init(contentsOf:) | user-provided value |
-| GRDB.swift:233:32:233:32 | remoteString | GRDB.swift:229:26:229:80 | call to String.init(contentsOf:) : | GRDB.swift:233:32:233:32 | remoteString | This query depends on a $@. | GRDB.swift:229:26:229:80 | call to String.init(contentsOf:) | user-provided value |
-| GRDB.swift:234:32:234:32 | remoteString | GRDB.swift:229:26:229:80 | call to String.init(contentsOf:) : | GRDB.swift:234:32:234:32 | remoteString | This query depends on a $@. | GRDB.swift:229:26:229:80 | call to String.init(contentsOf:) | user-provided value |
-| GRDB.swift:240:29:240:29 | remoteString | GRDB.swift:229:26:229:80 | call to String.init(contentsOf:) : | GRDB.swift:240:29:240:29 | remoteString | This query depends on a $@. | GRDB.swift:229:26:229:80 | call to String.init(contentsOf:) | user-provided value |
-| GRDB.swift:241:29:241:29 | remoteString | GRDB.swift:229:26:229:80 | call to String.init(contentsOf:) : | GRDB.swift:241:29:241:29 | remoteString | This query depends on a $@. | GRDB.swift:229:26:229:80 | call to String.init(contentsOf:) | user-provided value |
-| GRDB.swift:242:29:242:29 | remoteString | GRDB.swift:229:26:229:80 | call to String.init(contentsOf:) : | GRDB.swift:242:29:242:29 | remoteString | This query depends on a $@. | GRDB.swift:229:26:229:80 | call to String.init(contentsOf:) | user-provided value |
-| GRDB.swift:243:29:243:29 | remoteString | GRDB.swift:229:26:229:80 | call to String.init(contentsOf:) : | GRDB.swift:243:29:243:29 | remoteString | This query depends on a $@. | GRDB.swift:229:26:229:80 | call to String.init(contentsOf:) | user-provided value |
-| GRDB.swift:249:29:249:29 | remoteString | GRDB.swift:229:26:229:80 | call to String.init(contentsOf:) : | GRDB.swift:249:29:249:29 | remoteString | This query depends on a $@. | GRDB.swift:229:26:229:80 | call to String.init(contentsOf:) | user-provided value |
-| GRDB.swift:250:29:250:29 | remoteString | GRDB.swift:229:26:229:80 | call to String.init(contentsOf:) : | GRDB.swift:250:29:250:29 | remoteString | This query depends on a $@. | GRDB.swift:229:26:229:80 | call to String.init(contentsOf:) | user-provided value |
-| GRDB.swift:251:29:251:29 | remoteString | GRDB.swift:229:26:229:80 | call to String.init(contentsOf:) : | GRDB.swift:251:29:251:29 | remoteString | This query depends on a $@. | GRDB.swift:229:26:229:80 | call to String.init(contentsOf:) | user-provided value |
-| GRDB.swift:252:29:252:29 | remoteString | GRDB.swift:229:26:229:80 | call to String.init(contentsOf:) : | GRDB.swift:252:29:252:29 | remoteString | This query depends on a $@. | GRDB.swift:229:26:229:80 | call to String.init(contentsOf:) | user-provided value |
-| GRDB.swift:258:29:258:29 | remoteString | GRDB.swift:229:26:229:80 | call to String.init(contentsOf:) : | GRDB.swift:258:29:258:29 | remoteString | This query depends on a $@. | GRDB.swift:229:26:229:80 | call to String.init(contentsOf:) | user-provided value |
-| GRDB.swift:259:29:259:29 | remoteString | GRDB.swift:229:26:229:80 | call to String.init(contentsOf:) : | GRDB.swift:259:29:259:29 | remoteString | This query depends on a $@. | GRDB.swift:229:26:229:80 | call to String.init(contentsOf:) | user-provided value |
-| GRDB.swift:260:29:260:29 | remoteString | GRDB.swift:229:26:229:80 | call to String.init(contentsOf:) : | GRDB.swift:260:29:260:29 | remoteString | This query depends on a $@. | GRDB.swift:229:26:229:80 | call to String.init(contentsOf:) | user-provided value |
-| GRDB.swift:261:29:261:29 | remoteString | GRDB.swift:229:26:229:80 | call to String.init(contentsOf:) : | GRDB.swift:261:29:261:29 | remoteString | This query depends on a $@. | GRDB.swift:229:26:229:80 | call to String.init(contentsOf:) | user-provided value |
-| GRDB.swift:272:53:272:53 | remoteString | GRDB.swift:270:26:270:80 | call to String.init(contentsOf:) : | GRDB.swift:272:53:272:53 | remoteString | This query depends on a $@. | GRDB.swift:270:26:270:80 | call to String.init(contentsOf:) | user-provided value |
-| GRDB.swift:273:53:273:53 | remoteString | GRDB.swift:270:26:270:80 | call to String.init(contentsOf:) : | GRDB.swift:273:53:273:53 | remoteString | This query depends on a $@. | GRDB.swift:270:26:270:80 | call to String.init(contentsOf:) | user-provided value |
-| GRDB.swift:274:53:274:53 | remoteString | GRDB.swift:270:26:270:80 | call to String.init(contentsOf:) : | GRDB.swift:274:53:274:53 | remoteString | This query depends on a $@. | GRDB.swift:270:26:270:80 | call to String.init(contentsOf:) | user-provided value |
-| GRDB.swift:275:53:275:53 | remoteString | GRDB.swift:270:26:270:80 | call to String.init(contentsOf:) : | GRDB.swift:275:53:275:53 | remoteString | This query depends on a $@. | GRDB.swift:270:26:270:80 | call to String.init(contentsOf:) | user-provided value |
-| GRDB.swift:281:50:281:50 | remoteString | GRDB.swift:270:26:270:80 | call to String.init(contentsOf:) : | GRDB.swift:281:50:281:50 | remoteString | This query depends on a $@. | GRDB.swift:270:26:270:80 | call to String.init(contentsOf:) | user-provided value |
-| GRDB.swift:282:50:282:50 | remoteString | GRDB.swift:270:26:270:80 | call to String.init(contentsOf:) : | GRDB.swift:282:50:282:50 | remoteString | This query depends on a $@. | GRDB.swift:270:26:270:80 | call to String.init(contentsOf:) | user-provided value |
-| GRDB.swift:283:50:283:50 | remoteString | GRDB.swift:270:26:270:80 | call to String.init(contentsOf:) : | GRDB.swift:283:50:283:50 | remoteString | This query depends on a $@. | GRDB.swift:270:26:270:80 | call to String.init(contentsOf:) | user-provided value |
-| GRDB.swift:284:50:284:50 | remoteString | GRDB.swift:270:26:270:80 | call to String.init(contentsOf:) : | GRDB.swift:284:50:284:50 | remoteString | This query depends on a $@. | GRDB.swift:270:26:270:80 | call to String.init(contentsOf:) | user-provided value |
-| GRDB.swift:290:50:290:50 | remoteString | GRDB.swift:270:26:270:80 | call to String.init(contentsOf:) : | GRDB.swift:290:50:290:50 | remoteString | This query depends on a $@. | GRDB.swift:270:26:270:80 | call to String.init(contentsOf:) | user-provided value |
-| GRDB.swift:291:50:291:50 | remoteString | GRDB.swift:270:26:270:80 | call to String.init(contentsOf:) : | GRDB.swift:291:50:291:50 | remoteString | This query depends on a $@. | GRDB.swift:270:26:270:80 | call to String.init(contentsOf:) | user-provided value |
-| GRDB.swift:292:50:292:50 | remoteString | GRDB.swift:270:26:270:80 | call to String.init(contentsOf:) : | GRDB.swift:292:50:292:50 | remoteString | This query depends on a $@. | GRDB.swift:270:26:270:80 | call to String.init(contentsOf:) | user-provided value |
-| GRDB.swift:293:50:293:50 | remoteString | GRDB.swift:270:26:270:80 | call to String.init(contentsOf:) : | GRDB.swift:293:50:293:50 | remoteString | This query depends on a $@. | GRDB.swift:270:26:270:80 | call to String.init(contentsOf:) | user-provided value |
-| GRDB.swift:299:50:299:50 | remoteString | GRDB.swift:270:26:270:80 | call to String.init(contentsOf:) : | GRDB.swift:299:50:299:50 | remoteString | This query depends on a $@. | GRDB.swift:270:26:270:80 | call to String.init(contentsOf:) | user-provided value |
-| GRDB.swift:300:50:300:50 | remoteString | GRDB.swift:270:26:270:80 | call to String.init(contentsOf:) : | GRDB.swift:300:50:300:50 | remoteString | This query depends on a $@. | GRDB.swift:270:26:270:80 | call to String.init(contentsOf:) | user-provided value |
-| GRDB.swift:301:50:301:50 | remoteString | GRDB.swift:270:26:270:80 | call to String.init(contentsOf:) : | GRDB.swift:301:50:301:50 | remoteString | This query depends on a $@. | GRDB.swift:270:26:270:80 | call to String.init(contentsOf:) | user-provided value |
-| GRDB.swift:302:50:302:50 | remoteString | GRDB.swift:270:26:270:80 | call to String.init(contentsOf:) : | GRDB.swift:302:50:302:50 | remoteString | This query depends on a $@. | GRDB.swift:270:26:270:80 | call to String.init(contentsOf:) | user-provided value |
-| GRDB.swift:313:57:313:57 | remoteString | GRDB.swift:311:26:311:80 | call to String.init(contentsOf:) : | GRDB.swift:313:57:313:57 | remoteString | This query depends on a $@. | GRDB.swift:311:26:311:80 | call to String.init(contentsOf:) | user-provided value |
-| GRDB.swift:314:57:314:57 | remoteString | GRDB.swift:311:26:311:80 | call to String.init(contentsOf:) : | GRDB.swift:314:57:314:57 | remoteString | This query depends on a $@. | GRDB.swift:311:26:311:80 | call to String.init(contentsOf:) | user-provided value |
-| GRDB.swift:323:51:323:51 | remoteString | GRDB.swift:321:26:321:80 | call to String.init(contentsOf:) : | GRDB.swift:323:51:323:51 | remoteString | This query depends on a $@. | GRDB.swift:321:26:321:80 | call to String.init(contentsOf:) | user-provided value |
-| GRDB.swift:324:51:324:51 | remoteString | GRDB.swift:321:26:321:80 | call to String.init(contentsOf:) : | GRDB.swift:324:51:324:51 | remoteString | This query depends on a $@. | GRDB.swift:321:26:321:80 | call to String.init(contentsOf:) | user-provided value |
-| GRDB.swift:325:66:325:66 | remoteString | GRDB.swift:321:26:321:80 | call to String.init(contentsOf:) : | GRDB.swift:325:66:325:66 | remoteString | This query depends on a $@. | GRDB.swift:321:26:321:80 | call to String.init(contentsOf:) | user-provided value |
-| GRDB.swift:326:66:326:66 | remoteString | GRDB.swift:321:26:321:80 | call to String.init(contentsOf:) : | GRDB.swift:326:66:326:66 | remoteString | This query depends on a $@. | GRDB.swift:321:26:321:80 | call to String.init(contentsOf:) | user-provided value |
-| GRDB.swift:327:69:327:69 | remoteString | GRDB.swift:321:26:321:80 | call to String.init(contentsOf:) : | GRDB.swift:327:69:327:69 | remoteString | This query depends on a $@. | GRDB.swift:321:26:321:80 | call to String.init(contentsOf:) | user-provided value |
-| GRDB.swift:328:84:328:84 | remoteString | GRDB.swift:321:26:321:80 | call to String.init(contentsOf:) : | GRDB.swift:328:84:328:84 | remoteString | This query depends on a $@. | GRDB.swift:321:26:321:80 | call to String.init(contentsOf:) | user-provided value |
-| GRDB.swift:329:69:329:69 | remoteString | GRDB.swift:321:26:321:80 | call to String.init(contentsOf:) : | GRDB.swift:329:69:329:69 | remoteString | This query depends on a $@. | GRDB.swift:321:26:321:80 | call to String.init(contentsOf:) | user-provided value |
-| GRDB.swift:330:84:330:84 | remoteString | GRDB.swift:321:26:321:80 | call to String.init(contentsOf:) : | GRDB.swift:330:84:330:84 | remoteString | This query depends on a $@. | GRDB.swift:321:26:321:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:166:32:166:32 | remoteString | GRDB.swift:164:26:164:80 | call to String.init(contentsOf:) : | GRDB.swift:166:32:166:32 | remoteString | This query depends on a $@. | GRDB.swift:164:26:164:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:167:39:167:39 | remoteString | GRDB.swift:164:26:164:80 | call to String.init(contentsOf:) : | GRDB.swift:167:39:167:39 | remoteString | This query depends on a $@. | GRDB.swift:164:26:164:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:168:49:168:49 | remoteString | GRDB.swift:164:26:164:80 | call to String.init(contentsOf:) : | GRDB.swift:168:49:168:49 | remoteString | This query depends on a $@. | GRDB.swift:164:26:164:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:169:38:169:38 | remoteString | GRDB.swift:164:26:164:80 | call to String.init(contentsOf:) : | GRDB.swift:169:38:169:38 | remoteString | This query depends on a $@. | GRDB.swift:164:26:164:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:170:22:170:22 | remoteString | GRDB.swift:164:26:164:80 | call to String.init(contentsOf:) : | GRDB.swift:170:22:170:22 | remoteString | This query depends on a $@. | GRDB.swift:164:26:164:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:172:22:172:22 | remoteString | GRDB.swift:164:26:164:80 | call to String.init(contentsOf:) : | GRDB.swift:172:22:172:22 | remoteString | This query depends on a $@. | GRDB.swift:164:26:164:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:187:33:187:33 | remoteString | GRDB.swift:185:26:185:80 | call to String.init(contentsOf:) : | GRDB.swift:187:33:187:33 | remoteString | This query depends on a $@. | GRDB.swift:185:26:185:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:190:32:190:32 | remoteString | GRDB.swift:185:26:185:80 | call to String.init(contentsOf:) : | GRDB.swift:190:32:190:32 | remoteString | This query depends on a $@. | GRDB.swift:185:26:185:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:193:37:193:37 | remoteString | GRDB.swift:185:26:185:80 | call to String.init(contentsOf:) : | GRDB.swift:193:37:193:37 | remoteString | This query depends on a $@. | GRDB.swift:185:26:185:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:201:36:201:36 | remoteString | GRDB.swift:199:26:199:80 | call to String.init(contentsOf:) : | GRDB.swift:201:36:201:36 | remoteString | This query depends on a $@. | GRDB.swift:199:26:199:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:209:41:209:41 | remoteString | GRDB.swift:207:26:207:80 | call to String.init(contentsOf:) : | GRDB.swift:209:41:209:41 | remoteString | This query depends on a $@. | GRDB.swift:207:26:207:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:210:44:210:44 | remoteString | GRDB.swift:207:26:207:80 | call to String.init(contentsOf:) : | GRDB.swift:210:44:210:44 | remoteString | This query depends on a $@. | GRDB.swift:207:26:207:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:211:47:211:47 | remoteString | GRDB.swift:207:26:207:80 | call to String.init(contentsOf:) : | GRDB.swift:211:47:211:47 | remoteString | This query depends on a $@. | GRDB.swift:207:26:207:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:212:47:212:47 | remoteString | GRDB.swift:207:26:207:80 | call to String.init(contentsOf:) : | GRDB.swift:212:47:212:47 | remoteString | This query depends on a $@. | GRDB.swift:207:26:207:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:224:37:224:37 | remoteString | GRDB.swift:222:26:222:80 | call to String.init(contentsOf:) : | GRDB.swift:224:37:224:37 | remoteString | This query depends on a $@. | GRDB.swift:222:26:222:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:225:37:225:37 | remoteString | GRDB.swift:222:26:222:80 | call to String.init(contentsOf:) : | GRDB.swift:225:37:225:37 | remoteString | This query depends on a $@. | GRDB.swift:222:26:222:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:229:37:229:37 | remoteString | GRDB.swift:222:26:222:80 | call to String.init(contentsOf:) : | GRDB.swift:229:37:229:37 | remoteString | This query depends on a $@. | GRDB.swift:222:26:222:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:230:37:230:37 | remoteString | GRDB.swift:222:26:222:80 | call to String.init(contentsOf:) : | GRDB.swift:230:37:230:37 | remoteString | This query depends on a $@. | GRDB.swift:222:26:222:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:234:36:234:36 | remoteString | GRDB.swift:222:26:222:80 | call to String.init(contentsOf:) : | GRDB.swift:234:36:234:36 | remoteString | This query depends on a $@. | GRDB.swift:222:26:222:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:235:36:235:36 | remoteString | GRDB.swift:222:26:222:80 | call to String.init(contentsOf:) : | GRDB.swift:235:36:235:36 | remoteString | This query depends on a $@. | GRDB.swift:222:26:222:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:244:38:244:38 | remoteString | GRDB.swift:242:26:242:80 | call to String.init(contentsOf:) : | GRDB.swift:244:38:244:38 | remoteString | This query depends on a $@. | GRDB.swift:242:26:242:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:252:32:252:32 | remoteString | GRDB.swift:250:26:250:80 | call to String.init(contentsOf:) : | GRDB.swift:252:32:252:32 | remoteString | This query depends on a $@. | GRDB.swift:250:26:250:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:253:32:253:32 | remoteString | GRDB.swift:250:26:250:80 | call to String.init(contentsOf:) : | GRDB.swift:253:32:253:32 | remoteString | This query depends on a $@. | GRDB.swift:250:26:250:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:254:32:254:32 | remoteString | GRDB.swift:250:26:250:80 | call to String.init(contentsOf:) : | GRDB.swift:254:32:254:32 | remoteString | This query depends on a $@. | GRDB.swift:250:26:250:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:255:32:255:32 | remoteString | GRDB.swift:250:26:250:80 | call to String.init(contentsOf:) : | GRDB.swift:255:32:255:32 | remoteString | This query depends on a $@. | GRDB.swift:250:26:250:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:261:29:261:29 | remoteString | GRDB.swift:250:26:250:80 | call to String.init(contentsOf:) : | GRDB.swift:261:29:261:29 | remoteString | This query depends on a $@. | GRDB.swift:250:26:250:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:262:29:262:29 | remoteString | GRDB.swift:250:26:250:80 | call to String.init(contentsOf:) : | GRDB.swift:262:29:262:29 | remoteString | This query depends on a $@. | GRDB.swift:250:26:250:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:263:29:263:29 | remoteString | GRDB.swift:250:26:250:80 | call to String.init(contentsOf:) : | GRDB.swift:263:29:263:29 | remoteString | This query depends on a $@. | GRDB.swift:250:26:250:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:264:29:264:29 | remoteString | GRDB.swift:250:26:250:80 | call to String.init(contentsOf:) : | GRDB.swift:264:29:264:29 | remoteString | This query depends on a $@. | GRDB.swift:250:26:250:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:270:29:270:29 | remoteString | GRDB.swift:250:26:250:80 | call to String.init(contentsOf:) : | GRDB.swift:270:29:270:29 | remoteString | This query depends on a $@. | GRDB.swift:250:26:250:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:271:29:271:29 | remoteString | GRDB.swift:250:26:250:80 | call to String.init(contentsOf:) : | GRDB.swift:271:29:271:29 | remoteString | This query depends on a $@. | GRDB.swift:250:26:250:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:272:29:272:29 | remoteString | GRDB.swift:250:26:250:80 | call to String.init(contentsOf:) : | GRDB.swift:272:29:272:29 | remoteString | This query depends on a $@. | GRDB.swift:250:26:250:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:273:29:273:29 | remoteString | GRDB.swift:250:26:250:80 | call to String.init(contentsOf:) : | GRDB.swift:273:29:273:29 | remoteString | This query depends on a $@. | GRDB.swift:250:26:250:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:279:29:279:29 | remoteString | GRDB.swift:250:26:250:80 | call to String.init(contentsOf:) : | GRDB.swift:279:29:279:29 | remoteString | This query depends on a $@. | GRDB.swift:250:26:250:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:280:29:280:29 | remoteString | GRDB.swift:250:26:250:80 | call to String.init(contentsOf:) : | GRDB.swift:280:29:280:29 | remoteString | This query depends on a $@. | GRDB.swift:250:26:250:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:281:29:281:29 | remoteString | GRDB.swift:250:26:250:80 | call to String.init(contentsOf:) : | GRDB.swift:281:29:281:29 | remoteString | This query depends on a $@. | GRDB.swift:250:26:250:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:282:29:282:29 | remoteString | GRDB.swift:250:26:250:80 | call to String.init(contentsOf:) : | GRDB.swift:282:29:282:29 | remoteString | This query depends on a $@. | GRDB.swift:250:26:250:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:293:53:293:53 | remoteString | GRDB.swift:291:26:291:80 | call to String.init(contentsOf:) : | GRDB.swift:293:53:293:53 | remoteString | This query depends on a $@. | GRDB.swift:291:26:291:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:294:53:294:53 | remoteString | GRDB.swift:291:26:291:80 | call to String.init(contentsOf:) : | GRDB.swift:294:53:294:53 | remoteString | This query depends on a $@. | GRDB.swift:291:26:291:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:295:53:295:53 | remoteString | GRDB.swift:291:26:291:80 | call to String.init(contentsOf:) : | GRDB.swift:295:53:295:53 | remoteString | This query depends on a $@. | GRDB.swift:291:26:291:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:296:53:296:53 | remoteString | GRDB.swift:291:26:291:80 | call to String.init(contentsOf:) : | GRDB.swift:296:53:296:53 | remoteString | This query depends on a $@. | GRDB.swift:291:26:291:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:302:50:302:50 | remoteString | GRDB.swift:291:26:291:80 | call to String.init(contentsOf:) : | GRDB.swift:302:50:302:50 | remoteString | This query depends on a $@. | GRDB.swift:291:26:291:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:303:50:303:50 | remoteString | GRDB.swift:291:26:291:80 | call to String.init(contentsOf:) : | GRDB.swift:303:50:303:50 | remoteString | This query depends on a $@. | GRDB.swift:291:26:291:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:304:50:304:50 | remoteString | GRDB.swift:291:26:291:80 | call to String.init(contentsOf:) : | GRDB.swift:304:50:304:50 | remoteString | This query depends on a $@. | GRDB.swift:291:26:291:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:305:50:305:50 | remoteString | GRDB.swift:291:26:291:80 | call to String.init(contentsOf:) : | GRDB.swift:305:50:305:50 | remoteString | This query depends on a $@. | GRDB.swift:291:26:291:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:311:50:311:50 | remoteString | GRDB.swift:291:26:291:80 | call to String.init(contentsOf:) : | GRDB.swift:311:50:311:50 | remoteString | This query depends on a $@. | GRDB.swift:291:26:291:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:312:50:312:50 | remoteString | GRDB.swift:291:26:291:80 | call to String.init(contentsOf:) : | GRDB.swift:312:50:312:50 | remoteString | This query depends on a $@. | GRDB.swift:291:26:291:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:313:50:313:50 | remoteString | GRDB.swift:291:26:291:80 | call to String.init(contentsOf:) : | GRDB.swift:313:50:313:50 | remoteString | This query depends on a $@. | GRDB.swift:291:26:291:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:314:50:314:50 | remoteString | GRDB.swift:291:26:291:80 | call to String.init(contentsOf:) : | GRDB.swift:314:50:314:50 | remoteString | This query depends on a $@. | GRDB.swift:291:26:291:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:320:50:320:50 | remoteString | GRDB.swift:291:26:291:80 | call to String.init(contentsOf:) : | GRDB.swift:320:50:320:50 | remoteString | This query depends on a $@. | GRDB.swift:291:26:291:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:321:50:321:50 | remoteString | GRDB.swift:291:26:291:80 | call to String.init(contentsOf:) : | GRDB.swift:321:50:321:50 | remoteString | This query depends on a $@. | GRDB.swift:291:26:291:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:322:50:322:50 | remoteString | GRDB.swift:291:26:291:80 | call to String.init(contentsOf:) : | GRDB.swift:322:50:322:50 | remoteString | This query depends on a $@. | GRDB.swift:291:26:291:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:323:50:323:50 | remoteString | GRDB.swift:291:26:291:80 | call to String.init(contentsOf:) : | GRDB.swift:323:50:323:50 | remoteString | This query depends on a $@. | GRDB.swift:291:26:291:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:334:57:334:57 | remoteString | GRDB.swift:332:26:332:80 | call to String.init(contentsOf:) : | GRDB.swift:334:57:334:57 | remoteString | This query depends on a $@. | GRDB.swift:332:26:332:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:335:57:335:57 | remoteString | GRDB.swift:332:26:332:80 | call to String.init(contentsOf:) : | GRDB.swift:335:57:335:57 | remoteString | This query depends on a $@. | GRDB.swift:332:26:332:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:344:51:344:51 | remoteString | GRDB.swift:342:26:342:80 | call to String.init(contentsOf:) : | GRDB.swift:344:51:344:51 | remoteString | This query depends on a $@. | GRDB.swift:342:26:342:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:345:51:345:51 | remoteString | GRDB.swift:342:26:342:80 | call to String.init(contentsOf:) : | GRDB.swift:345:51:345:51 | remoteString | This query depends on a $@. | GRDB.swift:342:26:342:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:346:66:346:66 | remoteString | GRDB.swift:342:26:342:80 | call to String.init(contentsOf:) : | GRDB.swift:346:66:346:66 | remoteString | This query depends on a $@. | GRDB.swift:342:26:342:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:347:66:347:66 | remoteString | GRDB.swift:342:26:342:80 | call to String.init(contentsOf:) : | GRDB.swift:347:66:347:66 | remoteString | This query depends on a $@. | GRDB.swift:342:26:342:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:348:69:348:69 | remoteString | GRDB.swift:342:26:342:80 | call to String.init(contentsOf:) : | GRDB.swift:348:69:348:69 | remoteString | This query depends on a $@. | GRDB.swift:342:26:342:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:349:84:349:84 | remoteString | GRDB.swift:342:26:342:80 | call to String.init(contentsOf:) : | GRDB.swift:349:84:349:84 | remoteString | This query depends on a $@. | GRDB.swift:342:26:342:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:350:69:350:69 | remoteString | GRDB.swift:342:26:342:80 | call to String.init(contentsOf:) : | GRDB.swift:350:69:350:69 | remoteString | This query depends on a $@. | GRDB.swift:342:26:342:80 | call to String.init(contentsOf:) | user-provided value |
+| GRDB.swift:351:84:351:84 | remoteString | GRDB.swift:342:26:342:80 | call to String.init(contentsOf:) : | GRDB.swift:351:84:351:84 | remoteString | This query depends on a $@. | GRDB.swift:342:26:342:80 | call to String.init(contentsOf:) | user-provided value |
| SQLite.swift:73:17:73:17 | unsafeQuery1 | SQLite.swift:62:25:62:79 | call to String.init(contentsOf:) : | SQLite.swift:73:17:73:17 | unsafeQuery1 | This query depends on a $@. | SQLite.swift:62:25:62:79 | call to String.init(contentsOf:) | user-provided value |
| SQLite.swift:74:17:74:17 | unsafeQuery2 | SQLite.swift:62:25:62:79 | call to String.init(contentsOf:) : | SQLite.swift:74:17:74:17 | unsafeQuery2 | This query depends on a $@. | SQLite.swift:62:25:62:79 | call to String.init(contentsOf:) | user-provided value |
| SQLite.swift:75:17:75:17 | unsafeQuery3 | SQLite.swift:62:25:62:79 | call to String.init(contentsOf:) : | SQLite.swift:75:17:75:17 | unsafeQuery3 | This query depends on a $@. | SQLite.swift:62:25:62:79 | call to String.init(contentsOf:) | user-provided value |
From 5fe62e293acb20518919691497eb66570c9cc3cf Mon Sep 17 00:00:00 2001
From: Rasmus Lerchedahl Petersen
Date: Mon, 9 Jan 2023 17:45:50 +0100
Subject: [PATCH 137/381] python: fix bug, add clarifying comment
---
.../ql/src/experimental/Security/CWE-022bis/TarSlipImprov.ql | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/python/ql/src/experimental/Security/CWE-022bis/TarSlipImprov.ql b/python/ql/src/experimental/Security/CWE-022bis/TarSlipImprov.ql
index 80462fc91c0..0fa3580c1a0 100755
--- a/python/ql/src/experimental/Security/CWE-022bis/TarSlipImprov.ql
+++ b/python/ql/src/experimental/Security/CWE-022bis/TarSlipImprov.ql
@@ -107,10 +107,13 @@ class Configuration extends TaintTracking::Configuration {
nodeTo = call
)
or
+ // To handle the case of `with closing(tarfile.open()) as file:`
+ // we add a step from the first argument of `closing` to the call to `closing`,
+ // whenever that first argument is a return of `tarfile.open()`.
exists(API::CallNode closing |
closing = API::moduleImport("contextlib").getMember("closing").getACall() and
nodeFrom = closing.getArg(0) and
- nodeFrom = tarfileOpen().getReturn().getAValueReachingSink() and
+ nodeFrom = tarfileOpen().getReturn().getAValueReachableFromSource() and
nodeTo = closing
)
}
From c142495a8bdfb24cea962d0fb7362d0c6b067ce6 Mon Sep 17 00:00:00 2001
From: Rasmus Lerchedahl Petersen
Date: Mon, 9 Jan 2023 17:51:45 +0100
Subject: [PATCH 138/381] python: simplify code
---
.../Security/CWE-022bis/TarSlipImprov.ql | 17 +++++------------
1 file changed, 5 insertions(+), 12 deletions(-)
diff --git a/python/ql/src/experimental/Security/CWE-022bis/TarSlipImprov.ql b/python/ql/src/experimental/Security/CWE-022bis/TarSlipImprov.ql
index 0fa3580c1a0..175d5fd85f1 100755
--- a/python/ql/src/experimental/Security/CWE-022bis/TarSlipImprov.ql
+++ b/python/ql/src/experimental/Security/CWE-022bis/TarSlipImprov.ql
@@ -100,22 +100,15 @@ class Configuration extends TaintTracking::Configuration {
}
override predicate isAdditionalTaintStep(DataFlow::Node nodeFrom, DataFlow::Node nodeTo) {
- exists(AttrRead attr, MethodCallNode call |
- attr.accesses(nodeFrom, "getmembers") and
- nodeFrom = call.getObject() and
- nodeFrom instanceof AllTarfileOpens and
- nodeTo = call
- )
+ nodeTo.(MethodCallNode).calls(nodeFrom, "getmembers") and
+ nodeFrom instanceof AllTarfileOpens
or
// To handle the case of `with closing(tarfile.open()) as file:`
// we add a step from the first argument of `closing` to the call to `closing`,
// whenever that first argument is a return of `tarfile.open()`.
- exists(API::CallNode closing |
- closing = API::moduleImport("contextlib").getMember("closing").getACall() and
- nodeFrom = closing.getArg(0) and
- nodeFrom = tarfileOpen().getReturn().getAValueReachableFromSource() and
- nodeTo = closing
- )
+ nodeTo = API::moduleImport("contextlib").getMember("closing").getACall() and
+ nodeFrom = nodeTo.(API::CallNode).getArg(0) and
+ nodeFrom = tarfileOpen().getReturn().getAValueReachableFromSource()
}
}
From aad56097ac93e1b5c7d217d91e201e1f6141dd79 Mon Sep 17 00:00:00 2001
From: Tony Torralba
Date: Wed, 30 Nov 2022 13:04:10 +0100
Subject: [PATCH 139/381] Add Cleartext Loggin query for Swift.
With some caveats: see TODO comments and failing tests.
---
.../codeql/swift/dataflow/ExternalFlow.qll | 1 +
.../swift/security/CleartextLogging.qll | 67 +++++++++
.../swift/security/CleartextLoggingQuery.qll | 32 +++++
.../Security/CWE-312/CleartextLogging.qhelp | 50 +++++++
.../Security/CWE-312/CleartextLogging.ql | 24 ++++
.../CWE-312/CleartextLoggingBad.swift | 0
.../CWE-312/CleartextLoggingGood.swift | 0
.../CWE-312/CleartextLoggingTest.expected | 0
.../Security/CWE-312/CleartextLoggingTest.ql | 24 ++++
.../CWE-312/cleartextLoggingTest.swift | 130 ++++++++++++++++++
10 files changed, 328 insertions(+)
create mode 100644 swift/ql/lib/codeql/swift/security/CleartextLogging.qll
create mode 100644 swift/ql/lib/codeql/swift/security/CleartextLoggingQuery.qll
create mode 100644 swift/ql/src/queries/Security/CWE-312/CleartextLogging.qhelp
create mode 100644 swift/ql/src/queries/Security/CWE-312/CleartextLogging.ql
create mode 100644 swift/ql/src/queries/Security/CWE-312/CleartextLoggingBad.swift
create mode 100644 swift/ql/src/queries/Security/CWE-312/CleartextLoggingGood.swift
create mode 100644 swift/ql/test/query-tests/Security/CWE-312/CleartextLoggingTest.expected
create mode 100644 swift/ql/test/query-tests/Security/CWE-312/CleartextLoggingTest.ql
create mode 100644 swift/ql/test/query-tests/Security/CWE-312/cleartextLoggingTest.swift
diff --git a/swift/ql/lib/codeql/swift/dataflow/ExternalFlow.qll b/swift/ql/lib/codeql/swift/dataflow/ExternalFlow.qll
index 2c90d1e7351..60f8bc9782b 100644
--- a/swift/ql/lib/codeql/swift/dataflow/ExternalFlow.qll
+++ b/swift/ql/lib/codeql/swift/dataflow/ExternalFlow.qll
@@ -89,6 +89,7 @@ private module Frameworks {
private import codeql.swift.frameworks.StandardLibrary.UrlSession
private import codeql.swift.frameworks.StandardLibrary.WebView
private import codeql.swift.frameworks.Alamofire.Alamofire
+ private import codeql.swift.security.CleartextLogging
private import codeql.swift.security.PathInjection
private import codeql.swift.security.PredicateInjection
}
diff --git a/swift/ql/lib/codeql/swift/security/CleartextLogging.qll b/swift/ql/lib/codeql/swift/security/CleartextLogging.qll
new file mode 100644
index 00000000000..9e5e551effd
--- /dev/null
+++ b/swift/ql/lib/codeql/swift/security/CleartextLogging.qll
@@ -0,0 +1,67 @@
+/** Provides classes and predicates to reason about cleartext logging of sensitive data vulnerabilities. */
+
+import swift
+private import codeql.swift.dataflow.DataFlow
+private import codeql.swift.dataflow.ExternalFlow
+private import codeql.swift.security.SensitiveExprs
+
+/** A data flow sink for cleartext logging of sensitive data vulnerabilities. */
+abstract class CleartextLoggingSink extends DataFlow::Node { }
+
+/** A sanitizer for cleartext logging of sensitive data vulnerabilities. */
+abstract class CleartextLoggingSanitizer extends DataFlow::Node { }
+
+/**
+ * A unit class for adding additional taint steps.
+ *
+ * Extend this class to add additional taint steps that should apply to paths related to
+ * cleartext logging of sensitive data vulnerabilities.
+ */
+class CleartextLoggingAdditionalTaintStep extends Unit {
+ /**
+ * Holds if the step from `n1` to `n2` should be considered a taint
+ * step for flows related to cleartext logging of sensitive data vulnerabilities.
+ */
+ abstract predicate step(DataFlow::Node n1, DataFlow::Node n2);
+}
+
+private class DefaultCleartextLoggingSink extends CleartextLoggingSink {
+ DefaultCleartextLoggingSink() { sinkNode(this, "logging") }
+}
+
+// TODO: Remove this. It shouldn't be necessary.
+private class EncryptionCleartextLoggingSanitizer extends CleartextLoggingSanitizer {
+ EncryptionCleartextLoggingSanitizer() { this.asExpr() instanceof EncryptedExpr }
+}
+
+/*
+ * TODO: Add a sanitizer for the OsLogMessage interpolation with .private/.sensitive privacy options,
+ * or restrict the sinks to require .public interpolation depending on what the default behavior is.
+ */
+
+private class LoggingSinks extends SinkModelCsv {
+ override predicate row(string row) {
+ row =
+ [
+ ";;false;print(_:separator:terminator:);;;Argument[0].ArrayElement;logging",
+ ";;false;print(_:separator:terminator:);;;Argument[1..2];logging",
+ ";;false;print(_:separator:terminator:toStream:);;;Argument[0].ArrayElement;logging",
+ ";;false;print(_:separator:terminator:toStream:);;;Argument[1..2];logging",
+ ";;false;NSLog(_:_:);;;Argument[0];logging",
+ ";;false;NSLog(_:_:);;;Argument[1].ArrayElement;logging",
+ ";;false;NSLogv(_:_:);;;Argument[0];logging",
+ ";;false;NSLogv(_:_:);;;Argument[1].ArrayElement;logging",
+ ";;false;vfprintf(_:_:_:);;;Agument[1..2];logging",
+ ";Logger;true;log(_:);;;Argument[0];logging",
+ ";Logger;true;log(level:_:);;;Argument[1];logging",
+ ";Logger;true;trace(_:);;;Argument[1];logging",
+ ";Logger;true;debug(_:);;;Argument[1];logging",
+ ";Logger;true;info(_:);;;Argument[1];logging",
+ ";Logger;true;notice(_:);;;Argument[1];logging",
+ ";Logger;true;warning(_:);;;Argument[1];logging",
+ ";Logger;true;error(_:);;;Argument[1];logging",
+ ";Logger;true;critical(_:);;;Argument[1];logging",
+ ";Logger;true;fault(_:);;;Argument[1];logging",
+ ]
+ }
+}
diff --git a/swift/ql/lib/codeql/swift/security/CleartextLoggingQuery.qll b/swift/ql/lib/codeql/swift/security/CleartextLoggingQuery.qll
new file mode 100644
index 00000000000..d67f66e74b9
--- /dev/null
+++ b/swift/ql/lib/codeql/swift/security/CleartextLoggingQuery.qll
@@ -0,0 +1,32 @@
+/**
+ * Provides a taint-tracking configuration for reasoning about cleartext logging of
+ * sensitive data vulnerabilities.
+ */
+
+import swift
+private import codeql.swift.dataflow.DataFlow
+private import codeql.swift.dataflow.TaintTracking
+private import codeql.swift.security.CleartextLogging
+private import codeql.swift.security.SensitiveExprs
+
+/**
+ * A taint-tracking configuration for cleartext logging of sensitive data vulnerabilities.
+ */
+class CleartextLoggingConfiguration extends TaintTracking::Configuration {
+ CleartextLoggingConfiguration() { this = "CleartextLoggingConfiguration" }
+
+ override predicate isSource(DataFlow::Node source) { source.asExpr() instanceof SensitiveExpr }
+
+ override predicate isSink(DataFlow::Node sink) { sink instanceof CleartextLoggingSink }
+
+ override predicate isSanitizer(DataFlow::Node sanitizer) {
+ sanitizer instanceof CleartextLoggingSanitizer
+ }
+
+ // Disregard paths that contain other paths. This helps with performance.
+ override predicate isSanitizerIn(DataFlow::Node node) { this.isSource(node) }
+
+ override predicate isAdditionalTaintStep(DataFlow::Node n1, DataFlow::Node n2) {
+ any(CleartextLoggingAdditionalTaintStep s).step(n1, n2)
+ }
+}
diff --git a/swift/ql/src/queries/Security/CWE-312/CleartextLogging.qhelp b/swift/ql/src/queries/Security/CWE-312/CleartextLogging.qhelp
new file mode 100644
index 00000000000..fc5c7ed6f5e
--- /dev/null
+++ b/swift/ql/src/queries/Security/CWE-312/CleartextLogging.qhelp
@@ -0,0 +1,50 @@
+
+
+
+
+
+Sensitive information that is logged unencrypted is accessible to an attacker
+who gains access to the logs.
+
+
+
+
+
+Ensure that sensitive information is always encrypted or obfuscated before being
+logged.
+
+
+
+In general, decrypt sensitive information only at the point where it is
+necessary for it to be used in cleartext.
+
+
+
+Be aware that external processes often store the standard out and
+standard error streams of the application, causing logged sensitive
+information to be stored.
+
+
+
+
+
+The following example code logs user credentials (in this case, their password)
+in plain text:
+
+
+
+Instead, the credentials should be encrypted, obfuscated, or omitted entirely:
+
+
+
+
+
+
+
M. Dowd, J. McDonald and J. Schuhm, The Art of Software Security Assessment, 1st Edition, Chapter 2 - 'Common Vulnerabilities of Encryption', p. 43. Addison Wesley, 2006.
+
M. Howard and D. LeBlanc, Writing Secure Code, 2nd Edition, Chapter 9 - 'Protecting Secret Data', p. 299. Microsoft, 2002.
-When a library function dynamically constructs code in a potentially unsafe way, then
+When a library function dynamically constructs code in a potentially unsafe way,
it's important to document to clients of the library that the function should only be
used with trusted inputs.
@@ -35,7 +35,7 @@ then an attacker might be able to execute arbitrary code on the system.
To avoid this problem, either properly document that the function is potentially
-unsafe, or use an alternative solution such as JSON.parse or another library, like in the examples below,
+unsafe, or use an alternative solution such as JSON.parse or another library
that does not allow arbitrary code to be executed.
From 23a847b1cfca06e56c3962d8ea06798dfba9f92f Mon Sep 17 00:00:00 2001
From: erik-krogh
Date: Tue, 10 Jan 2023 10:10:36 +0100
Subject: [PATCH 152/381] track shell:true more in
js/shell-command-constructed-from-input
---
.../ql/lib/semmle/javascript/ApiGraphs.qll | 7 ++++++-
...eShellCommandConstructionCustomizations.qll | 5 +++++
.../UnsafeShellCommandConstruction.expected | 18 ++++++++++++++++++
.../UnsafeShellCommandConstruction/lib/lib.js | 9 +++++++++
4 files changed, 38 insertions(+), 1 deletion(-)
diff --git a/javascript/ql/lib/semmle/javascript/ApiGraphs.qll b/javascript/ql/lib/semmle/javascript/ApiGraphs.qll
index 3e708098635..a9c8bca2345 100644
--- a/javascript/ql/lib/semmle/javascript/ApiGraphs.qll
+++ b/javascript/ql/lib/semmle/javascript/ApiGraphs.qll
@@ -210,7 +210,12 @@ module API {
* This is similar to `asSink()` but additionally includes nodes that transitively reach a sink by data flow.
* See `asSink()` for examples.
*/
- DataFlow::Node getAValueReachingSink() { result = Impl::trackDefNode(this.asSink()) }
+ DataFlow::Node getAValueReachingSink() {
+ result = Impl::trackDefNode(this.asSink())
+ or
+ // in case `asSink()` is not a `SourceNode`.
+ result = asSink()
+ }
/** DEPRECATED. This predicate has been renamed to `asSink`. */
deprecated DataFlow::Node getARhs() { result = this.asSink() }
diff --git a/javascript/ql/lib/semmle/javascript/security/dataflow/UnsafeShellCommandConstructionCustomizations.qll b/javascript/ql/lib/semmle/javascript/security/dataflow/UnsafeShellCommandConstructionCustomizations.qll
index ca6920db466..6a2b4d94f35 100644
--- a/javascript/ql/lib/semmle/javascript/security/dataflow/UnsafeShellCommandConstructionCustomizations.qll
+++ b/javascript/ql/lib/semmle/javascript/security/dataflow/UnsafeShellCommandConstructionCustomizations.qll
@@ -166,6 +166,11 @@ module UnsafeShellCommandConstruction {
.asExpr()
.(BooleanLiteral)
.getValue() = "true"
+ or
+ exists(API::Node node |
+ node.asSink() = sys.getOptionsArg() and
+ node.getMember("shell").getAValueReachingSink().mayHaveBooleanValue(true)
+ )
}
/**
diff --git a/javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction/UnsafeShellCommandConstruction.expected b/javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction/UnsafeShellCommandConstruction.expected
index de11fb884c9..92cca128c59 100644
--- a/javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction/UnsafeShellCommandConstruction.expected
+++ b/javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction/UnsafeShellCommandConstruction.expected
@@ -282,6 +282,14 @@ nodes
| lib/lib.js:543:23:543:26 | name |
| lib/lib.js:545:23:545:26 | name |
| lib/lib.js:545:23:545:26 | name |
+| lib/lib.js:550:39:550:42 | name |
+| lib/lib.js:550:39:550:42 | name |
+| lib/lib.js:551:33:551:36 | args |
+| lib/lib.js:552:23:552:26 | args |
+| lib/lib.js:552:23:552:26 | args |
+| lib/lib.js:555:25:555:37 | ["-rf", name] |
+| lib/lib.js:555:33:555:36 | name |
+| lib/lib.js:555:33:555:36 | name |
| lib/subLib2/compiled-file.ts:3:26:3:29 | name |
| lib/subLib2/compiled-file.ts:3:26:3:29 | name |
| lib/subLib2/compiled-file.ts:4:25:4:28 | name |
@@ -659,6 +667,14 @@ edges
| lib/lib.js:509:39:509:42 | name | lib/lib.js:545:23:545:26 | name |
| lib/lib.js:509:39:509:42 | name | lib/lib.js:545:23:545:26 | name |
| lib/lib.js:509:39:509:42 | name | lib/lib.js:545:23:545:26 | name |
+| lib/lib.js:550:39:550:42 | name | lib/lib.js:555:33:555:36 | name |
+| lib/lib.js:550:39:550:42 | name | lib/lib.js:555:33:555:36 | name |
+| lib/lib.js:550:39:550:42 | name | lib/lib.js:555:33:555:36 | name |
+| lib/lib.js:550:39:550:42 | name | lib/lib.js:555:33:555:36 | name |
+| lib/lib.js:551:33:551:36 | args | lib/lib.js:552:23:552:26 | args |
+| lib/lib.js:551:33:551:36 | args | lib/lib.js:552:23:552:26 | args |
+| lib/lib.js:555:25:555:37 | ["-rf", name] | lib/lib.js:551:33:551:36 | args |
+| lib/lib.js:555:33:555:36 | name | lib/lib.js:555:25:555:37 | ["-rf", name] |
| lib/subLib2/compiled-file.ts:3:26:3:29 | name | lib/subLib2/compiled-file.ts:4:25:4:28 | name |
| lib/subLib2/compiled-file.ts:3:26:3:29 | name | lib/subLib2/compiled-file.ts:4:25:4:28 | name |
| lib/subLib2/compiled-file.ts:3:26:3:29 | name | lib/subLib2/compiled-file.ts:4:25:4:28 | name |
@@ -775,6 +791,8 @@ edges
| lib/lib.js:537:11:537:26 | "rm -rf " + name | lib/lib.js:509:39:509:42 | name | lib/lib.js:537:23:537:26 | name | This string concatenation which depends on $@ is later used in a $@. | lib/lib.js:509:39:509:42 | name | library input | lib/lib.js:537:3:537:27 | cp.exec ... + name) | shell command |
| lib/lib.js:543:11:543:26 | "rm -rf " + name | lib/lib.js:509:39:509:42 | name | lib/lib.js:543:23:543:26 | name | This string concatenation which depends on $@ is later used in a $@. | lib/lib.js:509:39:509:42 | name | library input | lib/lib.js:543:3:543:27 | cp.exec ... + name) | shell command |
| lib/lib.js:545:11:545:26 | "rm -rf " + name | lib/lib.js:509:39:509:42 | name | lib/lib.js:545:23:545:26 | name | This string concatenation which depends on $@ is later used in a $@. | lib/lib.js:509:39:509:42 | name | library input | lib/lib.js:545:3:545:27 | cp.exec ... + name) | shell command |
+| lib/lib.js:552:23:552:26 | args | lib/lib.js:550:39:550:42 | name | lib/lib.js:552:23:552:26 | args | This shell argument which depends on $@ is later used in a $@. | lib/lib.js:550:39:550:42 | name | library input | lib/lib.js:552:9:552:38 | cp.spaw ... wnOpts) | shell command |
+| lib/lib.js:555:33:555:36 | name | lib/lib.js:550:39:550:42 | name | lib/lib.js:555:33:555:36 | name | This shell argument which depends on $@ is later used in a $@. | lib/lib.js:550:39:550:42 | name | library input | lib/lib.js:552:9:552:38 | cp.spaw ... wnOpts) | shell command |
| lib/subLib2/compiled-file.ts:4:13:4:28 | "rm -rf " + name | lib/subLib2/compiled-file.ts:3:26:3:29 | name | lib/subLib2/compiled-file.ts:4:25:4:28 | name | This string concatenation which depends on $@ is later used in a $@. | lib/subLib2/compiled-file.ts:3:26:3:29 | name | library input | lib/subLib2/compiled-file.ts:4:5:4:29 | cp.exec ... + name) | shell command |
| lib/subLib2/special-file.js:4:10:4:25 | "rm -rf " + name | lib/subLib2/special-file.js:3:28:3:31 | name | lib/subLib2/special-file.js:4:22:4:25 | name | This string concatenation which depends on $@ is later used in a $@. | lib/subLib2/special-file.js:3:28:3:31 | name | library input | lib/subLib2/special-file.js:4:2:4:26 | cp.exec ... + name) | shell command |
| lib/subLib3/my-file.ts:4:10:4:25 | "rm -rf " + name | lib/subLib3/my-file.ts:3:28:3:31 | name | lib/subLib3/my-file.ts:4:22:4:25 | name | This string concatenation which depends on $@ is later used in a $@. | lib/subLib3/my-file.ts:3:28:3:31 | name | library input | lib/subLib3/my-file.ts:4:2:4:26 | cp.exec ... + name) | shell command |
diff --git a/javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction/lib/lib.js b/javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction/lib/lib.js
index 64b279d7d05..728ddbfa91e 100644
--- a/javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction/lib/lib.js
+++ b/javascript/ql/test/query-tests/Security/CWE-078/UnsafeShellCommandConstruction/lib/lib.js
@@ -545,3 +545,12 @@ module.exports.sanitizer4 = function (name) {
cp.exec("rm -rf " + name); // NOT OK
}
}
+
+
+module.exports.shellThing = function (name) {
+ function indirectShell(cmd, args, spawnOpts) {
+ cp.spawn(cmd, args, spawnOpts); // NOT OK
+ }
+
+ indirectShell("rm", ["-rf", name], {shell: true});
+}
\ No newline at end of file
From 43696f5e27db5495d35259099c0a3328e7953a56 Mon Sep 17 00:00:00 2001
From: erik-krogh
Date: Tue, 10 Jan 2023 10:24:19 +0100
Subject: [PATCH 153/381] add explicit this
---
javascript/ql/lib/semmle/javascript/ApiGraphs.qll | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/javascript/ql/lib/semmle/javascript/ApiGraphs.qll b/javascript/ql/lib/semmle/javascript/ApiGraphs.qll
index a9c8bca2345..80a5487943a 100644
--- a/javascript/ql/lib/semmle/javascript/ApiGraphs.qll
+++ b/javascript/ql/lib/semmle/javascript/ApiGraphs.qll
@@ -214,7 +214,7 @@ module API {
result = Impl::trackDefNode(this.asSink())
or
// in case `asSink()` is not a `SourceNode`.
- result = asSink()
+ result = this.asSink()
}
/** DEPRECATED. This predicate has been renamed to `asSink`. */
From f7d8d16ed3fc3e5c673d547f6866aab9faaf74ad Mon Sep 17 00:00:00 2001
From: Ian Lynagh
Date: Mon, 21 Nov 2022 19:56:22 +0000
Subject: [PATCH 154/381] Kotlin: Fix build for 1.8.0-Beta
The build no longer works for Kotlin < 1.8: We get
error: class 'org.jetbrains.kotlin.ir.IrElement' was compiled
with an incompatible version of Kotlin. The binary version
of its metadata is 1.8.0, expected version is 1.6.0.
---
.../kotlin_plugin_versions.py | 2 +-
.../KotlinExtractorCommandLineProcessor.kt | 2 ++
.../KotlinExtractorComponentRegistrar.kt | 5 +++
.../src/main/kotlin/KotlinFileExtractor.kt | 8 +++--
.../src/main/kotlin/KotlinUsesExtractor.kt | 10 +++---
.../src/main/kotlin/PrimitiveTypeInfo.kt | 3 +-
.../src/main/kotlin/utils/GetByFqName.kt | 33 +++++++++++++++++++
.../v_1_4_32/ExperimentalCompilerApi.kt | 4 +++
.../v_1_4_32/FirIncompatiblePluginAPI.kt | 5 +++
.../v_1_8_0-Beta/ExperimentalCompilerApi.kt | 4 +++
.../v_1_8_0-Beta/FirIncompatiblePluginAPI.kt | 4 +++
11 files changed, 71 insertions(+), 9 deletions(-)
create mode 100644 java/kotlin-extractor/src/main/kotlin/utils/GetByFqName.kt
create mode 100644 java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_4_32/ExperimentalCompilerApi.kt
create mode 100644 java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_4_32/FirIncompatiblePluginAPI.kt
create mode 100644 java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_8_0-Beta/ExperimentalCompilerApi.kt
create mode 100644 java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_8_0-Beta/FirIncompatiblePluginAPI.kt
diff --git a/java/kotlin-extractor/kotlin_plugin_versions.py b/java/kotlin-extractor/kotlin_plugin_versions.py
index 99691b89fd2..1081883479c 100755
--- a/java/kotlin-extractor/kotlin_plugin_versions.py
+++ b/java/kotlin-extractor/kotlin_plugin_versions.py
@@ -25,7 +25,7 @@ def version_string_to_tuple(version):
ci_version = '1.7.20'
# Version numbers in the list need to be in semantically increasing order
-many_versions = [ '1.4.32', '1.5.0', '1.5.10', '1.5.20', '1.5.30', '1.6.0', '1.6.20', '1.7.0', '1.7.20' ]
+many_versions = [ '1.4.32', '1.5.0', '1.5.10', '1.5.20', '1.5.30', '1.6.0', '1.6.20', '1.7.0', '1.7.20', '1.8.0-Beta' ]
many_versions_tuples = [version_string_to_tuple(v) for v in many_versions]
diff --git a/java/kotlin-extractor/src/main/kotlin/KotlinExtractorCommandLineProcessor.kt b/java/kotlin-extractor/src/main/kotlin/KotlinExtractorCommandLineProcessor.kt
index 5c29d6af54e..f110d48231f 100644
--- a/java/kotlin-extractor/src/main/kotlin/KotlinExtractorCommandLineProcessor.kt
+++ b/java/kotlin-extractor/src/main/kotlin/KotlinExtractorCommandLineProcessor.kt
@@ -3,9 +3,11 @@ package com.github.codeql
import org.jetbrains.kotlin.compiler.plugin.AbstractCliOption
import org.jetbrains.kotlin.compiler.plugin.CliOption
import org.jetbrains.kotlin.compiler.plugin.CommandLineProcessor
+import org.jetbrains.kotlin.compiler.plugin.ExperimentalCompilerApi
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.CompilerConfigurationKey
+@OptIn(ExperimentalCompilerApi::class)
class KotlinExtractorCommandLineProcessor : CommandLineProcessor {
override val pluginId = "kotlin-extractor"
diff --git a/java/kotlin-extractor/src/main/kotlin/KotlinExtractorComponentRegistrar.kt b/java/kotlin-extractor/src/main/kotlin/KotlinExtractorComponentRegistrar.kt
index daee156d58c..f2f22390eb3 100644
--- a/java/kotlin-extractor/src/main/kotlin/KotlinExtractorComponentRegistrar.kt
+++ b/java/kotlin-extractor/src/main/kotlin/KotlinExtractorComponentRegistrar.kt
@@ -1,10 +1,15 @@
+// For ComponentRegistrar
+@file:Suppress("DEPRECATION")
+
package com.github.codeql
import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
+import org.jetbrains.kotlin.compiler.plugin.ExperimentalCompilerApi
import com.intellij.mock.MockProject
import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar
import org.jetbrains.kotlin.config.CompilerConfiguration
+@OptIn(ExperimentalCompilerApi::class)
class KotlinExtractorComponentRegistrar : ComponentRegistrar {
override fun registerProjectComponents(
project: MockProject,
diff --git a/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt b/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt
index 5990fb3389d..99eacabb25e 100644
--- a/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt
+++ b/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt
@@ -1709,6 +1709,10 @@ open class KotlinFileExtractor(
when (b.kind) {
IrSyntheticBodyKind.ENUM_VALUES -> tw.writeKtSyntheticBody(callable, 1)
IrSyntheticBodyKind.ENUM_VALUEOF -> tw.writeKtSyntheticBody(callable, 2)
+ else -> {
+ // TODO: Support IrSyntheticBodyKind.ENUM_ENTRIES
+ logger.errorElement("Unhandled synthetic body kind " + b.kind.javaClass, b)
+ }
}
}
}
@@ -2400,7 +2404,7 @@ open class KotlinFileExtractor(
private fun findTopLevelFunctionOrWarn(functionFilter: String, type: String, parameterTypes: Array, warnAgainstElement: IrElement): IrFunction? {
- val fn = pluginContext.referenceFunctions(FqName(functionFilter))
+ val fn = getFunctionsByFqName(pluginContext, functionFilter)
.firstOrNull { fnSymbol ->
fnSymbol.owner.parentClassOrNull?.fqNameWhenAvailable?.asString() == type &&
fnSymbol.owner.valueParameters.map { it.type.classFqName?.asString() }.toTypedArray() contentEquals parameterTypes
@@ -2419,7 +2423,7 @@ open class KotlinFileExtractor(
private fun findTopLevelPropertyOrWarn(propertyFilter: String, type: String, warnAgainstElement: IrElement): IrProperty? {
- val prop = pluginContext.referenceProperties(FqName(propertyFilter))
+ val prop = getPropertiesByFqName(pluginContext, propertyFilter)
.firstOrNull { it.owner.parentClassOrNull?.fqNameWhenAvailable?.asString() == type }
?.owner
diff --git a/java/kotlin-extractor/src/main/kotlin/KotlinUsesExtractor.kt b/java/kotlin-extractor/src/main/kotlin/KotlinUsesExtractor.kt
index fe55fdba256..92fc961dd0f 100644
--- a/java/kotlin-extractor/src/main/kotlin/KotlinUsesExtractor.kt
+++ b/java/kotlin-extractor/src/main/kotlin/KotlinUsesExtractor.kt
@@ -41,7 +41,7 @@ open class KotlinUsesExtractor(
val globalExtensionState: KotlinExtractorGlobalState
) {
fun referenceExternalClass(name: String) =
- pluginContext.referenceClass(FqName(name))?.owner.also {
+ getClassByFqName(pluginContext, FqName(name))?.owner.also {
if (it == null)
logger.warn("Unable to resolve external class $name")
else
@@ -118,7 +118,7 @@ open class KotlinUsesExtractor(
}
fun getJavaEquivalentClass(c: IrClass) =
- getJavaEquivalentClassId(c)?.let { pluginContext.referenceClass(it.asSingleFqName()) }?.owner
+ getJavaEquivalentClassId(c)?.let { getClassByFqName(pluginContext, it.asSingleFqName()) }?.owner
/**
* Gets a KotlinFileExtractor based on this one, except it attributes locations to the file that declares the given class.
@@ -328,7 +328,7 @@ open class KotlinUsesExtractor(
return@getOrPut null
}
- val result = pluginContext.referenceClass(qualifiedName)?.owner
+ val result = getClassByFqName(pluginContext, qualifiedName)?.owner
if (result != null) {
logger.info("Replaced synthetic class ${c.name} with its real equivalent")
return@getOrPut result
@@ -337,7 +337,7 @@ open class KotlinUsesExtractor(
// The above doesn't work for (some) generated nested classes, such as R$id, which should be R.id
val fqn = qualifiedName.asString()
if (fqn.indexOf('$') >= 0) {
- val nested = pluginContext.referenceClass(FqName(fqn.replace('$', '.')))?.owner
+ val nested = getClassByFqName(pluginContext, fqn.replace('$', '.'))?.owner
if (nested != null) {
logger.info("Replaced synthetic nested class ${c.name} with its real equivalent")
return@getOrPut nested
@@ -454,7 +454,7 @@ open class KotlinUsesExtractor(
}
fun tryGetPair(arity: Int): Pair?>? {
- val replaced = pluginContext.referenceClass(fqName)?.owner ?: return null
+ val replaced = getClassByFqName(pluginContext, fqName)?.owner ?: return null
return Pair(replaced, List(arity) { makeTypeProjection(pluginContext.irBuiltIns.anyNType, Variance.INVARIANT) })
}
diff --git a/java/kotlin-extractor/src/main/kotlin/PrimitiveTypeInfo.kt b/java/kotlin-extractor/src/main/kotlin/PrimitiveTypeInfo.kt
index 8d844a65ec8..a14b0c138db 100644
--- a/java/kotlin-extractor/src/main/kotlin/PrimitiveTypeInfo.kt
+++ b/java/kotlin-extractor/src/main/kotlin/PrimitiveTypeInfo.kt
@@ -7,6 +7,7 @@ import org.jetbrains.kotlin.ir.declarations.IrPackageFragment
import org.jetbrains.kotlin.ir.types.IrSimpleType
import org.jetbrains.kotlin.ir.types.classOrNull
import org.jetbrains.kotlin.name.FqName
+import com.github.codeql.utils.*
class PrimitiveTypeMapping(val logger: Logger, val pluginContext: IrPluginContext) {
fun getPrimitiveInfo(s: IrSimpleType) =
@@ -25,7 +26,7 @@ class PrimitiveTypeMapping(val logger: Logger, val pluginContext: IrPluginContex
)
private fun findClass(fqName: String, fallback: IrClass): IrClass {
- val symbol = pluginContext.referenceClass(FqName(fqName))
+ val symbol = getClassByFqName(pluginContext, fqName)
if(symbol == null) {
logger.warn("Can't find $fqName")
// Do the best we can
diff --git a/java/kotlin-extractor/src/main/kotlin/utils/GetByFqName.kt b/java/kotlin-extractor/src/main/kotlin/utils/GetByFqName.kt
new file mode 100644
index 00000000000..0d1b63bf0f2
--- /dev/null
+++ b/java/kotlin-extractor/src/main/kotlin/utils/GetByFqName.kt
@@ -0,0 +1,33 @@
+package com.github.codeql.utils
+
+import org.jetbrains.kotlin.backend.common.extensions.FirIncompatiblePluginAPI
+import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
+import org.jetbrains.kotlin.ir.symbols.*
+import org.jetbrains.kotlin.name.FqName
+
+fun getClassByFqName(pluginContext: IrPluginContext, fqName: String): IrClassSymbol? {
+ return getClassByFqName(pluginContext, FqName(fqName))
+}
+
+fun getClassByFqName(pluginContext: IrPluginContext, fqName: FqName): IrClassSymbol? {
+ @OptIn(FirIncompatiblePluginAPI::class)
+ return pluginContext.referenceClass(fqName)
+}
+
+fun getFunctionsByFqName(pluginContext: IrPluginContext, fqName: String): Collection {
+ return getFunctionsByFqName(pluginContext, FqName(fqName))
+}
+
+fun getFunctionsByFqName(pluginContext: IrPluginContext, fqName: FqName): Collection {
+ @OptIn(FirIncompatiblePluginAPI::class)
+ return pluginContext.referenceFunctions(fqName)
+}
+
+fun getPropertiesByFqName(pluginContext: IrPluginContext, fqName: String): Collection {
+ return getPropertiesByFqName(pluginContext, FqName(fqName))
+}
+
+fun getPropertiesByFqName(pluginContext: IrPluginContext, fqName: FqName): Collection {
+ @OptIn(FirIncompatiblePluginAPI::class)
+ return pluginContext.referenceProperties(fqName)
+}
diff --git a/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_4_32/ExperimentalCompilerApi.kt b/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_4_32/ExperimentalCompilerApi.kt
new file mode 100644
index 00000000000..9b40a26bc51
--- /dev/null
+++ b/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_4_32/ExperimentalCompilerApi.kt
@@ -0,0 +1,4 @@
+package org.jetbrains.kotlin.compiler.plugin
+
+@RequiresOptIn("This API is experimental. There are no stability guarantees for it")
+annotation class ExperimentalCompilerApi
diff --git a/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_4_32/FirIncompatiblePluginAPI.kt b/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_4_32/FirIncompatiblePluginAPI.kt
new file mode 100644
index 00000000000..45d573da9c7
--- /dev/null
+++ b/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_4_32/FirIncompatiblePluginAPI.kt
@@ -0,0 +1,5 @@
+package org.jetbrains.kotlin.backend.common.extensions
+
+@RequiresOptIn("This API is not available after FIR")
+annotation class FirIncompatiblePluginAPI
+
diff --git a/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_8_0-Beta/ExperimentalCompilerApi.kt b/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_8_0-Beta/ExperimentalCompilerApi.kt
new file mode 100644
index 00000000000..48829cc30c5
--- /dev/null
+++ b/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_8_0-Beta/ExperimentalCompilerApi.kt
@@ -0,0 +1,4 @@
+package com.github.codeql
+
+// The compiler provides the annotation class, so we don't need to do
+// anything
diff --git a/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_8_0-Beta/FirIncompatiblePluginAPI.kt b/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_8_0-Beta/FirIncompatiblePluginAPI.kt
new file mode 100644
index 00000000000..48829cc30c5
--- /dev/null
+++ b/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_8_0-Beta/FirIncompatiblePluginAPI.kt
@@ -0,0 +1,4 @@
+package com.github.codeql
+
+// The compiler provides the annotation class, so we don't need to do
+// anything
From 6fbda1a9f0c2d8e9e5184932df483ef851792438 Mon Sep 17 00:00:00 2001
From: Ian Lynagh
Date: Thu, 8 Dec 2022 19:19:16 +0000
Subject: [PATCH 155/381] Kotlin: Accept test changes with 1.8
---
java/ql/test/kotlin/library-tests/enum/test.expected | 5 +++++
.../library-tests/java-lang-number-conversions/test.expected | 1 +
.../test/kotlin/library-tests/reflection/reflection.expected | 5 +++++
3 files changed, 11 insertions(+)
diff --git a/java/ql/test/kotlin/library-tests/enum/test.expected b/java/ql/test/kotlin/library-tests/enum/test.expected
index abc7e2e87c7..2484ff2e2ba 100644
--- a/java/ql/test/kotlin/library-tests/enum/test.expected
+++ b/java/ql/test/kotlin/library-tests/enum/test.expected
@@ -15,6 +15,7 @@ enumConstants
| describeConstable |
| equals |
| finalize |
+| forEach |
| getDeclaringClass |
| hasMoreElements |
| hashCode |
@@ -23,8 +24,12 @@ enumConstants
| noneOf |
| of |
| ordinal |
+| parallelStream |
| range |
| resolveConstantDesc |
+| spliterator |
+| stream |
+| toArray |
| toString |
| typeCheck |
| usesEnum |
diff --git a/java/ql/test/kotlin/library-tests/java-lang-number-conversions/test.expected b/java/ql/test/kotlin/library-tests/java-lang-number-conversions/test.expected
index 52ed7b2ccfe..993ddb13e55 100644
--- a/java/ql/test/kotlin/library-tests/java-lang-number-conversions/test.expected
+++ b/java/ql/test/kotlin/library-tests/java-lang-number-conversions/test.expected
@@ -36,6 +36,7 @@
| kotlin.Byte | minus |
| kotlin.Byte | plus |
| kotlin.Byte | rangeTo |
+| kotlin.Byte | rangeUntil |
| kotlin.Byte | rem |
| kotlin.Byte | shortValue |
| kotlin.Byte | times |
diff --git a/java/ql/test/kotlin/library-tests/reflection/reflection.expected b/java/ql/test/kotlin/library-tests/reflection/reflection.expected
index f2482a81ec1..d149bd24563 100644
--- a/java/ql/test/kotlin/library-tests/reflection/reflection.expected
+++ b/java/ql/test/kotlin/library-tests/reflection/reflection.expected
@@ -269,6 +269,11 @@ compGenerated
| file:///CharRange.class:0:0:0:0 | spliterator | Forwarder for a Kotlin class inheriting an interface default method |
| file:///Class2.class:0:0:0:0 | getValue | Default property accessor |
| file:///Class2.class:0:0:0:0 | getValue | Default property accessor |
+| file:///EnumEntries.class:0:0:0:0 | forEach | Forwarder for a Kotlin class inheriting an interface default method |
+| file:///EnumEntries.class:0:0:0:0 | parallelStream | Forwarder for a Kotlin class inheriting an interface default method |
+| file:///EnumEntries.class:0:0:0:0 | spliterator | Forwarder for a Kotlin class inheriting an interface default method |
+| file:///EnumEntries.class:0:0:0:0 | stream | Forwarder for a Kotlin class inheriting an interface default method |
+| file:///EnumEntries.class:0:0:0:0 | toArray | Forwarder for a Kotlin class inheriting an interface default method |
| file:///IntProgression.class:0:0:0:0 | forEach | Forwarder for a Kotlin class inheriting an interface default method |
| file:///IntProgression.class:0:0:0:0 | spliterator | Forwarder for a Kotlin class inheriting an interface default method |
| file:///IntRange.class:0:0:0:0 | forEach | Forwarder for a Kotlin class inheriting an interface default method |
From b51c3aae85510def6a659b9585240e80e680d917 Mon Sep 17 00:00:00 2001
From: Ian Lynagh
Date: Thu, 8 Dec 2022 19:19:39 +0000
Subject: [PATCH 156/381] Kotlin: Logs test: Allow for -Beta versions etc when
parsing the logs
---
.../integration-tests/all-platforms/kotlin/logs/index_logs.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/java/ql/integration-tests/all-platforms/kotlin/logs/index_logs.py b/java/ql/integration-tests/all-platforms/kotlin/logs/index_logs.py
index a02c8b3f75a..9aa6ad13863 100644
--- a/java/ql/integration-tests/all-platforms/kotlin/logs/index_logs.py
+++ b/java/ql/integration-tests/all-platforms/kotlin/logs/index_logs.py
@@ -32,7 +32,7 @@ with open('logs.csv', 'w', newline='') as f_out:
j = json.loads(line)
msg = j['message']
msg = re.sub(r'(?<=Extraction for invocation TRAP file ).*[\\/]kt-db[\\/]trap[\\/]java[\\/]invocations[\\/]kotlin\..*\.trap', '', msg)
- msg = re.sub('(?<=Kotlin version )[0-9.]+', '', msg)
+ msg = re.sub('(?<=Kotlin version )[0-9.]+(-[a-zA-Z0-9.]+)?', '', msg)
if msg.startswith('Peak memory: '):
# Peak memory information varies from run to run, so just ignore it
continue
From 89b33637612c64b2af3dfd074576ac65c203f55d Mon Sep 17 00:00:00 2001
From: Ian Lynagh
Date: Thu, 8 Dec 2022 19:20:22 +0000
Subject: [PATCH 157/381] Kotlin: Bump CI version to 1.8.0-Beta
---
java/kotlin-extractor/kotlin_plugin_versions.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/java/kotlin-extractor/kotlin_plugin_versions.py b/java/kotlin-extractor/kotlin_plugin_versions.py
index 1081883479c..b3f9cfd1812 100755
--- a/java/kotlin-extractor/kotlin_plugin_versions.py
+++ b/java/kotlin-extractor/kotlin_plugin_versions.py
@@ -22,7 +22,7 @@ def version_string_to_tuple(version):
return tuple([int(m.group(i)) for i in range(1, 4)] + [m.group(4)])
# Version number used by CI. It needs to be one of the versions in many_versions.
-ci_version = '1.7.20'
+ci_version = '1.8.0-Beta'
# Version numbers in the list need to be in semantically increasing order
many_versions = [ '1.4.32', '1.5.0', '1.5.10', '1.5.20', '1.5.30', '1.6.0', '1.6.20', '1.7.0', '1.7.20', '1.8.0-Beta' ]
From c4119761cc2f56d673edbb94814a75707f0f0c1c Mon Sep 17 00:00:00 2001
From: Ian Lynagh
Date: Mon, 9 Jan 2023 19:39:34 +0000
Subject: [PATCH 158/381] Kotlin: Another 1.8 build fix
---
java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt b/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt
index 99eacabb25e..793d7b15b6f 100644
--- a/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt
+++ b/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt
@@ -1387,7 +1387,7 @@ open class KotlinFileExtractor(
private fun getNullabilityAnnotation(t: IrType, declOrigin: IrDeclarationOrigin, existingAnnotations: List, javaAnnotations: Collection?) =
getNullabilityAnnotationName(t, declOrigin, existingAnnotations, javaAnnotations)?.let {
- pluginContext.referenceClass(it)?.let { annotationClass ->
+ getClassByFqName(pluginContext, it)?.let { annotationClass ->
annotationClass.owner.declarations.firstIsInstanceOrNull()?.let { annotationConstructor ->
IrConstructorCallImpl.fromSymbolOwner(
UNDEFINED_OFFSET, UNDEFINED_OFFSET, annotationConstructor.returnType, annotationConstructor.symbol, 0
From 20b35e5d02e1a8432d28ff43442cf75033a8326e Mon Sep 17 00:00:00 2001
From: Ian Lynagh
Date: Mon, 9 Jan 2023 19:52:31 +0000
Subject: [PATCH 159/381] Kotlin: 1.8.0 changes
---
docs/codeql/reusables/supported-versions-compilers.rst | 2 +-
java/kotlin-extractor/build.gradle | 3 +++
java/kotlin-extractor/kotlin_plugin_versions.py | 4 ++--
.../{v_1_8_0-Beta => v_1_8_0}/ExperimentalCompilerApi.kt | 0
.../{v_1_8_0-Beta => v_1_8_0}/FirIncompatiblePluginAPI.kt | 0
5 files changed, 6 insertions(+), 3 deletions(-)
rename java/kotlin-extractor/src/main/kotlin/utils/versions/{v_1_8_0-Beta => v_1_8_0}/ExperimentalCompilerApi.kt (100%)
rename java/kotlin-extractor/src/main/kotlin/utils/versions/{v_1_8_0-Beta => v_1_8_0}/FirIncompatiblePluginAPI.kt (100%)
diff --git a/docs/codeql/reusables/supported-versions-compilers.rst b/docs/codeql/reusables/supported-versions-compilers.rst
index 85a650ed17a..c9b38fc4c19 100644
--- a/docs/codeql/reusables/supported-versions-compilers.rst
+++ b/docs/codeql/reusables/supported-versions-compilers.rst
@@ -20,7 +20,7 @@
Java,"Java 7 to 18 [4]_","javac (OpenJDK and Oracle JDK),
Eclipse compiler for Java (ECJ) [5]_",``.java``
- Kotlin [6]_,"Kotlin 1.5.0 to 1.7.21","kotlinc",``.kt``
+ Kotlin [6]_,"Kotlin 1.5.0 to 1.8.0","kotlinc",``.kt``
JavaScript,ECMAScript 2022 or lower,Not applicable,"``.js``, ``.jsx``, ``.mjs``, ``.es``, ``.es6``, ``.htm``, ``.html``, ``.xhtm``, ``.xhtml``, ``.vue``, ``.hbs``, ``.ejs``, ``.njk``, ``.json``, ``.yaml``, ``.yml``, ``.raml``, ``.xml`` [7]_"
Python [8]_,"2.7, 3.5, 3.6, 3.7, 3.8, 3.9, 3.10",Not applicable,``.py``
Ruby [9]_,"up to 3.1",Not applicable,"``.rb``, ``.erb``, ``.gemspec``, ``Gemfile``"
diff --git a/java/kotlin-extractor/build.gradle b/java/kotlin-extractor/build.gradle
index 7859a2c4c08..57229642a92 100644
--- a/java/kotlin-extractor/build.gradle
+++ b/java/kotlin-extractor/build.gradle
@@ -46,6 +46,9 @@ sourceSets {
"utils/versions/v_1_7_20-Beta/createImplicitParameterDeclarationWithWrappedDescriptor.kt",
"utils/versions/v_1_7_20-Beta/allOverriddenIncludingSelf.kt",
+
+ "utils/versions/v_1_8_0/ExperimentalCompilerApi.kt",
+ "utils/versions/v_1_8_0/FirIncompatiblePluginAPI.kt",
]
}
}
diff --git a/java/kotlin-extractor/kotlin_plugin_versions.py b/java/kotlin-extractor/kotlin_plugin_versions.py
index b3f9cfd1812..8d08c75803e 100755
--- a/java/kotlin-extractor/kotlin_plugin_versions.py
+++ b/java/kotlin-extractor/kotlin_plugin_versions.py
@@ -22,10 +22,10 @@ def version_string_to_tuple(version):
return tuple([int(m.group(i)) for i in range(1, 4)] + [m.group(4)])
# Version number used by CI. It needs to be one of the versions in many_versions.
-ci_version = '1.8.0-Beta'
+ci_version = '1.8.0'
# Version numbers in the list need to be in semantically increasing order
-many_versions = [ '1.4.32', '1.5.0', '1.5.10', '1.5.20', '1.5.30', '1.6.0', '1.6.20', '1.7.0', '1.7.20', '1.8.0-Beta' ]
+many_versions = [ '1.4.32', '1.5.0', '1.5.10', '1.5.20', '1.5.30', '1.6.0', '1.6.20', '1.7.0', '1.7.20', '1.8.0' ]
many_versions_tuples = [version_string_to_tuple(v) for v in many_versions]
diff --git a/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_8_0-Beta/ExperimentalCompilerApi.kt b/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_8_0/ExperimentalCompilerApi.kt
similarity index 100%
rename from java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_8_0-Beta/ExperimentalCompilerApi.kt
rename to java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_8_0/ExperimentalCompilerApi.kt
diff --git a/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_8_0-Beta/FirIncompatiblePluginAPI.kt b/java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_8_0/FirIncompatiblePluginAPI.kt
similarity index 100%
rename from java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_8_0-Beta/FirIncompatiblePluginAPI.kt
rename to java/kotlin-extractor/src/main/kotlin/utils/versions/v_1_8_0/FirIncompatiblePluginAPI.kt
From c71ea80029a9db803a4062c0868f9888e17b2b25 Mon Sep 17 00:00:00 2001
From: Ian Lynagh
Date: Tue, 10 Jan 2023 12:56:12 +0000
Subject: [PATCH 160/381] Kotlin: Accept test changes
We now get better locations, with Kotlin 1.8.0.
---
.../PrintAst.expected | 100 +++++++++---------
1 file changed, 50 insertions(+), 50 deletions(-)
diff --git a/java/ql/integration-tests/all-platforms/kotlin/annotation-id-consistency/PrintAst.expected b/java/ql/integration-tests/all-platforms/kotlin/annotation-id-consistency/PrintAst.expected
index 751777f3748..6da5da6d522 100644
--- a/java/ql/integration-tests/all-platforms/kotlin/annotation-id-consistency/PrintAst.expected
+++ b/java/ql/integration-tests/all-platforms/kotlin/annotation-id-consistency/PrintAst.expected
@@ -146,25 +146,24 @@ test.kt:
# 19| 1: [Annotation] VarargAnnotation
# 0| 1: [ArrayInit] {...}
# 20| 2: [Annotation] VarargAnnotation
-# 0| 1: [ArrayInit] {...}
-# 0| 1: [IntegerLiteral] 1
+# 20| 1: [ArrayInit] {...}
+# 20| 1: [IntegerLiteral] 1
# 21| 3: [Annotation] VarargAnnotation
-# 0| 1: [ArrayInit] {...}
-# 0| 1: [IntegerLiteral] 1
-# 0| 2: [IntegerLiteral] 2
+# 21| 1: [ArrayInit] {...}
+# 21| 1: [IntegerLiteral] 1
+# 21| 2: [IntegerLiteral] 2
# 22| 4: [Annotation] VarargAnnotation
-# 0| 1: [ArrayInit] {...}
-# 0| 1: [IntegerLiteral] 1
-# 0| 2: [IntegerLiteral] 2
-# 0| 3: [IntegerLiteral] 3
+# 22| 1: [ArrayInit] {...}
+# 22| 1: [IntegerLiteral] 1
+# 22| 2: [IntegerLiteral] 2
+# 22| 3: [IntegerLiteral] 3
# 23| 5: [Annotation] VarargAnnotation
-# 0| 1: [ArrayInit] {...}
-# 0| 1: [IntegerLiteral] 1
-# 0| 2: [IntegerLiteral] 2
-# 0| 3: [IntegerLiteral] 3
+# 23| 1: [ArrayInit] {...}
+# 23| 1: [IntegerLiteral] 1
+# 23| 2: [IntegerLiteral] 2
+# 23| 3: [IntegerLiteral] 3
# 17| 2: [Annotation] Ann1
-# 0| 1: [IntegerLiteral] 1
-# 0| 2: [Annotation] Ann2
+# 0| 1: [Annotation] Ann2
# 0| 1: [StringLiteral] "Hello"
# 0| 2: [TypeLiteral] String.class
# 0| 0: [TypeAccess] String
@@ -182,16 +181,17 @@ test.kt:
# 0| 0: [TypeAccess] String
# 0| 2: [TypeLiteral] int.class
# 0| 0: [TypeAccess] int
-# 0| 3: [VarAccess] DayOfWeek.MONDAY
-# 0| -1: [TypeAccess] DayOfWeek
+# 17| 2: [IntegerLiteral] 1
+# 17| 3: [VarAccess] DayOfWeek.MONDAY
+# 17| -1: [TypeAccess] DayOfWeek
# 18| 3: [Annotation] GenericAnnotation
-# 0| 1: [TypeLiteral] String.class
-# 0| 0: [TypeAccess] String
-# 0| 2: [ArrayInit] {...}
-# 0| 1: [TypeLiteral] String.class
-# 0| 0: [TypeAccess] String
-# 0| 2: [TypeLiteral] String.class
-# 0| 0: [TypeAccess] String
+# 18| 1: [TypeLiteral] String.class
+# 18| 0: [TypeAccess] String
+# 18| 2: [ArrayInit] {...}
+# 18| 1: [TypeLiteral] String.class
+# 18| 0: [TypeAccess] String
+# 18| 2: [TypeLiteral] String.class
+# 18| 0: [TypeAccess] String
# 24| 4: [Annotation] AnnWithDefaults
# 0| 1: [IntegerLiteral] 1
# 0| 2: [StringLiteral] "hello"
@@ -211,25 +211,24 @@ test.kt:
# 29| 1: [Annotation] VarargAnnotation
# 0| 1: [ArrayInit] {...}
# 30| 2: [Annotation] VarargAnnotation
-# 0| 1: [ArrayInit] {...}
-# 0| 1: [IntegerLiteral] 1
+# 30| 1: [ArrayInit] {...}
+# 30| 1: [IntegerLiteral] 1
# 31| 3: [Annotation] VarargAnnotation
-# 0| 1: [ArrayInit] {...}
-# 0| 1: [IntegerLiteral] 1
-# 0| 2: [IntegerLiteral] 2
+# 31| 1: [ArrayInit] {...}
+# 31| 1: [IntegerLiteral] 1
+# 31| 2: [IntegerLiteral] 2
# 32| 4: [Annotation] VarargAnnotation
-# 0| 1: [ArrayInit] {...}
-# 0| 1: [IntegerLiteral] 1
-# 0| 2: [IntegerLiteral] 2
-# 0| 3: [IntegerLiteral] 3
+# 32| 1: [ArrayInit] {...}
+# 32| 1: [IntegerLiteral] 1
+# 32| 2: [IntegerLiteral] 2
+# 32| 3: [IntegerLiteral] 3
# 33| 5: [Annotation] VarargAnnotation
-# 0| 1: [ArrayInit] {...}
-# 0| 1: [IntegerLiteral] 1
-# 0| 2: [IntegerLiteral] 2
-# 0| 3: [IntegerLiteral] 3
+# 33| 1: [ArrayInit] {...}
+# 33| 1: [IntegerLiteral] 1
+# 33| 2: [IntegerLiteral] 2
+# 33| 3: [IntegerLiteral] 3
# 27| 2: [Annotation] Ann1
-# 0| 1: [IntegerLiteral] 1
-# 0| 2: [Annotation] Ann2
+# 0| 1: [Annotation] Ann2
# 0| 1: [StringLiteral] "Hello"
# 0| 2: [TypeLiteral] String.class
# 0| 0: [TypeAccess] String
@@ -247,16 +246,17 @@ test.kt:
# 0| 0: [TypeAccess] String
# 0| 2: [TypeLiteral] int.class
# 0| 0: [TypeAccess] int
-# 0| 3: [VarAccess] DayOfWeek.MONDAY
-# 0| -1: [TypeAccess] DayOfWeek
+# 27| 2: [IntegerLiteral] 1
+# 27| 3: [VarAccess] DayOfWeek.MONDAY
+# 27| -1: [TypeAccess] DayOfWeek
# 28| 3: [Annotation] GenericAnnotation
-# 0| 1: [TypeLiteral] String.class
-# 0| 0: [TypeAccess] String
-# 0| 2: [ArrayInit] {...}
-# 0| 1: [TypeLiteral] String.class
-# 0| 0: [TypeAccess] String
-# 0| 2: [TypeLiteral] String.class
-# 0| 0: [TypeAccess] String
+# 28| 1: [TypeLiteral] String.class
+# 28| 0: [TypeAccess] String
+# 28| 2: [ArrayInit] {...}
+# 28| 1: [TypeLiteral] String.class
+# 28| 0: [TypeAccess] String
+# 28| 2: [TypeLiteral] String.class
+# 28| 0: [TypeAccess] String
# 34| 4: [Annotation] AnnWithDefaults
# 0| 1: [IntegerLiteral] 1
# 0| 2: [StringLiteral] "hello"
@@ -279,7 +279,7 @@ test.kt:
# 40| 11: [Class] HasKotlinDeprecatedAnnotationUsedByJava
#-----| -3: (Annotations)
# 40| 1: [Annotation] Deprecated
-# 0| 1: [StringLiteral] "Kotlin deprecation message 1"
+# 40| 1: [StringLiteral] "Kotlin deprecation message 1"
# 41| 1: [Constructor] HasKotlinDeprecatedAnnotationUsedByJava
# 40| 5: [BlockStmt] { ... }
# 40| 0: [SuperConstructorInvocationStmt] super(...)
@@ -294,7 +294,7 @@ test.kt:
# 46| 13: [Class] HasKotlinDeprecatedAnnotationUsedByKotlin
#-----| -3: (Annotations)
# 46| 1: [Annotation] Deprecated
-# 0| 1: [StringLiteral] "Kotlin deprecation message 2"
+# 46| 1: [StringLiteral] "Kotlin deprecation message 2"
# 47| 1: [Constructor] HasKotlinDeprecatedAnnotationUsedByKotlin
# 46| 5: [BlockStmt] { ... }
# 46| 0: [SuperConstructorInvocationStmt] super(...)
From b7eb521fa037f62ec7fa818b2a556b7897d267d8 Mon Sep 17 00:00:00 2001
From: Ian Lynagh
Date: Tue, 10 Jan 2023 13:04:36 +0000
Subject: [PATCH 161/381] Kotlin: Fix custom_plugin test for Kotlin 1.8.0
---
.../linux-only/kotlin/custom_plugin/plugin/Plugin.kt | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/java/ql/integration-tests/linux-only/kotlin/custom_plugin/plugin/Plugin.kt b/java/ql/integration-tests/linux-only/kotlin/custom_plugin/plugin/Plugin.kt
index d80801974e2..f45b4804393 100644
--- a/java/ql/integration-tests/linux-only/kotlin/custom_plugin/plugin/Plugin.kt
+++ b/java/ql/integration-tests/linux-only/kotlin/custom_plugin/plugin/Plugin.kt
@@ -2,11 +2,13 @@ package com.github.codeql
import com.intellij.mock.MockProject
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
+import org.jetbrains.kotlin.backend.common.extensions.FirIncompatiblePluginAPI
import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
import org.jetbrains.kotlin.backend.common.ir.addDispatchReceiver
import org.jetbrains.kotlin.backend.common.lower.DeclarationIrBuilder
import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar
+import org.jetbrains.kotlin.compiler.plugin.ExperimentalCompilerApi
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
@@ -35,6 +37,7 @@ import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
+@OptIn(ExperimentalCompilerApi::class)
class TestComponentRegistrar : ComponentRegistrar {
override fun registerProjectComponents(
project: MockProject,
@@ -188,6 +191,7 @@ class IrAdder : IrGenerationExtension {
}
private fun addFunWithUnsafeCoerce(declaration: IrClass) {
+ @OptIn(FirIncompatiblePluginAPI::class)
val uintType = pluginContext.referenceClass(FqName("kotlin.UInt"))!!.owner.typeWith()
declaration.declarations.add(pluginContext.irFactory.buildFun {
name = Name.identifier("")
@@ -264,6 +268,7 @@ class IrAdder : IrGenerationExtension {
name = Name.identifier("start")
origin = IrDeclarationOrigin.IR_EXTERNAL_JAVA_DECLARATION_STUB
modality = Modality.FINAL
+ @OptIn(FirIncompatiblePluginAPI::class)
returnType = pluginContext.referenceClass(FqName("java.lang.Process"))!!.owner.defaultType
}.apply {
addDispatchReceiver { type = processBuilderStubType }
From 3367da82c43193a908c5f9ed92192a6c430b776f Mon Sep 17 00:00:00 2001
From: Ian Lynagh
Date: Tue, 10 Jan 2023 14:24:33 +0000
Subject: [PATCH 162/381] Kotlin: Accept test changes
We get better locations with Kotlin 1.8.0.
---
.../annotation_classes/PrintAst.expected | 78 +++++++++----------
.../annotation_classes/classes.expected | 10 +--
2 files changed, 44 insertions(+), 44 deletions(-)
diff --git a/java/ql/test/kotlin/library-tests/annotation_classes/PrintAst.expected b/java/ql/test/kotlin/library-tests/annotation_classes/PrintAst.expected
index c457b0811dd..0ff19b747fa 100644
--- a/java/ql/test/kotlin/library-tests/annotation_classes/PrintAst.expected
+++ b/java/ql/test/kotlin/library-tests/annotation_classes/PrintAst.expected
@@ -108,39 +108,39 @@ def.kt:
# 0| 9: [VarAccess] ElementType.TYPE_USE
# 0| -1: [TypeAccess] ElementType
# 5| 3: [Annotation] Target
-# 0| 1: [ArrayInit] {...}
-# 0| 1: [VarAccess] AnnotationTarget.CLASS
-# 0| -1: [TypeAccess] AnnotationTarget
-# 0| 2: [VarAccess] AnnotationTarget.ANNOTATION_CLASS
-# 0| -1: [TypeAccess] AnnotationTarget
-# 0| 3: [VarAccess] AnnotationTarget.TYPE_PARAMETER
-# 0| -1: [TypeAccess] AnnotationTarget
-# 0| 4: [VarAccess] AnnotationTarget.PROPERTY
-# 0| -1: [TypeAccess] AnnotationTarget
-# 0| 5: [VarAccess] AnnotationTarget.FIELD
-# 0| -1: [TypeAccess] AnnotationTarget
-# 0| 6: [VarAccess] AnnotationTarget.LOCAL_VARIABLE
-# 0| -1: [TypeAccess] AnnotationTarget
-# 0| 7: [VarAccess] AnnotationTarget.VALUE_PARAMETER
-# 0| -1: [TypeAccess] AnnotationTarget
-# 0| 8: [VarAccess] AnnotationTarget.CONSTRUCTOR
-# 0| -1: [TypeAccess] AnnotationTarget
-# 0| 9: [VarAccess] AnnotationTarget.FUNCTION
-# 0| -1: [TypeAccess] AnnotationTarget
-# 0| 10: [VarAccess] AnnotationTarget.PROPERTY_GETTER
-# 0| -1: [TypeAccess] AnnotationTarget
-# 0| 11: [VarAccess] AnnotationTarget.PROPERTY_SETTER
-# 0| -1: [TypeAccess] AnnotationTarget
-# 0| 12: [VarAccess] AnnotationTarget.TYPE
-# 0| -1: [TypeAccess] AnnotationTarget
-# 0| 13: [VarAccess] AnnotationTarget.FILE
-# 0| -1: [TypeAccess] AnnotationTarget
-# 0| 14: [VarAccess] AnnotationTarget.TYPEALIAS
-# 0| -1: [TypeAccess] AnnotationTarget
+# 5| 1: [ArrayInit] {...}
+# 5| 1: [VarAccess] AnnotationTarget.CLASS
+# 5| -1: [TypeAccess] AnnotationTarget
+# 5| 2: [VarAccess] AnnotationTarget.ANNOTATION_CLASS
+# 5| -1: [TypeAccess] AnnotationTarget
+# 5| 3: [VarAccess] AnnotationTarget.TYPE_PARAMETER
+# 5| -1: [TypeAccess] AnnotationTarget
+# 5| 4: [VarAccess] AnnotationTarget.PROPERTY
+# 5| -1: [TypeAccess] AnnotationTarget
+# 5| 5: [VarAccess] AnnotationTarget.FIELD
+# 5| -1: [TypeAccess] AnnotationTarget
+# 5| 6: [VarAccess] AnnotationTarget.LOCAL_VARIABLE
+# 5| -1: [TypeAccess] AnnotationTarget
+# 5| 7: [VarAccess] AnnotationTarget.VALUE_PARAMETER
+# 5| -1: [TypeAccess] AnnotationTarget
+# 5| 8: [VarAccess] AnnotationTarget.CONSTRUCTOR
+# 5| -1: [TypeAccess] AnnotationTarget
+# 5| 9: [VarAccess] AnnotationTarget.FUNCTION
+# 5| -1: [TypeAccess] AnnotationTarget
+# 5| 10: [VarAccess] AnnotationTarget.PROPERTY_GETTER
+# 5| -1: [TypeAccess] AnnotationTarget
+# 5| 11: [VarAccess] AnnotationTarget.PROPERTY_SETTER
+# 5| -1: [TypeAccess] AnnotationTarget
+# 5| 12: [VarAccess] AnnotationTarget.TYPE
+# 5| -1: [TypeAccess] AnnotationTarget
+# 5| 13: [VarAccess] AnnotationTarget.FILE
+# 5| -1: [TypeAccess] AnnotationTarget
+# 5| 14: [VarAccess] AnnotationTarget.TYPEALIAS
+# 5| -1: [TypeAccess] AnnotationTarget
# 21| 1: [Method] a
#-----| 1: (Annotations)
# 21| 1: [Annotation] JvmName
-# 0| 1: [StringLiteral] "a"
+# 21| 1: [StringLiteral] "a"
# 21| 3: [TypeAccess] int
# 23| 3: [Interface] Annot1k
#-----| -3: (Annotations)
@@ -201,21 +201,21 @@ def.kt:
# 38| 6: [Class] Z
#-----| -3: (Annotations)
# 38| 1: [Annotation] Annot0k
-# 0| 1: [IntegerLiteral] 1
+# 38| 1: [IntegerLiteral] 1
# 39| 2: [Annotation] Annot1k
# 0| 1: [IntegerLiteral] 2
# 0| 2: [StringLiteral] "ab"
# 0| 3: [TypeLiteral] X.class
# 0| 0: [TypeAccess] X
-# 0| 4: [VarAccess] Y.B
-# 0| -1: [TypeAccess] Y
-# 0| 5: [ArrayInit] {...}
-# 0| 1: [VarAccess] Y.C
-# 0| -1: [TypeAccess] Y
-# 0| 2: [VarAccess] Y.A
-# 0| -1: [TypeAccess] Y
-# 0| 6: [Annotation] Annot0k
+# 0| 4: [Annotation] Annot0k
# 0| 1: [IntegerLiteral] 1
+# 39| 5: [VarAccess] Y.B
+# 39| -1: [TypeAccess] Y
+# 39| 6: [ArrayInit] {...}
+# 39| 1: [VarAccess] Y.C
+# 39| -1: [TypeAccess] Y
+# 39| 2: [VarAccess] Y.A
+# 39| -1: [TypeAccess] Y
# 42| 1: [Constructor] Z
#-----| 1: (Annotations)
# 41| 1: [Annotation] Annot0k
diff --git a/java/ql/test/kotlin/library-tests/annotation_classes/classes.expected b/java/ql/test/kotlin/library-tests/annotation_classes/classes.expected
index b04dd33d2e7..01f5581b73a 100644
--- a/java/ql/test/kotlin/library-tests/annotation_classes/classes.expected
+++ b/java/ql/test/kotlin/library-tests/annotation_classes/classes.expected
@@ -36,16 +36,16 @@ annotationValues
| def.kt:0:0:0:0 | Retention | def.kt:0:0:0:0 | RetentionPolicy.RUNTIME |
| def.kt:0:0:0:0 | Retention | def.kt:0:0:0:0 | RetentionPolicy.RUNTIME |
| def.kt:0:0:0:0 | Target | def.kt:0:0:0:0 | {...} |
-| def.kt:5:1:20:1 | Target | def.kt:0:0:0:0 | {...} |
-| def.kt:21:26:21:42 | JvmName | def.kt:0:0:0:0 | "a" |
+| def.kt:5:1:20:1 | Target | def.kt:5:9:5:30 | {...} |
+| def.kt:21:26:21:42 | JvmName | def.kt:21:39:21:41 | "a" |
| def.kt:23:1:23:8 | Annot0k | def.kt:0:0:0:0 | 0 |
-| def.kt:38:1:38:17 | Annot0k | def.kt:0:0:0:0 | 1 |
+| def.kt:38:1:38:17 | Annot0k | def.kt:38:16:38:16 | 1 |
| def.kt:39:1:39:40 | Annot1k | def.kt:0:0:0:0 | 2 |
| def.kt:39:1:39:40 | Annot1k | def.kt:0:0:0:0 | "ab" |
| def.kt:39:1:39:40 | Annot1k | def.kt:0:0:0:0 | Annot0k |
| def.kt:39:1:39:40 | Annot1k | def.kt:0:0:0:0 | X.class |
-| def.kt:39:1:39:40 | Annot1k | def.kt:0:0:0:0 | Y.B |
-| def.kt:39:1:39:40 | Annot1k | def.kt:0:0:0:0 | {...} |
+| def.kt:39:1:39:40 | Annot1k | def.kt:39:14:39:16 | Y.B |
+| def.kt:39:1:39:40 | Annot1k | def.kt:39:23:39:39 | {...} |
| def.kt:41:5:41:12 | Annot0k | def.kt:0:0:0:0 | 0 |
| def.kt:45:1:45:8 | Annot0k | def.kt:0:0:0:0 | 0 |
| def.kt:46:21:46:28 | Annot0k | def.kt:0:0:0:0 | 0 |
From ae8c75ac97c5230eb86d3bc685c28a9599e92764 Mon Sep 17 00:00:00 2001
From: Tony Torralba
Date: Tue, 10 Jan 2023 13:34:44 +0100
Subject: [PATCH 163/381] Generalize ConjunctionParent
---
.../src/codeql_ql/style/ConjunctionParent.qll | 45 +++++++++++++++++++
ql/ql/src/queries/style/OmittableExists.ql | 28 +++++++-----
.../src/queries/style/RedundantAssignment.ql | 45 +++----------------
3 files changed, 69 insertions(+), 49 deletions(-)
create mode 100644 ql/ql/src/codeql_ql/style/ConjunctionParent.qll
diff --git a/ql/ql/src/codeql_ql/style/ConjunctionParent.qll b/ql/ql/src/codeql_ql/style/ConjunctionParent.qll
new file mode 100644
index 00000000000..f3b96f18b11
--- /dev/null
+++ b/ql/ql/src/codeql_ql/style/ConjunctionParent.qll
@@ -0,0 +1,45 @@
+import ql
+
+signature predicate checkAstNodeSig(AstNode p);
+
+module ConjunctionParent {
+ /**
+ * Gets the top-most parent of `p` that is not a disjunction.
+ */
+ AstNode getConjunctionParent(AstNode p) {
+ result =
+ min(int level, AstNode parent |
+ parent = getConjunctionParentRec(p) and level = level(parent)
+ |
+ parent order by level
+ )
+ }
+
+ /**
+ * Gets a (transitive) parent of `p`, where the parent is not a negative edge, and `checkAstNode(p)` holds.
+ */
+ private AstNode getConjunctionParentRec(AstNode p) {
+ checkAstNode(p) and
+ result = p
+ or
+ result = getConjunctionParentRec(p).getParent() and
+ not result instanceof Disjunction and
+ not result instanceof IfFormula and
+ not result instanceof Implication and
+ not result instanceof Negation and
+ not result instanceof Predicate and
+ not result instanceof FullAggregate and
+ not result instanceof Forex and
+ not result instanceof Forall
+ }
+
+ /**
+ * Gets which level in the AST `p` is at.
+ * E.g. the top-level is 0, the next level is 1, etc.
+ */
+ private int level(AstNode p) {
+ p instanceof TopLevel and result = 0
+ or
+ result = level(p.getParent()) + 1
+ }
+}
diff --git a/ql/ql/src/queries/style/OmittableExists.ql b/ql/ql/src/queries/style/OmittableExists.ql
index c6e47c260df..4da6342fabf 100644
--- a/ql/ql/src/queries/style/OmittableExists.ql
+++ b/ql/ql/src/queries/style/OmittableExists.ql
@@ -9,15 +9,14 @@
*/
import ql
+import codeql_ql.style.ConjunctionParent
-class AggregateOrForQuantifier extends AstNode {
- AggregateOrForQuantifier() {
- this instanceof FullAggregate or this instanceof Forex or this instanceof Forall
- }
-}
-
-from VarDecl existsArgument, VarAccess use
-where
+/**
+ * Holds if `existsArgument` is the declaration of a variable in an `exists` formula,
+ * and `use` is both its only use and an argument of a predicate that doesn't restrict
+ * the corresponding parameter type.
+ */
+predicate omittableExists(VarDecl existsArgument, VarAccess use) {
existsArgument = any(Exists e).getAnArgument() and
use = unique( | | existsArgument.getAnAccess()) and
exists(Call c, int argPos, Type paramType |
@@ -25,7 +24,16 @@ where
|
existsArgument.getType() = paramType.getASuperType*() and
not paramType instanceof DatabaseType
- ) and
- not use.getParent*() instanceof AggregateOrForQuantifier
+ )
+}
+
+/** Holds if `p` is an exists variable (either declaration or use) that can be omitted. */
+predicate omittableExistsNode(AstNode p) { omittableExists(p, _) or omittableExists(_, p) }
+
+from VarDecl existsArgument, VarAccess use
+where
+ omittableExists(existsArgument, use) and
+ ConjunctionParent::getConjunctionParent(existsArgument) =
+ ConjunctionParent::getConjunctionParent(use)
select existsArgument, "This exists variable can be omitted by using a don't-care expression $@.",
use, "in this argument"
diff --git a/ql/ql/src/queries/style/RedundantAssignment.ql b/ql/ql/src/queries/style/RedundantAssignment.ql
index 7baf046b97a..83f62364d9f 100644
--- a/ql/ql/src/queries/style/RedundantAssignment.ql
+++ b/ql/ql/src/queries/style/RedundantAssignment.ql
@@ -9,6 +9,8 @@
*/
import ql
+import codeql_ql.style.ConjunctionParent
+import codeql.GlobalValueNumbering as GVN
/**
* A variable that is set equal to (assigned) a value one or more times.
@@ -40,8 +42,6 @@ class AssignedVariable extends VarDecl {
}
}
-import codeql.GlobalValueNumbering as GVN
-
/**
* Holds if `assigned1` and `assigned2` assigns the same value to `var`.
* The assignments may be on different branches of a disjunction.
@@ -58,47 +58,14 @@ predicate candidateRedundantAssignment(AssignedVariable var, Expr assigned1, Exp
assigned1 != assigned2
}
-/**
- * Gets a (transitive) parent of `p`, where the parent is not a disjunction, and `p` is a candidate assignment from `candidateRedundantAssignment`.
- */
-AstNode getConjunctionParentRec(AstNode p) {
- candidateRedundantAssignment(_, p, _) and
- result = p
- or
- result = getConjunctionParentRec(p).getParent() and
- not result instanceof Disjunction and
- not result instanceof IfFormula and
- not result instanceof Implication and
- not result instanceof Negation and
- not result instanceof Predicate
-}
-
-/**
- * Gets which level in the AST `p` is at.
- * E.g. the top-level is 0, the next level is 1, etc.
- */
-int level(AstNode p) {
- p instanceof TopLevel and result = 0
- or
- result = level(p.getParent()) + 1
-}
-
-/**
- * Gets the top-most parent of `p` that is not a disjunction.
- */
-AstNode getConjunctionParent(AstNode p) {
- result =
- min(int level, AstNode parent |
- parent = getConjunctionParentRec(p) and level = level(parent)
- |
- parent order by level
- )
-}
+/** Holds if `p` is a candidate node for redundant assignment. */
+predicate candidateNode(AstNode p) { candidateRedundantAssignment(_, p, _) }
from AssignedVariable var, Expr assigned1, Expr assigned2
where
candidateRedundantAssignment(var, assigned1, assigned2) and
- getConjunctionParent(assigned1) = getConjunctionParent(assigned2) and
+ ConjunctionParent::getConjunctionParent(assigned1) =
+ ConjunctionParent::getConjunctionParent(assigned2) and
// de-duplcation:
(
assigned1.getLocation().getStartLine() < assigned2.getLocation().getStartLine()
From 3fa11c21c392b2daa847c7e387bffa94351aea48 Mon Sep 17 00:00:00 2001
From: Jonathan Leitschuh
Date: Wed, 14 Dec 2022 14:35:24 -0500
Subject: [PATCH 164/381] [Java] Document fixes for deserialization
vulnerabilities by framework
Related https://github.com/github/codeql/issues/11603
---
.../CWE/CWE-502/UnsafeDeserialization.qhelp | 55 ++++++++++++++++++-
1 file changed, 54 insertions(+), 1 deletion(-)
diff --git a/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.qhelp b/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.qhelp
index d1933ad4ac2..8d6bd34dab2 100644
--- a/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.qhelp
+++ b/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.qhelp
@@ -51,6 +51,59 @@ from the input stream removes the vulnerability.
+
+
+Fixes by framework
+
+
+
+
Project
+
Maven Cordinates
+
Secure by Default
+
Fix
+
+
+
XMLDecoder
+
Java Standard Library
+
No
+
Don't use XMLDecoder with untrusted user input. It is impossible to secure.
+
+
+
ObjectInputStream
+
Java Standard Library
+
No
+
Leverage a validating input stream like org.apache.commons.io.serialization.ValidatingObjectInputStream
+
+
+
FastJson
+
com.alibaba:fastjson
+
Partially
+
Call com.alibaba.fastjson.parser.ParserConfig#setSafeMode with the argument true
Instantiate the org.yaml.snakeyaml.Yaml instance explicitly with an instance of org.yaml.snakeyaml.constructor.SafeConstructor as an argument.
+
+
+
FasterXML jackson-databind
+
com.fasterxml.jackson.core:jackson-databind
+
Yes
+
+ Don't call com.fasterxml.jackson.databind.ObjectMapper#enableDefaultTyping and don't annotate any object fields with com.fasterxml.jackson.annotation.JsonTypeInfo passing either the CLASS or MINIMAL_CLASS values to the annotation.
+ Read this guide.
+
+
+
+
Kryo
+
com.esotericsoftware:kryo and com.esotericsoftware:kryo5
+
com.esotericsoftware:kryo versions including & after 5.0.0 Yes; com.esotericsoftware:kryo5 Yes
+
Don't call com.esotericsoftware.kryo(5).Kryo#setRegistrationRequired with the argument false.
Hessian deserialization and related gadget chains:
From b7364f542886898b29f5a16c7e247536ff6c3793 Mon Sep 17 00:00:00 2001
From: Tony Torralba
Date: Mon, 19 Dec 2022 10:08:13 +0100
Subject: [PATCH 165/381] Update UnsafeDeserialization.qhelp
Move the table under , minor fixes.
---
.../CWE/CWE-502/UnsafeDeserialization.qhelp | 108 +++++++++---------
1 file changed, 54 insertions(+), 54 deletions(-)
diff --git a/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.qhelp b/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.qhelp
index 8d6bd34dab2..2e9a368a9f0 100644
--- a/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.qhelp
+++ b/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.qhelp
@@ -28,11 +28,64 @@ for example JSON or XML. However, these formats should not be deserialized
into complex objects because this provides further opportunities for attack.
For example, XML-based deserialization attacks
are possible through libraries such as XStream and XmlDecoder.
-
+
+
Alternatively, a tightly controlled whitelist can limit the vulnerability of code, but be aware
of the existence of so-called Bypass Gadgets, which can circumvent such
protection measures.
+
+Fixes by framework:
+
+
+
+
+
Project
+
Maven Coordinates
+
Secure by Default
+
Fix
+
+
+
XMLDecoder
+
Java Standard Library
+
No
+
Don't use XMLDecoder with untrusted user input. It is impossible to secure.
+
+
+
ObjectInputStream
+
Java Standard Library
+
No
+
Leverage a validating input stream like org.apache.commons.io.serialization.ValidatingObjectInputStream.
+
+
+
FastJson
+
com.alibaba:fastjson
+
Partially
+
Call com.alibaba.fastjson.parser.ParserConfig#setSafeMode with the argument true.
Instantiate the org.yaml.snakeyaml.Yaml instance explicitly with an instance of org.yaml.snakeyaml.constructor.SafeConstructor as an argument.
+
+
+
FasterXML jackson-databind
+
com.fasterxml.jackson.core:jackson-databind
+
Yes
+
+ Don't call com.fasterxml.jackson.databind.ObjectMapper#enableDefaultTyping and don't annotate any object fields with com.fasterxml.jackson.annotation.JsonTypeInfo passing either the CLASS or MINIMAL_CLASS values to the annotation.
+ Read this guide.
+
+
+
+
Kryo
+
com.esotericsoftware:kryo and com.esotericsoftware:kryo5
+
com.esotericsoftware:kryo >= 5.0.0 and com.esotericsoftware:kryo5 Yes
+
Don't call com.esotericsoftware.kryo(5).Kryo#setRegistrationRequired with the argument false.
+
+
+
@@ -51,59 +104,6 @@ from the input stream removes the vulnerability.
-
-
-Fixes by framework
-
-
-
-
Project
-
Maven Cordinates
-
Secure by Default
-
Fix
-
-
-
XMLDecoder
-
Java Standard Library
-
No
-
Don't use XMLDecoder with untrusted user input. It is impossible to secure.
-
-
-
ObjectInputStream
-
Java Standard Library
-
No
-
Leverage a validating input stream like org.apache.commons.io.serialization.ValidatingObjectInputStream
-
-
-
FastJson
-
com.alibaba:fastjson
-
Partially
-
Call com.alibaba.fastjson.parser.ParserConfig#setSafeMode with the argument true
Instantiate the org.yaml.snakeyaml.Yaml instance explicitly with an instance of org.yaml.snakeyaml.constructor.SafeConstructor as an argument.
-
-
-
FasterXML jackson-databind
-
com.fasterxml.jackson.core:jackson-databind
-
Yes
-
- Don't call com.fasterxml.jackson.databind.ObjectMapper#enableDefaultTyping and don't annotate any object fields with com.fasterxml.jackson.annotation.JsonTypeInfo passing either the CLASS or MINIMAL_CLASS values to the annotation.
- Read this guide.
-
-
-
-
Kryo
-
com.esotericsoftware:kryo and com.esotericsoftware:kryo5
-
com.esotericsoftware:kryo versions including & after 5.0.0 Yes; com.esotericsoftware:kryo5 Yes
-
Don't call com.esotericsoftware.kryo(5).Kryo#setRegistrationRequired with the argument false.
-
-
-
-
From 1d7881e03fc26730e1ca40e03ed5e1b150e1d922 Mon Sep 17 00:00:00 2001
From: Jonathan Leitschuh
Date: Tue, 3 Jan 2023 13:36:36 -0500
Subject: [PATCH 166/381] Apply suggestions from code review
Co-authored-by: Chris Smowton
---
.../CWE/CWE-502/UnsafeDeserialization.qhelp | 16 ++++++++--------
1 file changed, 8 insertions(+), 8 deletions(-)
diff --git a/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.qhelp b/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.qhelp
index 2e9a368a9f0..aa421154d1e 100644
--- a/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.qhelp
+++ b/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.qhelp
@@ -35,7 +35,7 @@ of the existence of so-called Bypass Gadgets, which can circumvent such
protection measures.
-Fixes by framework:
+Recommendations specific to particular frameworks supported by this query:
@@ -43,38 +43,38 @@ Fixes by framework:
Project
Maven Coordinates
Secure by Default
-
Fix
+
Recommendation
XMLDecoder
Java Standard Library
No
-
Don't use XMLDecoder with untrusted user input. It is impossible to secure.
+
Do not use with untrusted user input.
ObjectInputStream
Java Standard Library
No
-
Leverage a validating input stream like org.apache.commons.io.serialization.ValidatingObjectInputStream.
+
Use a validating input stream, such as org.apache.commons.io.serialization.ValidatingObjectInputStream.
FastJson
com.alibaba:fastjson
Partially
-
Call com.alibaba.fastjson.parser.ParserConfig#setSafeMode with the argument true.
+
Call com.alibaba.fastjson.parser.ParserConfig#setSafeMode with the argument true before deserializing untrusted data.
Instantiate the org.yaml.snakeyaml.Yaml instance explicitly with an instance of org.yaml.snakeyaml.constructor.SafeConstructor as an argument.
+
Pass an instance of org.yaml.snakeyaml.constructor.SafeConstructor to org.yaml.snakeyaml.Yaml's constructor before using it to deserialize untrusted data.
FasterXML jackson-databind
com.fasterxml.jackson.core:jackson-databind
Yes
- Don't call com.fasterxml.jackson.databind.ObjectMapper#enableDefaultTyping and don't annotate any object fields with com.fasterxml.jackson.annotation.JsonTypeInfo passing either the CLASS or MINIMAL_CLASS values to the annotation.
+ Don't call com.fasterxml.jackson.databind.ObjectMapper#enableDefaultTyping and don't annotate any object fields with @JsonTypeInfo(CLASS) or @JsonTypeInfo(MINIMAL_CLASS) if untrusted data may be deserialized.
Read this guide.
@@ -82,7 +82,7 @@ Fixes by framework:
Kryo
com.esotericsoftware:kryo and com.esotericsoftware:kryo5
com.esotericsoftware:kryo >= 5.0.0 and com.esotericsoftware:kryo5 Yes
-
Don't call com.esotericsoftware.kryo(5).Kryo#setRegistrationRequired with the argument false.
+
Don't call com.esotericsoftware.kryo(5).Kryo#setRegistrationRequired with the argument false on any Kryo instance that may deserialize untrusted data.
From 4c1c12dd70198906fe547a76f3dc26322e6807c9 Mon Sep 17 00:00:00 2001
From: Florin Coada
Date: Mon, 9 Jan 2023 19:31:15 +0000
Subject: [PATCH 167/381] suggestions in list format
---
.../CWE/CWE-502/UnsafeDeserialization.qhelp | 86 ++++++++-----------
1 file changed, 37 insertions(+), 49 deletions(-)
diff --git a/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.qhelp b/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.qhelp
index aa421154d1e..c991e037791 100644
--- a/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.qhelp
+++ b/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.qhelp
@@ -37,55 +37,43 @@ protection measures.
Recommendations specific to particular frameworks supported by this query:
-
-
-
-
Project
-
Maven Coordinates
-
Secure by Default
-
Recommendation
-
-
-
XMLDecoder
-
Java Standard Library
-
No
-
Do not use with untrusted user input.
-
-
-
ObjectInputStream
-
Java Standard Library
-
No
-
Use a validating input stream, such as org.apache.commons.io.serialization.ValidatingObjectInputStream.
-
-
-
FastJson
-
com.alibaba:fastjson
-
Partially
-
Call com.alibaba.fastjson.parser.ParserConfig#setSafeMode with the argument true before deserializing untrusted data.
Pass an instance of org.yaml.snakeyaml.constructor.SafeConstructor to org.yaml.snakeyaml.Yaml's constructor before using it to deserialize untrusted data.
-
-
-
FasterXML jackson-databind
-
com.fasterxml.jackson.core:jackson-databind
-
Yes
-
- Don't call com.fasterxml.jackson.databind.ObjectMapper#enableDefaultTyping and don't annotate any object fields with @JsonTypeInfo(CLASS) or @JsonTypeInfo(MINIMAL_CLASS) if untrusted data may be deserialized.
- Read this guide.
-
-
-
-
Kryo
-
com.esotericsoftware:kryo and com.esotericsoftware:kryo5
-
com.esotericsoftware:kryo >= 5.0.0 and com.esotericsoftware:kryo5 Yes
-
Don't call com.esotericsoftware.kryo(5).Kryo#setRegistrationRequired with the argument false on any Kryo instance that may deserialize untrusted data.
-
-
-
+
FastJson - com.alibaba:fastjson
+
+
Secure by Default: Partially
+
Recommendation: Call com.alibaba.fastjson.parser.ParserConfig#setSafeMode with the argument true before deserializing untrusted data.
Recommendation: Don't call com.fasterxml.jackson.databind.ObjectMapper#enableDefaultTyping and don't annotate any object fields with com.fasterxml.jackson.annotation.JsonTypeInfo passing either the CLASS or MINIMAL_CLASS values to the annotation.
+ Read this guide.
+
+
+
Kryo - com.esotericsoftware:kryo and com.esotericsoftware:kryo5
+
+
Secure by Default: Yes for com.esotericsoftware:kryo5 and for com.esotericsoftware:kryo >= v5.0.0
+
Recommendation: Don't call com.esotericsoftware.kryo(5).Kryo#setRegistrationRequired with the argument false on any Kryo instance that may deserialize untrusted data.
+
+
+
ObjectInputStream - Java Standard Library
+
+
Secure by Default: No
+
Recommendation: Use a validating input stream, such as org.apache.commons.io.serialization.ValidatingObjectInputStream.
+
+
+
SnakeYAML - org.yaml:snakeyaml
+
+
Secure by Default: No
+
Recommendation: Pass an instance of org.yaml.snakeyaml.constructor.SafeConstructor to org.yaml.snakeyaml.Yaml's constructor before using it to deserialize untrusted data.
+
+
+
XML Decoder - Standard Java Library
+
+
Secure by Defauly: No
+
Recommendation: Do not use with untrusted user input.
+
+
From 38ca68febb941571a547fdefff4699ed6d459b8e Mon Sep 17 00:00:00 2001
From: erik-krogh
Date: Tue, 10 Jan 2023 09:20:21 +0100
Subject: [PATCH 168/381] recognize "-->" as a bad tag filter
---
.../BadTagFilter/BadTagFilter.expected | 1 +
.../Security/CWE-116/BadTagFilter/tst.js | 7 +++++++
.../codeql/regex/nfa/BadTagFilterQuery.qll | 20 +++++++++++++++----
3 files changed, 24 insertions(+), 4 deletions(-)
diff --git a/javascript/ql/test/query-tests/Security/CWE-116/BadTagFilter/BadTagFilter.expected b/javascript/ql/test/query-tests/Security/CWE-116/BadTagFilter/BadTagFilter.expected
index 3d1c86b7b04..675ac7f6f83 100644
--- a/javascript/ql/test/query-tests/Security/CWE-116/BadTagFilter/BadTagFilter.expected
+++ b/javascript/ql/test/query-tests/Security/CWE-116/BadTagFilter/BadTagFilter.expected
@@ -15,3 +15,4 @@
| tst.js:20:3:20:57 | (<[a-z\\/!$]("[^"]*"\|'[^']*'\|[^'">])*>\|) | 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 an HTML comment end tag. |
| tst.js:22:6:22:33 | \|<([^>]*?)> | 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:31:6:31:8 | --> | This regular expression only parses --> and not --!> as a HTML comment end tag. |
diff --git a/javascript/ql/test/query-tests/Security/CWE-116/BadTagFilter/tst.js b/javascript/ql/test/query-tests/Security/CWE-116/BadTagFilter/tst.js
index 2b71107e512..5b294adae1b 100644
--- a/javascript/ql/test/query-tests/Security/CWE-116/BadTagFilter/tst.js
+++ b/javascript/ql/test/query-tests/Security/CWE-116/BadTagFilter/tst.js
@@ -26,3 +26,10 @@ doFilters(filters)
var strip = '", "", "",
"", "",
"", "",
- ""
+ "", "-->", "--!>", "--"
] and
testWithGroups = false
)
@@ -107,6 +113,12 @@ module Make {
") and not --!> as an HTML comment end tag."
)
or
+ // CVE-2021-4231 - matching only "-->" but not "--!>".
+ regexp.matches("-->") and
+ not regexp.matches("--!>") and
+ not regexp.matches("--") and
+ msg = "This regular expression only parses --> and not --!> as a HTML comment end tag."
+ or
regexp.matches("") and
not regexp.matches("") and
not regexp.matches("") and
From dc88bdccc78b6579496aa910e638e60f00a9e598 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
<41898282+github-actions[bot]@users.noreply.github.com>
Date: Tue, 10 Jan 2023 21:04:31 +0000
Subject: [PATCH 169/381] JS: Bump patch version of ML-powered library and
query packs
---
.../ql/experimental/adaptivethreatmodeling/lib/qlpack.yml | 2 +-
.../ql/experimental/adaptivethreatmodeling/src/qlpack.yml | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/javascript/ql/experimental/adaptivethreatmodeling/lib/qlpack.yml b/javascript/ql/experimental/adaptivethreatmodeling/lib/qlpack.yml
index 3cf9c6bb727..c929118886d 100644
--- a/javascript/ql/experimental/adaptivethreatmodeling/lib/qlpack.yml
+++ b/javascript/ql/experimental/adaptivethreatmodeling/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/javascript-experimental-atm-lib
-version: 0.4.4
+version: 0.4.5
extractor: javascript
library: true
groups:
diff --git a/javascript/ql/experimental/adaptivethreatmodeling/src/qlpack.yml b/javascript/ql/experimental/adaptivethreatmodeling/src/qlpack.yml
index bded7e9f770..b3077891878 100644
--- a/javascript/ql/experimental/adaptivethreatmodeling/src/qlpack.yml
+++ b/javascript/ql/experimental/adaptivethreatmodeling/src/qlpack.yml
@@ -1,6 +1,6 @@
name: codeql/javascript-experimental-atm-queries
language: javascript
-version: 0.4.4
+version: 0.4.5
suites: codeql-suites
defaultSuiteFile: codeql-suites/javascript-atm-code-scanning.qls
groups:
From 76e121e3598106571b0fb39d7875455c9320f6b5 Mon Sep 17 00:00:00 2001
From: "github-actions[bot]"
<41898282+github-actions[bot]@users.noreply.github.com>
Date: Tue, 10 Jan 2023 21:11:23 +0000
Subject: [PATCH 170/381] JS: Bump version of ML-powered library and query
packs to 0.4.6
---
.../ql/experimental/adaptivethreatmodeling/lib/qlpack.yml | 2 +-
.../ql/experimental/adaptivethreatmodeling/src/qlpack.yml | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/javascript/ql/experimental/adaptivethreatmodeling/lib/qlpack.yml b/javascript/ql/experimental/adaptivethreatmodeling/lib/qlpack.yml
index c929118886d..bb438789364 100644
--- a/javascript/ql/experimental/adaptivethreatmodeling/lib/qlpack.yml
+++ b/javascript/ql/experimental/adaptivethreatmodeling/lib/qlpack.yml
@@ -1,5 +1,5 @@
name: codeql/javascript-experimental-atm-lib
-version: 0.4.5
+version: 0.4.6
extractor: javascript
library: true
groups:
diff --git a/javascript/ql/experimental/adaptivethreatmodeling/src/qlpack.yml b/javascript/ql/experimental/adaptivethreatmodeling/src/qlpack.yml
index b3077891878..55db320ce03 100644
--- a/javascript/ql/experimental/adaptivethreatmodeling/src/qlpack.yml
+++ b/javascript/ql/experimental/adaptivethreatmodeling/src/qlpack.yml
@@ -1,6 +1,6 @@
name: codeql/javascript-experimental-atm-queries
language: javascript
-version: 0.4.5
+version: 0.4.6
suites: codeql-suites
defaultSuiteFile: codeql-suites/javascript-atm-code-scanning.qls
groups:
From 181a711f045012f91f06565e77ba43a633304f97 Mon Sep 17 00:00:00 2001
From: Jami Cogswell
Date: Tue, 10 Jan 2023 21:06:03 -0500
Subject: [PATCH 171/381] Java: switch Collectors.joining model from neutral to
summary
---
java/ql/lib/ext/java.util.stream.model.yml | 2 +-
java/ql/test/ext/TestModels/Test.java | 4 ++++
2 files changed, 5 insertions(+), 1 deletion(-)
diff --git a/java/ql/lib/ext/java.util.stream.model.yml b/java/ql/lib/ext/java.util.stream.model.yml
index aae79ed57ac..7df9272f4be 100644
--- a/java/ql/lib/ext/java.util.stream.model.yml
+++ b/java/ql/lib/ext/java.util.stream.model.yml
@@ -9,6 +9,7 @@ extensions:
- ["java.util.stream", "BaseStream", True, "sequential", "()", "", "Argument[-1].Element", "ReturnValue.Element", "value", "manual"]
- ["java.util.stream", "BaseStream", True, "spliterator", "()", "", "Argument[-1].Element", "ReturnValue.Element", "value", "manual"]
- ["java.util.stream", "BaseStream", True, "unordered", "()", "", "Argument[-1].Element", "ReturnValue.Element", "value", "manual"]
+ - ["java.util.stream", "Collectors", False, "joining", "(CharSequence)", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["java.util.stream", "Stream", True, "allMatch", "(Predicate)", "", "Argument[-1].Element", "Argument[0].Parameter[0]", "value", "manual"]
- ["java.util.stream", "Stream", True, "anyMatch", "(Predicate)", "", "Argument[-1].Element", "Argument[0].Parameter[0]", "value", "manual"]
- ["java.util.stream", "Stream", True, "collect", "(Supplier,BiConsumer,BiConsumer)", "", "Argument[-1].Element", "Argument[1].Parameter[1]", "value", "manual"]
@@ -92,7 +93,6 @@ extensions:
pack: codeql/java-all
extensible: neutralModel
data:
- - ["java.util.stream", "Collectors", "joining", "(CharSequence)", "manual"]
- ["java.util.stream", "Collectors", "toList", "()", "manual"]
- ["java.util.stream", "Collectors", "toMap", "(Function,Function)", "manual"]
- ["java.util.stream", "Collectors", "toSet", "()", "manual"]
diff --git a/java/ql/test/ext/TestModels/Test.java b/java/ql/test/ext/TestModels/Test.java
index 0b29879d907..7be2728b190 100644
--- a/java/ql/test/ext/TestModels/Test.java
+++ b/java/ql/test/ext/TestModels/Test.java
@@ -11,6 +11,7 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import java.util.function.Supplier;
+import java.util.stream.Collectors;
public class Test {
@@ -128,6 +129,9 @@ public class Test {
AtomicReference ar = new AtomicReference(source());
sink(ar.get()); // $hasValueFlow
+ // java.util.stream
+ sink(Collectors.joining((CharSequence)source())); // $hasTaintFlow
+
// java.util.concurrent
CountDownLatch cdl = new CountDownLatch((int)source());
sink(cdl.getCount()); // $hasValueFlow
From ecf568629bc3fa613cebde7beda35c35f7cab573 Mon Sep 17 00:00:00 2001
From: Tony Torralba
Date: Wed, 11 Jan 2023 09:41:16 +0100
Subject: [PATCH 172/381] Add ExprAggregate as a negative edge in
getConjunctionParentRec
---
ql/ql/src/codeql_ql/style/ConjunctionParent.qll | 1 +
.../queries/style/OmittableExists/OmittableExists.expected | 2 +-
ql/ql/test/queries/style/OmittableExists/Test.qll | 4 ++++
3 files changed, 6 insertions(+), 1 deletion(-)
diff --git a/ql/ql/src/codeql_ql/style/ConjunctionParent.qll b/ql/ql/src/codeql_ql/style/ConjunctionParent.qll
index f3b96f18b11..c39d6d2cb71 100644
--- a/ql/ql/src/codeql_ql/style/ConjunctionParent.qll
+++ b/ql/ql/src/codeql_ql/style/ConjunctionParent.qll
@@ -28,6 +28,7 @@ module ConjunctionParent {
not result instanceof Implication and
not result instanceof Negation and
not result instanceof Predicate and
+ not result instanceof ExprAggregate and
not result instanceof FullAggregate and
not result instanceof Forex and
not result instanceof Forall
diff --git a/ql/ql/test/queries/style/OmittableExists/OmittableExists.expected b/ql/ql/test/queries/style/OmittableExists/OmittableExists.expected
index 7062471b7fb..a0e093c7405 100644
--- a/ql/ql/test/queries/style/OmittableExists/OmittableExists.expected
+++ b/ql/ql/test/queries/style/OmittableExists/OmittableExists.expected
@@ -1 +1 @@
-| Test.qll:18:10:18:14 | i | This exists variable can be omitted by using a don't-care expression $@. | Test.qll:18:29:18:29 | i | in this argument |
+| Test.qll:20:10:20:14 | i | This exists variable can be omitted by using a don't-care expression $@. | Test.qll:20:29:20:29 | i | in this argument |
diff --git a/ql/ql/test/queries/style/OmittableExists/Test.qll b/ql/ql/test/queries/style/OmittableExists/Test.qll
index f9809b9d485..fc020742b85 100644
--- a/ql/ql/test/queries/style/OmittableExists/Test.qll
+++ b/ql/ql/test/queries/style/OmittableExists/Test.qll
@@ -6,6 +6,8 @@ predicate yetAnotherPredicate(int i, int y) { none() }
predicate dbTypePredicate(@location l) { none() }
+string predicateWithResult(int i) { none() }
+
class SmallInt extends int {
SmallInt() { this = [0 .. 10] }
}
@@ -23,6 +25,8 @@ predicate test() {
or
exists(int i | aPredicate(i) and exists(int i2 | i = i2)) // GOOD
or
+ exists(int i | count(predicateWithResult(i)) = 0) // GOOD
+ or
exists(int i | count(int y | yetAnotherPredicate(i, y)) > 0) // GOOD
or
exists(int i | forex(int y | yetAnotherPredicate(i, y))) // GOOD
From ed2dd87bda573aa543c1763d89ed89756419c4e5 Mon Sep 17 00:00:00 2001
From: erik-krogh
Date: Wed, 11 Jan 2023 11:12:57 +0100
Subject: [PATCH 173/381] update the codeql-action version used in QL-for-QL
---
.github/workflows/ql-for-ql-build.yml | 6 +++---
.github/workflows/ql-for-ql-dataset_measure.yml | 2 +-
.github/workflows/ql-for-ql-tests.yml | 2 +-
3 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/.github/workflows/ql-for-ql-build.yml b/.github/workflows/ql-for-ql-build.yml
index 29b8bc16300..144c0e7b71a 100644
--- a/.github/workflows/ql-for-ql-build.yml
+++ b/.github/workflows/ql-for-ql-build.yml
@@ -27,7 +27,7 @@ jobs:
uses: ./.github/actions/find-latest-bundle
- name: Find codeql
id: find-codeql
- uses: github/codeql-action/init@77a8d2d10c0b403a8b4aadbd223dc489ecd22683
+ uses: github/codeql-action/init@45955cb1830b640e2c1603ad72ad542a49d47b96
with:
languages: javascript # does not matter
tools: ${{ steps.find-latest-bundle.outputs.url }}
@@ -137,7 +137,7 @@ jobs:
env:
CONF: ./ql-for-ql-config.yml
- name: Initialize CodeQL
- uses: github/codeql-action/init@77a8d2d10c0b403a8b4aadbd223dc489ecd22683
+ uses: github/codeql-action/init@45955cb1830b640e2c1603ad72ad542a49d47b96
with:
languages: ql
db-location: ${{ runner.temp }}/db
@@ -150,7 +150,7 @@ jobs:
PACK: ${{ runner.temp }}/pack
- name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@77a8d2d10c0b403a8b4aadbd223dc489ecd22683
+ uses: github/codeql-action/analyze@45955cb1830b640e2c1603ad72ad542a49d47b96
with:
category: "ql-for-ql"
- name: Copy sarif file to CWD
diff --git a/.github/workflows/ql-for-ql-dataset_measure.yml b/.github/workflows/ql-for-ql-dataset_measure.yml
index 41f95a686ba..1b99dbeab2e 100644
--- a/.github/workflows/ql-for-ql-dataset_measure.yml
+++ b/.github/workflows/ql-for-ql-dataset_measure.yml
@@ -25,7 +25,7 @@ jobs:
- name: Find codeql
id: find-codeql
- uses: github/codeql-action/init@77a8d2d10c0b403a8b4aadbd223dc489ecd22683
+ uses: github/codeql-action/init@45955cb1830b640e2c1603ad72ad542a49d47b96
with:
languages: javascript # does not matter
- uses: actions/cache@v3
diff --git a/.github/workflows/ql-for-ql-tests.yml b/.github/workflows/ql-for-ql-tests.yml
index ce7963e8f79..8d4459a34d6 100644
--- a/.github/workflows/ql-for-ql-tests.yml
+++ b/.github/workflows/ql-for-ql-tests.yml
@@ -22,7 +22,7 @@ jobs:
- uses: actions/checkout@v3
- name: Find codeql
id: find-codeql
- uses: github/codeql-action/init@77a8d2d10c0b403a8b4aadbd223dc489ecd22683
+ uses: github/codeql-action/init@45955cb1830b640e2c1603ad72ad542a49d47b96
with:
languages: javascript # does not matter
- uses: actions/cache@v3
From 74a58f64aad2c4f4b7c1b742f6be6387c106d9c3 Mon Sep 17 00:00:00 2001
From: erik-krogh
Date: Wed, 11 Jan 2023 11:08:12 +0100
Subject: [PATCH 174/381] move queries folder instead of .cache folder now that
we got .qlx
---
.github/workflows/ql-for-ql-build.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/ql-for-ql-build.yml b/.github/workflows/ql-for-ql-build.yml
index 144c0e7b71a..30c15e035a3 100644
--- a/.github/workflows/ql-for-ql-build.yml
+++ b/.github/workflows/ql-for-ql-build.yml
@@ -145,7 +145,7 @@ jobs:
tools: ${{ steps.find-latest-bundle.outputs.url }}
- name: Move pack cache
run: |
- cp -r ${PACK}/.cache ql/ql/src/.cache
+ cp -r ${PACK}/queries ql/ql/src
env:
PACK: ${{ runner.temp }}/pack
From 3fa6a7cbffe55051932a4676d2bb5c9548375722 Mon Sep 17 00:00:00 2001
From: Erik Krogh Kristensen
Date: Wed, 11 Jan 2023 12:29:15 +0100
Subject: [PATCH 175/381] cache -> queries
Co-authored-by: Tony Torralba
---
.github/workflows/ql-for-ql-build.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/.github/workflows/ql-for-ql-build.yml b/.github/workflows/ql-for-ql-build.yml
index 30c15e035a3..393974acab8 100644
--- a/.github/workflows/ql-for-ql-build.yml
+++ b/.github/workflows/ql-for-ql-build.yml
@@ -143,7 +143,7 @@ jobs:
db-location: ${{ runner.temp }}/db
config-file: ./ql-for-ql-config.yml
tools: ${{ steps.find-latest-bundle.outputs.url }}
- - name: Move pack cache
+ - name: Move pack queries
run: |
cp -r ${PACK}/queries ql/ql/src
env:
From 178fd0e9e151674f86c34f2d59c2d2b9c1e5e05f Mon Sep 17 00:00:00 2001
From: Michael Nebel
Date: Tue, 20 Dec 2022 13:39:36 +0100
Subject: [PATCH 176/381] C#/Java: Remove all dashes in mode-generator.
---
.github/workflows/mad_modelDiff.yml | 4 ++--
.github/workflows/mad_regenerate-models.yml | 2 +-
.../utils/model-generator/CaptureDiscardedSummaryModels.ql | 2 +-
csharp/ql/src/utils/model-generator/CaptureNeutralModels.ql | 4 ++--
csharp/ql/src/utils/model-generator/CaptureSinkModels.ql | 4 ++--
csharp/ql/src/utils/model-generator/CaptureSourceModels.ql | 4 ++--
csharp/ql/src/utils/model-generator/CaptureSummaryModels.ql | 4 ++--
.../utils/model-generator/CaptureTypeBasedSummaryModels.ql | 4 ++--
.../utils/model-generator/dataflow/CaptureNeutralModels.qlref | 2 +-
.../utils/model-generator/dataflow/CaptureSinkModels.qlref | 2 +-
.../utils/model-generator/dataflow/CaptureSourceModels.qlref | 2 +-
.../utils/model-generator/dataflow/CaptureSummaryModels.qlref | 2 +-
.../typebasedflow/CaptureTypeBasedSummaryModels.qlref | 2 +-
java/ql/src/utils/model-generator/CaptureNeutralModels.ql | 4 ++--
java/ql/src/utils/model-generator/CaptureSinkModels.ql | 4 ++--
java/ql/src/utils/model-generator/CaptureSourceModels.ql | 4 ++--
java/ql/src/utils/model-generator/CaptureSummaryModels.ql | 4 ++--
.../utils/model-generator/CaptureTypeBasedSummaryModels.ql | 4 ++--
java/ql/src/utils/model-generator/RegenerateModels.py | 2 +-
.../utils/model-generator/dataflow/CaptureNeutralModels.qlref | 2 +-
.../utils/model-generator/dataflow/CaptureSinkModels.qlref | 2 +-
.../utils/model-generator/dataflow/CaptureSourceModels.qlref | 2 +-
.../utils/model-generator/dataflow/CaptureSummaryModels.qlref | 2 +-
misc/scripts/models-as-data/generate_flow_model.py | 2 +-
misc/suite-helpers/code-scanning-selectors.yml | 2 +-
misc/suite-helpers/security-and-quality-selectors.yml | 2 +-
misc/suite-helpers/security-extended-selectors.yml | 2 +-
27 files changed, 38 insertions(+), 38 deletions(-)
diff --git a/.github/workflows/mad_modelDiff.yml b/.github/workflows/mad_modelDiff.yml
index 586b1576bd6..2affe5f3bd7 100644
--- a/.github/workflows/mad_modelDiff.yml
+++ b/.github/workflows/mad_modelDiff.yml
@@ -11,7 +11,7 @@ on:
branches:
- main
paths:
- - "java/ql/src/utils/model-generator/**/*.*"
+ - "java/ql/src/utils/modelgenerator/**/*.*"
- ".github/workflows/mad_modelDiff.yml"
permissions:
@@ -61,7 +61,7 @@ jobs:
DATABASE=$2
cd codeql-$QL_VARIANT
SHORTNAME=`basename $DATABASE`
- python java/ql/src/utils/model-generator/GenerateFlowModel.py --with-summaries --with-sinks $DATABASE ${SHORTNAME}.temp.model.yml
+ python java/ql/src/utils/modelgenerator/GenerateFlowModel.py --with-summaries --with-sinks $DATABASE ${SHORTNAME}.temp.model.yml
mv java/ql/lib/ext/generated/${SHORTNAME}.temp.model.yml $MODELS/${SHORTNAME}Generated_${QL_VARIANT}.model.yml
cd ..
}
diff --git a/.github/workflows/mad_regenerate-models.yml b/.github/workflows/mad_regenerate-models.yml
index d92e3652d5c..6b3d0347a86 100644
--- a/.github/workflows/mad_regenerate-models.yml
+++ b/.github/workflows/mad_regenerate-models.yml
@@ -50,7 +50,7 @@ jobs:
SLUG: ${{ matrix.slug }}
run: |
SHORTNAME=${SLUG//[^a-zA-Z0-9_]/}
- java/ql/src/utils/model-generator/RegenerateModels.py "${SLUG}" dbs/${SHORTNAME}
+ java/ql/src/utils/modelgenerator/RegenerateModels.py "${SLUG}" dbs/${SHORTNAME}
- name: Stage changes
run: |
find java -name "*.model.yml" -print0 | xargs -0 git add
diff --git a/csharp/ql/src/utils/model-generator/CaptureDiscardedSummaryModels.ql b/csharp/ql/src/utils/model-generator/CaptureDiscardedSummaryModels.ql
index 695a928e2f8..9e71580b552 100644
--- a/csharp/ql/src/utils/model-generator/CaptureDiscardedSummaryModels.ql
+++ b/csharp/ql/src/utils/model-generator/CaptureDiscardedSummaryModels.ql
@@ -1,7 +1,7 @@
/**
* @name Capture discarded summary models.
* @description Finds summary models that are discarded as handwritten counterparts exist.
- * @id cs/utils/model-generator/discarded-summary-models
+ * @id cs/utils/modelgenerator/discarded-summary-models
*/
import semmle.code.csharp.dataflow.ExternalFlow
diff --git a/csharp/ql/src/utils/model-generator/CaptureNeutralModels.ql b/csharp/ql/src/utils/model-generator/CaptureNeutralModels.ql
index 9cf2b81ba7c..a7e4be6ff2e 100644
--- a/csharp/ql/src/utils/model-generator/CaptureNeutralModels.ql
+++ b/csharp/ql/src/utils/model-generator/CaptureNeutralModels.ql
@@ -2,8 +2,8 @@
* @name Capture neutral models.
* @description Finds neutral models to be used by other queries.
* @kind diagnostic
- * @id cs/utils/model-generator/neutral-models
- * @tags model-generator
+ * @id cs/utils/modelgenerator/neutral-models
+ * @tags modelgenerator
*/
import semmle.code.csharp.dataflow.ExternalFlow
diff --git a/csharp/ql/src/utils/model-generator/CaptureSinkModels.ql b/csharp/ql/src/utils/model-generator/CaptureSinkModels.ql
index 68b3ec91974..c19971b098a 100644
--- a/csharp/ql/src/utils/model-generator/CaptureSinkModels.ql
+++ b/csharp/ql/src/utils/model-generator/CaptureSinkModels.ql
@@ -2,8 +2,8 @@
* @name Capture sink models.
* @description Finds public methods that act as sinks as they flow into a known sink.
* @kind diagnostic
- * @id cs/utils/model-generator/sink-models
- * @tags model-generator
+ * @id cs/utils/modelgenerator/sink-models
+ * @tags modelgenerator
*/
import utils.modelgenerator.internal.CaptureModels
diff --git a/csharp/ql/src/utils/model-generator/CaptureSourceModels.ql b/csharp/ql/src/utils/model-generator/CaptureSourceModels.ql
index 9c3c87d8251..913624e315a 100644
--- a/csharp/ql/src/utils/model-generator/CaptureSourceModels.ql
+++ b/csharp/ql/src/utils/model-generator/CaptureSourceModels.ql
@@ -2,8 +2,8 @@
* @name Capture source models.
* @description Finds APIs that act as sources as they expose already known sources.
* @kind diagnostic
- * @id cs/utils/model-generator/source-models
- * @tags model-generator
+ * @id cs/utils/modelgenerator/source-models
+ * @tags modelgenerator
*/
import utils.modelgenerator.internal.CaptureModels
diff --git a/csharp/ql/src/utils/model-generator/CaptureSummaryModels.ql b/csharp/ql/src/utils/model-generator/CaptureSummaryModels.ql
index 0dd22e3babb..eadb7e005f3 100644
--- a/csharp/ql/src/utils/model-generator/CaptureSummaryModels.ql
+++ b/csharp/ql/src/utils/model-generator/CaptureSummaryModels.ql
@@ -2,8 +2,8 @@
* @name Capture summary models.
* @description Finds applicable summary models to be used by other queries.
* @kind diagnostic
- * @id cs/utils/model-generator/summary-models
- * @tags model-generator
+ * @id cs/utils/modelgenerator/summary-models
+ * @tags modelgenerator
*/
import semmle.code.csharp.dataflow.ExternalFlow
diff --git a/csharp/ql/src/utils/model-generator/CaptureTypeBasedSummaryModels.ql b/csharp/ql/src/utils/model-generator/CaptureTypeBasedSummaryModels.ql
index f15a786f53f..d2bb7c39826 100644
--- a/csharp/ql/src/utils/model-generator/CaptureTypeBasedSummaryModels.ql
+++ b/csharp/ql/src/utils/model-generator/CaptureTypeBasedSummaryModels.ql
@@ -2,8 +2,8 @@
* @name Capture typed based summary models.
* @description Finds applicable summary models to be used by other queries.
* @kind diagnostic
- * @id cs/utils/model-generator/summary-models-typed-based
- * @tags model-generator
+ * @id cs/utils/modelgenerator/summary-models-typed-based
+ * @tags modelgenerator
*/
import utils.modelgenerator.internal.CaptureTypeBasedSummaryModels
diff --git a/csharp/ql/test/utils/model-generator/dataflow/CaptureNeutralModels.qlref b/csharp/ql/test/utils/model-generator/dataflow/CaptureNeutralModels.qlref
index cb6ef7faa65..851ddc0d294 100644
--- a/csharp/ql/test/utils/model-generator/dataflow/CaptureNeutralModels.qlref
+++ b/csharp/ql/test/utils/model-generator/dataflow/CaptureNeutralModels.qlref
@@ -1 +1 @@
-utils/model-generator/CaptureNeutralModels.ql
\ No newline at end of file
+utils/modelgenerator/CaptureNeutralModels.ql
\ No newline at end of file
diff --git a/csharp/ql/test/utils/model-generator/dataflow/CaptureSinkModels.qlref b/csharp/ql/test/utils/model-generator/dataflow/CaptureSinkModels.qlref
index c478ac760c4..36d2f144247 100644
--- a/csharp/ql/test/utils/model-generator/dataflow/CaptureSinkModels.qlref
+++ b/csharp/ql/test/utils/model-generator/dataflow/CaptureSinkModels.qlref
@@ -1 +1 @@
-utils/model-generator/CaptureSinkModels.ql
\ No newline at end of file
+utils/modelgenerator/CaptureSinkModels.ql
\ No newline at end of file
diff --git a/csharp/ql/test/utils/model-generator/dataflow/CaptureSourceModels.qlref b/csharp/ql/test/utils/model-generator/dataflow/CaptureSourceModels.qlref
index 10593c28e92..6bbb499fc27 100644
--- a/csharp/ql/test/utils/model-generator/dataflow/CaptureSourceModels.qlref
+++ b/csharp/ql/test/utils/model-generator/dataflow/CaptureSourceModels.qlref
@@ -1 +1 @@
-utils/model-generator/CaptureSourceModels.ql
\ No newline at end of file
+utils/modelgenerator/CaptureSourceModels.ql
\ No newline at end of file
diff --git a/csharp/ql/test/utils/model-generator/dataflow/CaptureSummaryModels.qlref b/csharp/ql/test/utils/model-generator/dataflow/CaptureSummaryModels.qlref
index 1ebf2afb19b..d751f3823f3 100644
--- a/csharp/ql/test/utils/model-generator/dataflow/CaptureSummaryModels.qlref
+++ b/csharp/ql/test/utils/model-generator/dataflow/CaptureSummaryModels.qlref
@@ -1 +1 @@
-utils/model-generator/CaptureSummaryModels.ql
\ No newline at end of file
+utils/modelgenerator/CaptureSummaryModels.ql
\ No newline at end of file
diff --git a/csharp/ql/test/utils/model-generator/typebasedflow/CaptureTypeBasedSummaryModels.qlref b/csharp/ql/test/utils/model-generator/typebasedflow/CaptureTypeBasedSummaryModels.qlref
index 99c0975a4c2..73821d0ff84 100644
--- a/csharp/ql/test/utils/model-generator/typebasedflow/CaptureTypeBasedSummaryModels.qlref
+++ b/csharp/ql/test/utils/model-generator/typebasedflow/CaptureTypeBasedSummaryModels.qlref
@@ -1 +1 @@
-utils/model-generator/CaptureTypeBasedSummaryModels.ql
\ No newline at end of file
+utils/modelgenerator/CaptureTypeBasedSummaryModels.ql
\ No newline at end of file
diff --git a/java/ql/src/utils/model-generator/CaptureNeutralModels.ql b/java/ql/src/utils/model-generator/CaptureNeutralModels.ql
index 96744de89b6..32d4ceb3aa9 100644
--- a/java/ql/src/utils/model-generator/CaptureNeutralModels.ql
+++ b/java/ql/src/utils/model-generator/CaptureNeutralModels.ql
@@ -2,8 +2,8 @@
* @name Capture neutral models.
* @description Finds neutral models to be used by other queries.
* @kind diagnostic
- * @id java/utils/model-generator/neutral-models
- * @tags model-generator
+ * @id java/utils/modelgenerator/neutral-models
+ * @tags modelgenerator
*/
import utils.modelgenerator.internal.CaptureModels
diff --git a/java/ql/src/utils/model-generator/CaptureSinkModels.ql b/java/ql/src/utils/model-generator/CaptureSinkModels.ql
index f047a8a13af..3d2cd5933ff 100644
--- a/java/ql/src/utils/model-generator/CaptureSinkModels.ql
+++ b/java/ql/src/utils/model-generator/CaptureSinkModels.ql
@@ -2,8 +2,8 @@
* @name Capture sink models.
* @description Finds public methods that act as sinks as they flow into a known sink.
* @kind diagnostic
- * @id java/utils/model-generator/sink-models
- * @tags model-generator
+ * @id java/utils/modelgenerator/sink-models
+ * @tags modelgenerator
*/
import utils.modelgenerator.internal.CaptureModels
diff --git a/java/ql/src/utils/model-generator/CaptureSourceModels.ql b/java/ql/src/utils/model-generator/CaptureSourceModels.ql
index 7dfc8e0ad34..fffc43adc78 100644
--- a/java/ql/src/utils/model-generator/CaptureSourceModels.ql
+++ b/java/ql/src/utils/model-generator/CaptureSourceModels.ql
@@ -2,8 +2,8 @@
* @name Capture source models.
* @description Finds APIs that act as sources as they expose already known sources.
* @kind diagnostic
- * @id java/utils/model-generator/source-models
- * @tags model-generator
+ * @id java/utils/modelgenerator/source-models
+ * @tags modelgenerator
*/
import utils.modelgenerator.internal.CaptureModels
diff --git a/java/ql/src/utils/model-generator/CaptureSummaryModels.ql b/java/ql/src/utils/model-generator/CaptureSummaryModels.ql
index a8d23ca5b34..33a21940d39 100644
--- a/java/ql/src/utils/model-generator/CaptureSummaryModels.ql
+++ b/java/ql/src/utils/model-generator/CaptureSummaryModels.ql
@@ -2,8 +2,8 @@
* @name Capture summary models.
* @description Finds applicable summary models to be used by other queries.
* @kind diagnostic
- * @id java/utils/model-generator/summary-models
- * @tags model-generator
+ * @id java/utils/modelgenerator/summary-models
+ * @tags modelgenerator
*/
import utils.modelgenerator.internal.CaptureModels
diff --git a/java/ql/src/utils/model-generator/CaptureTypeBasedSummaryModels.ql b/java/ql/src/utils/model-generator/CaptureTypeBasedSummaryModels.ql
index 1cdb5fe959f..959b6dc7f78 100644
--- a/java/ql/src/utils/model-generator/CaptureTypeBasedSummaryModels.ql
+++ b/java/ql/src/utils/model-generator/CaptureTypeBasedSummaryModels.ql
@@ -2,8 +2,8 @@
* @name Capture typed based summary models.
* @description Finds applicable summary models to be used by other queries.
* @kind diagnostic
- * @id java/utils/model-generator/summary-models-typed-based
- * @tags model-generator
+ * @id java/utils/modelgenerator/summary-models-typed-based
+ * @tags modelgenerator
*/
import utils.modelgenerator.internal.CaptureTypeBasedSummaryModels
diff --git a/java/ql/src/utils/model-generator/RegenerateModels.py b/java/ql/src/utils/model-generator/RegenerateModels.py
index 6bea57793a0..1f7df71776b 100755
--- a/java/ql/src/utils/model-generator/RegenerateModels.py
+++ b/java/ql/src/utils/model-generator/RegenerateModels.py
@@ -35,7 +35,7 @@ def regenerateModel(lgtmSlug, extractedDb):
sys.exit(1)
modelFile = lgtmSlugToModelFile[lgtmSlug]
codeQlRoot = findGitRoot()
- subprocess.check_call([codeQlRoot + "/java/ql/src/utils/model-generator/GenerateFlowModel.py",
+ subprocess.check_call([codeQlRoot + "/java/ql/src/utils/modelgenerator/GenerateFlowModel.py",
"--with-summaries", "--with-sinks", "--with-neutrals",
extractedDb, modelFile])
print("Regenerated " + modelFile)
diff --git a/java/ql/test/utils/model-generator/dataflow/CaptureNeutralModels.qlref b/java/ql/test/utils/model-generator/dataflow/CaptureNeutralModels.qlref
index cb6ef7faa65..851ddc0d294 100644
--- a/java/ql/test/utils/model-generator/dataflow/CaptureNeutralModels.qlref
+++ b/java/ql/test/utils/model-generator/dataflow/CaptureNeutralModels.qlref
@@ -1 +1 @@
-utils/model-generator/CaptureNeutralModels.ql
\ No newline at end of file
+utils/modelgenerator/CaptureNeutralModels.ql
\ No newline at end of file
diff --git a/java/ql/test/utils/model-generator/dataflow/CaptureSinkModels.qlref b/java/ql/test/utils/model-generator/dataflow/CaptureSinkModels.qlref
index c478ac760c4..36d2f144247 100644
--- a/java/ql/test/utils/model-generator/dataflow/CaptureSinkModels.qlref
+++ b/java/ql/test/utils/model-generator/dataflow/CaptureSinkModels.qlref
@@ -1 +1 @@
-utils/model-generator/CaptureSinkModels.ql
\ No newline at end of file
+utils/modelgenerator/CaptureSinkModels.ql
\ No newline at end of file
diff --git a/java/ql/test/utils/model-generator/dataflow/CaptureSourceModels.qlref b/java/ql/test/utils/model-generator/dataflow/CaptureSourceModels.qlref
index 10593c28e92..6bbb499fc27 100644
--- a/java/ql/test/utils/model-generator/dataflow/CaptureSourceModels.qlref
+++ b/java/ql/test/utils/model-generator/dataflow/CaptureSourceModels.qlref
@@ -1 +1 @@
-utils/model-generator/CaptureSourceModels.ql
\ No newline at end of file
+utils/modelgenerator/CaptureSourceModels.ql
\ No newline at end of file
diff --git a/java/ql/test/utils/model-generator/dataflow/CaptureSummaryModels.qlref b/java/ql/test/utils/model-generator/dataflow/CaptureSummaryModels.qlref
index 1ebf2afb19b..d751f3823f3 100644
--- a/java/ql/test/utils/model-generator/dataflow/CaptureSummaryModels.qlref
+++ b/java/ql/test/utils/model-generator/dataflow/CaptureSummaryModels.qlref
@@ -1 +1 @@
-utils/model-generator/CaptureSummaryModels.ql
\ No newline at end of file
+utils/modelgenerator/CaptureSummaryModels.ql
\ No newline at end of file
diff --git a/misc/scripts/models-as-data/generate_flow_model.py b/misc/scripts/models-as-data/generate_flow_model.py
index 30f90000d4c..c9699d1585b 100644
--- a/misc/scripts/models-as-data/generate_flow_model.py
+++ b/misc/scripts/models-as-data/generate_flow_model.py
@@ -33,7 +33,7 @@ class Generator:
self.generateNeutrals = False
self.generateTypeBasedSummaries = False
self.dryRun = False
- self.dirname = "model-generator"
+ self.dirname = "modelgenerator"
def printHelp(self):
diff --git a/misc/suite-helpers/code-scanning-selectors.yml b/misc/suite-helpers/code-scanning-selectors.yml
index d587ffa7b34..a237728316b 100644
--- a/misc/suite-helpers/code-scanning-selectors.yml
+++ b/misc/suite-helpers/code-scanning-selectors.yml
@@ -30,4 +30,4 @@
- /Diagnostics/Internal/.*/
- exclude:
tags contain:
- - model-generator
+ - modelgenerator
diff --git a/misc/suite-helpers/security-and-quality-selectors.yml b/misc/suite-helpers/security-and-quality-selectors.yml
index c5068f87fd7..90a22352b80 100644
--- a/misc/suite-helpers/security-and-quality-selectors.yml
+++ b/misc/suite-helpers/security-and-quality-selectors.yml
@@ -31,4 +31,4 @@
- /Diagnostics/Internal/.*/
- exclude:
tags contain:
- - model-generator
+ - modelgenerator
diff --git a/misc/suite-helpers/security-extended-selectors.yml b/misc/suite-helpers/security-extended-selectors.yml
index 9d2f5851b78..aff154d0d30 100644
--- a/misc/suite-helpers/security-extended-selectors.yml
+++ b/misc/suite-helpers/security-extended-selectors.yml
@@ -36,4 +36,4 @@
- /Diagnostics/Internal/.*/
- exclude:
tags contain:
- - model-generator
+ - modelgenerator
From 787b4743eece4141bc330a48557e249134df5ce3 Mon Sep 17 00:00:00 2001
From: Michael Nebel
Date: Tue, 20 Dec 2022 13:55:29 +0100
Subject: [PATCH 177/381] C#/Java: Rename the directories containing the model
generator and tests.
---
.../CaptureDiscardedSummaryModels.ql | 0
.../{model-generator => modelgenerator}/CaptureNeutralModels.ql | 0
.../{model-generator => modelgenerator}/CaptureSinkModels.ql | 0
.../{model-generator => modelgenerator}/CaptureSourceModels.ql | 0
.../{model-generator => modelgenerator}/CaptureSummaryModels.ql | 0
.../CaptureTypeBasedSummaryModels.ql | 0
.../{model-generator => modelgenerator}/GenerateFlowModel.py | 0
.../dataflow/CaptureNeutralModels.expected | 0
.../dataflow/CaptureNeutralModels.qlref | 0
.../dataflow/CaptureSinkModels.expected | 0
.../dataflow/CaptureSinkModels.qlref | 0
.../dataflow/CaptureSourceModels.expected | 0
.../dataflow/CaptureSourceModels.qlref | 0
.../dataflow/CaptureSummaryModels.expected | 0
.../dataflow/CaptureSummaryModels.qlref | 0
.../{model-generator => modelgenerator}/dataflow/NoSummaries.cs | 0
.../utils/{model-generator => modelgenerator}/dataflow/Sinks.cs | 0
.../utils/{model-generator => modelgenerator}/dataflow/Sources.cs | 0
.../{model-generator => modelgenerator}/dataflow/Summaries.cs | 0
.../utils/{model-generator => modelgenerator}/dataflow/options | 0
.../typebasedflow/CaptureTypeBasedSummaryModels.expected | 0
.../typebasedflow/CaptureTypeBasedSummaryModels.qlref | 0
.../typebasedflow/TypeBasedSummaries.cs | 0
.../{model-generator => modelgenerator}/CaptureNeutralModels.ql | 0
.../{model-generator => modelgenerator}/CaptureSinkModels.ql | 0
.../{model-generator => modelgenerator}/CaptureSourceModels.ql | 0
.../{model-generator => modelgenerator}/CaptureSummaryModels.ql | 0
.../CaptureTypeBasedSummaryModels.ql | 0
.../{model-generator => modelgenerator}/GenerateFlowModel.py | 0
.../utils/{model-generator => modelgenerator}/RegenerateModels.py | 0
.../dataflow/CaptureNeutralModels.expected | 0
.../dataflow/CaptureNeutralModels.qlref | 0
.../dataflow/CaptureSinkModels.expected | 0
.../dataflow/CaptureSinkModels.qlref | 0
.../dataflow/CaptureSourceModels.expected | 0
.../dataflow/CaptureSourceModels.qlref | 0
.../dataflow/CaptureSummaryModels.expected | 0
.../dataflow/CaptureSummaryModels.qlref | 0
.../dataflow/p/AbstractImplOfExternalSPI.java | 0
.../{model-generator => modelgenerator}/dataflow/p/Factory.java | 0
.../dataflow/p/FinalClass.java | 0
.../{model-generator => modelgenerator}/dataflow/p/FluentAPI.java | 0
.../dataflow/p/ImmutablePojo.java | 0
.../dataflow/p/ImplOfExternalSPI.java | 0
.../dataflow/p/InnerClasses.java | 0
.../dataflow/p/InnerHolder.java | 0
.../{model-generator => modelgenerator}/dataflow/p/Joiner.java | 0
.../dataflow/p/MultipleImpls.java | 0
.../{model-generator => modelgenerator}/dataflow/p/ParamFlow.java | 0
.../{model-generator => modelgenerator}/dataflow/p/Pojo.java | 0
.../dataflow/p/PrivateFlowViaPublicInterface.java | 0
.../{model-generator => modelgenerator}/dataflow/p/Sinks.java | 0
.../{model-generator => modelgenerator}/dataflow/p/SomeEnum.java | 0
.../{model-generator => modelgenerator}/dataflow/p/Sources.java | 0
.../typebasedflow/CaptureTypeBasedSummaryModels.expected | 0
.../typebasedflow/CaptureTypeBasedSummaryModels.ql | 0
.../typebasedflow/p/MyFunction.java | 0
.../typebasedflow/p/Stream.java | 0
.../typebasedflow/p/TypeBasedCollection.java | 0
.../typebasedflow/p/TypeBasedComplex.java | 0
.../typebasedflow/p/TypeBasedSimple.java | 0
61 files changed, 0 insertions(+), 0 deletions(-)
rename csharp/ql/src/utils/{model-generator => modelgenerator}/CaptureDiscardedSummaryModels.ql (100%)
rename csharp/ql/src/utils/{model-generator => modelgenerator}/CaptureNeutralModels.ql (100%)
rename csharp/ql/src/utils/{model-generator => modelgenerator}/CaptureSinkModels.ql (100%)
rename csharp/ql/src/utils/{model-generator => modelgenerator}/CaptureSourceModels.ql (100%)
rename csharp/ql/src/utils/{model-generator => modelgenerator}/CaptureSummaryModels.ql (100%)
rename csharp/ql/src/utils/{model-generator => modelgenerator}/CaptureTypeBasedSummaryModels.ql (100%)
rename csharp/ql/src/utils/{model-generator => modelgenerator}/GenerateFlowModel.py (100%)
rename csharp/ql/test/utils/{model-generator => modelgenerator}/dataflow/CaptureNeutralModels.expected (100%)
rename csharp/ql/test/utils/{model-generator => modelgenerator}/dataflow/CaptureNeutralModels.qlref (100%)
rename csharp/ql/test/utils/{model-generator => modelgenerator}/dataflow/CaptureSinkModels.expected (100%)
rename csharp/ql/test/utils/{model-generator => modelgenerator}/dataflow/CaptureSinkModels.qlref (100%)
rename csharp/ql/test/utils/{model-generator => modelgenerator}/dataflow/CaptureSourceModels.expected (100%)
rename csharp/ql/test/utils/{model-generator => modelgenerator}/dataflow/CaptureSourceModels.qlref (100%)
rename csharp/ql/test/utils/{model-generator => modelgenerator}/dataflow/CaptureSummaryModels.expected (100%)
rename csharp/ql/test/utils/{model-generator => modelgenerator}/dataflow/CaptureSummaryModels.qlref (100%)
rename csharp/ql/test/utils/{model-generator => modelgenerator}/dataflow/NoSummaries.cs (100%)
rename csharp/ql/test/utils/{model-generator => modelgenerator}/dataflow/Sinks.cs (100%)
rename csharp/ql/test/utils/{model-generator => modelgenerator}/dataflow/Sources.cs (100%)
rename csharp/ql/test/utils/{model-generator => modelgenerator}/dataflow/Summaries.cs (100%)
rename csharp/ql/test/utils/{model-generator => modelgenerator}/dataflow/options (100%)
rename csharp/ql/test/utils/{model-generator => modelgenerator}/typebasedflow/CaptureTypeBasedSummaryModels.expected (100%)
rename csharp/ql/test/utils/{model-generator => modelgenerator}/typebasedflow/CaptureTypeBasedSummaryModels.qlref (100%)
rename csharp/ql/test/utils/{model-generator => modelgenerator}/typebasedflow/TypeBasedSummaries.cs (100%)
rename java/ql/src/utils/{model-generator => modelgenerator}/CaptureNeutralModels.ql (100%)
rename java/ql/src/utils/{model-generator => modelgenerator}/CaptureSinkModels.ql (100%)
rename java/ql/src/utils/{model-generator => modelgenerator}/CaptureSourceModels.ql (100%)
rename java/ql/src/utils/{model-generator => modelgenerator}/CaptureSummaryModels.ql (100%)
rename java/ql/src/utils/{model-generator => modelgenerator}/CaptureTypeBasedSummaryModels.ql (100%)
rename java/ql/src/utils/{model-generator => modelgenerator}/GenerateFlowModel.py (100%)
rename java/ql/src/utils/{model-generator => modelgenerator}/RegenerateModels.py (100%)
rename java/ql/test/utils/{model-generator => modelgenerator}/dataflow/CaptureNeutralModels.expected (100%)
rename java/ql/test/utils/{model-generator => modelgenerator}/dataflow/CaptureNeutralModels.qlref (100%)
rename java/ql/test/utils/{model-generator => modelgenerator}/dataflow/CaptureSinkModels.expected (100%)
rename java/ql/test/utils/{model-generator => modelgenerator}/dataflow/CaptureSinkModels.qlref (100%)
rename java/ql/test/utils/{model-generator => modelgenerator}/dataflow/CaptureSourceModels.expected (100%)
rename java/ql/test/utils/{model-generator => modelgenerator}/dataflow/CaptureSourceModels.qlref (100%)
rename java/ql/test/utils/{model-generator => modelgenerator}/dataflow/CaptureSummaryModels.expected (100%)
rename java/ql/test/utils/{model-generator => modelgenerator}/dataflow/CaptureSummaryModels.qlref (100%)
rename java/ql/test/utils/{model-generator => modelgenerator}/dataflow/p/AbstractImplOfExternalSPI.java (100%)
rename java/ql/test/utils/{model-generator => modelgenerator}/dataflow/p/Factory.java (100%)
rename java/ql/test/utils/{model-generator => modelgenerator}/dataflow/p/FinalClass.java (100%)
rename java/ql/test/utils/{model-generator => modelgenerator}/dataflow/p/FluentAPI.java (100%)
rename java/ql/test/utils/{model-generator => modelgenerator}/dataflow/p/ImmutablePojo.java (100%)
rename java/ql/test/utils/{model-generator => modelgenerator}/dataflow/p/ImplOfExternalSPI.java (100%)
rename java/ql/test/utils/{model-generator => modelgenerator}/dataflow/p/InnerClasses.java (100%)
rename java/ql/test/utils/{model-generator => modelgenerator}/dataflow/p/InnerHolder.java (100%)
rename java/ql/test/utils/{model-generator => modelgenerator}/dataflow/p/Joiner.java (100%)
rename java/ql/test/utils/{model-generator => modelgenerator}/dataflow/p/MultipleImpls.java (100%)
rename java/ql/test/utils/{model-generator => modelgenerator}/dataflow/p/ParamFlow.java (100%)
rename java/ql/test/utils/{model-generator => modelgenerator}/dataflow/p/Pojo.java (100%)
rename java/ql/test/utils/{model-generator => modelgenerator}/dataflow/p/PrivateFlowViaPublicInterface.java (100%)
rename java/ql/test/utils/{model-generator => modelgenerator}/dataflow/p/Sinks.java (100%)
rename java/ql/test/utils/{model-generator => modelgenerator}/dataflow/p/SomeEnum.java (100%)
rename java/ql/test/utils/{model-generator => modelgenerator}/dataflow/p/Sources.java (100%)
rename java/ql/test/utils/{model-generator => modelgenerator}/typebasedflow/CaptureTypeBasedSummaryModels.expected (100%)
rename java/ql/test/utils/{model-generator => modelgenerator}/typebasedflow/CaptureTypeBasedSummaryModels.ql (100%)
rename java/ql/test/utils/{model-generator => modelgenerator}/typebasedflow/p/MyFunction.java (100%)
rename java/ql/test/utils/{model-generator => modelgenerator}/typebasedflow/p/Stream.java (100%)
rename java/ql/test/utils/{model-generator => modelgenerator}/typebasedflow/p/TypeBasedCollection.java (100%)
rename java/ql/test/utils/{model-generator => modelgenerator}/typebasedflow/p/TypeBasedComplex.java (100%)
rename java/ql/test/utils/{model-generator => modelgenerator}/typebasedflow/p/TypeBasedSimple.java (100%)
diff --git a/csharp/ql/src/utils/model-generator/CaptureDiscardedSummaryModels.ql b/csharp/ql/src/utils/modelgenerator/CaptureDiscardedSummaryModels.ql
similarity index 100%
rename from csharp/ql/src/utils/model-generator/CaptureDiscardedSummaryModels.ql
rename to csharp/ql/src/utils/modelgenerator/CaptureDiscardedSummaryModels.ql
diff --git a/csharp/ql/src/utils/model-generator/CaptureNeutralModels.ql b/csharp/ql/src/utils/modelgenerator/CaptureNeutralModels.ql
similarity index 100%
rename from csharp/ql/src/utils/model-generator/CaptureNeutralModels.ql
rename to csharp/ql/src/utils/modelgenerator/CaptureNeutralModels.ql
diff --git a/csharp/ql/src/utils/model-generator/CaptureSinkModels.ql b/csharp/ql/src/utils/modelgenerator/CaptureSinkModels.ql
similarity index 100%
rename from csharp/ql/src/utils/model-generator/CaptureSinkModels.ql
rename to csharp/ql/src/utils/modelgenerator/CaptureSinkModels.ql
diff --git a/csharp/ql/src/utils/model-generator/CaptureSourceModels.ql b/csharp/ql/src/utils/modelgenerator/CaptureSourceModels.ql
similarity index 100%
rename from csharp/ql/src/utils/model-generator/CaptureSourceModels.ql
rename to csharp/ql/src/utils/modelgenerator/CaptureSourceModels.ql
diff --git a/csharp/ql/src/utils/model-generator/CaptureSummaryModels.ql b/csharp/ql/src/utils/modelgenerator/CaptureSummaryModels.ql
similarity index 100%
rename from csharp/ql/src/utils/model-generator/CaptureSummaryModels.ql
rename to csharp/ql/src/utils/modelgenerator/CaptureSummaryModels.ql
diff --git a/csharp/ql/src/utils/model-generator/CaptureTypeBasedSummaryModels.ql b/csharp/ql/src/utils/modelgenerator/CaptureTypeBasedSummaryModels.ql
similarity index 100%
rename from csharp/ql/src/utils/model-generator/CaptureTypeBasedSummaryModels.ql
rename to csharp/ql/src/utils/modelgenerator/CaptureTypeBasedSummaryModels.ql
diff --git a/csharp/ql/src/utils/model-generator/GenerateFlowModel.py b/csharp/ql/src/utils/modelgenerator/GenerateFlowModel.py
similarity index 100%
rename from csharp/ql/src/utils/model-generator/GenerateFlowModel.py
rename to csharp/ql/src/utils/modelgenerator/GenerateFlowModel.py
diff --git a/csharp/ql/test/utils/model-generator/dataflow/CaptureNeutralModels.expected b/csharp/ql/test/utils/modelgenerator/dataflow/CaptureNeutralModels.expected
similarity index 100%
rename from csharp/ql/test/utils/model-generator/dataflow/CaptureNeutralModels.expected
rename to csharp/ql/test/utils/modelgenerator/dataflow/CaptureNeutralModels.expected
diff --git a/csharp/ql/test/utils/model-generator/dataflow/CaptureNeutralModels.qlref b/csharp/ql/test/utils/modelgenerator/dataflow/CaptureNeutralModels.qlref
similarity index 100%
rename from csharp/ql/test/utils/model-generator/dataflow/CaptureNeutralModels.qlref
rename to csharp/ql/test/utils/modelgenerator/dataflow/CaptureNeutralModels.qlref
diff --git a/csharp/ql/test/utils/model-generator/dataflow/CaptureSinkModels.expected b/csharp/ql/test/utils/modelgenerator/dataflow/CaptureSinkModels.expected
similarity index 100%
rename from csharp/ql/test/utils/model-generator/dataflow/CaptureSinkModels.expected
rename to csharp/ql/test/utils/modelgenerator/dataflow/CaptureSinkModels.expected
diff --git a/csharp/ql/test/utils/model-generator/dataflow/CaptureSinkModels.qlref b/csharp/ql/test/utils/modelgenerator/dataflow/CaptureSinkModels.qlref
similarity index 100%
rename from csharp/ql/test/utils/model-generator/dataflow/CaptureSinkModels.qlref
rename to csharp/ql/test/utils/modelgenerator/dataflow/CaptureSinkModels.qlref
diff --git a/csharp/ql/test/utils/model-generator/dataflow/CaptureSourceModels.expected b/csharp/ql/test/utils/modelgenerator/dataflow/CaptureSourceModels.expected
similarity index 100%
rename from csharp/ql/test/utils/model-generator/dataflow/CaptureSourceModels.expected
rename to csharp/ql/test/utils/modelgenerator/dataflow/CaptureSourceModels.expected
diff --git a/csharp/ql/test/utils/model-generator/dataflow/CaptureSourceModels.qlref b/csharp/ql/test/utils/modelgenerator/dataflow/CaptureSourceModels.qlref
similarity index 100%
rename from csharp/ql/test/utils/model-generator/dataflow/CaptureSourceModels.qlref
rename to csharp/ql/test/utils/modelgenerator/dataflow/CaptureSourceModels.qlref
diff --git a/csharp/ql/test/utils/model-generator/dataflow/CaptureSummaryModels.expected b/csharp/ql/test/utils/modelgenerator/dataflow/CaptureSummaryModels.expected
similarity index 100%
rename from csharp/ql/test/utils/model-generator/dataflow/CaptureSummaryModels.expected
rename to csharp/ql/test/utils/modelgenerator/dataflow/CaptureSummaryModels.expected
diff --git a/csharp/ql/test/utils/model-generator/dataflow/CaptureSummaryModels.qlref b/csharp/ql/test/utils/modelgenerator/dataflow/CaptureSummaryModels.qlref
similarity index 100%
rename from csharp/ql/test/utils/model-generator/dataflow/CaptureSummaryModels.qlref
rename to csharp/ql/test/utils/modelgenerator/dataflow/CaptureSummaryModels.qlref
diff --git a/csharp/ql/test/utils/model-generator/dataflow/NoSummaries.cs b/csharp/ql/test/utils/modelgenerator/dataflow/NoSummaries.cs
similarity index 100%
rename from csharp/ql/test/utils/model-generator/dataflow/NoSummaries.cs
rename to csharp/ql/test/utils/modelgenerator/dataflow/NoSummaries.cs
diff --git a/csharp/ql/test/utils/model-generator/dataflow/Sinks.cs b/csharp/ql/test/utils/modelgenerator/dataflow/Sinks.cs
similarity index 100%
rename from csharp/ql/test/utils/model-generator/dataflow/Sinks.cs
rename to csharp/ql/test/utils/modelgenerator/dataflow/Sinks.cs
diff --git a/csharp/ql/test/utils/model-generator/dataflow/Sources.cs b/csharp/ql/test/utils/modelgenerator/dataflow/Sources.cs
similarity index 100%
rename from csharp/ql/test/utils/model-generator/dataflow/Sources.cs
rename to csharp/ql/test/utils/modelgenerator/dataflow/Sources.cs
diff --git a/csharp/ql/test/utils/model-generator/dataflow/Summaries.cs b/csharp/ql/test/utils/modelgenerator/dataflow/Summaries.cs
similarity index 100%
rename from csharp/ql/test/utils/model-generator/dataflow/Summaries.cs
rename to csharp/ql/test/utils/modelgenerator/dataflow/Summaries.cs
diff --git a/csharp/ql/test/utils/model-generator/dataflow/options b/csharp/ql/test/utils/modelgenerator/dataflow/options
similarity index 100%
rename from csharp/ql/test/utils/model-generator/dataflow/options
rename to csharp/ql/test/utils/modelgenerator/dataflow/options
diff --git a/csharp/ql/test/utils/model-generator/typebasedflow/CaptureTypeBasedSummaryModels.expected b/csharp/ql/test/utils/modelgenerator/typebasedflow/CaptureTypeBasedSummaryModels.expected
similarity index 100%
rename from csharp/ql/test/utils/model-generator/typebasedflow/CaptureTypeBasedSummaryModels.expected
rename to csharp/ql/test/utils/modelgenerator/typebasedflow/CaptureTypeBasedSummaryModels.expected
diff --git a/csharp/ql/test/utils/model-generator/typebasedflow/CaptureTypeBasedSummaryModels.qlref b/csharp/ql/test/utils/modelgenerator/typebasedflow/CaptureTypeBasedSummaryModels.qlref
similarity index 100%
rename from csharp/ql/test/utils/model-generator/typebasedflow/CaptureTypeBasedSummaryModels.qlref
rename to csharp/ql/test/utils/modelgenerator/typebasedflow/CaptureTypeBasedSummaryModels.qlref
diff --git a/csharp/ql/test/utils/model-generator/typebasedflow/TypeBasedSummaries.cs b/csharp/ql/test/utils/modelgenerator/typebasedflow/TypeBasedSummaries.cs
similarity index 100%
rename from csharp/ql/test/utils/model-generator/typebasedflow/TypeBasedSummaries.cs
rename to csharp/ql/test/utils/modelgenerator/typebasedflow/TypeBasedSummaries.cs
diff --git a/java/ql/src/utils/model-generator/CaptureNeutralModels.ql b/java/ql/src/utils/modelgenerator/CaptureNeutralModels.ql
similarity index 100%
rename from java/ql/src/utils/model-generator/CaptureNeutralModels.ql
rename to java/ql/src/utils/modelgenerator/CaptureNeutralModels.ql
diff --git a/java/ql/src/utils/model-generator/CaptureSinkModels.ql b/java/ql/src/utils/modelgenerator/CaptureSinkModels.ql
similarity index 100%
rename from java/ql/src/utils/model-generator/CaptureSinkModels.ql
rename to java/ql/src/utils/modelgenerator/CaptureSinkModels.ql
diff --git a/java/ql/src/utils/model-generator/CaptureSourceModels.ql b/java/ql/src/utils/modelgenerator/CaptureSourceModels.ql
similarity index 100%
rename from java/ql/src/utils/model-generator/CaptureSourceModels.ql
rename to java/ql/src/utils/modelgenerator/CaptureSourceModels.ql
diff --git a/java/ql/src/utils/model-generator/CaptureSummaryModels.ql b/java/ql/src/utils/modelgenerator/CaptureSummaryModels.ql
similarity index 100%
rename from java/ql/src/utils/model-generator/CaptureSummaryModels.ql
rename to java/ql/src/utils/modelgenerator/CaptureSummaryModels.ql
diff --git a/java/ql/src/utils/model-generator/CaptureTypeBasedSummaryModels.ql b/java/ql/src/utils/modelgenerator/CaptureTypeBasedSummaryModels.ql
similarity index 100%
rename from java/ql/src/utils/model-generator/CaptureTypeBasedSummaryModels.ql
rename to java/ql/src/utils/modelgenerator/CaptureTypeBasedSummaryModels.ql
diff --git a/java/ql/src/utils/model-generator/GenerateFlowModel.py b/java/ql/src/utils/modelgenerator/GenerateFlowModel.py
similarity index 100%
rename from java/ql/src/utils/model-generator/GenerateFlowModel.py
rename to java/ql/src/utils/modelgenerator/GenerateFlowModel.py
diff --git a/java/ql/src/utils/model-generator/RegenerateModels.py b/java/ql/src/utils/modelgenerator/RegenerateModels.py
similarity index 100%
rename from java/ql/src/utils/model-generator/RegenerateModels.py
rename to java/ql/src/utils/modelgenerator/RegenerateModels.py
diff --git a/java/ql/test/utils/model-generator/dataflow/CaptureNeutralModels.expected b/java/ql/test/utils/modelgenerator/dataflow/CaptureNeutralModels.expected
similarity index 100%
rename from java/ql/test/utils/model-generator/dataflow/CaptureNeutralModels.expected
rename to java/ql/test/utils/modelgenerator/dataflow/CaptureNeutralModels.expected
diff --git a/java/ql/test/utils/model-generator/dataflow/CaptureNeutralModels.qlref b/java/ql/test/utils/modelgenerator/dataflow/CaptureNeutralModels.qlref
similarity index 100%
rename from java/ql/test/utils/model-generator/dataflow/CaptureNeutralModels.qlref
rename to java/ql/test/utils/modelgenerator/dataflow/CaptureNeutralModels.qlref
diff --git a/java/ql/test/utils/model-generator/dataflow/CaptureSinkModels.expected b/java/ql/test/utils/modelgenerator/dataflow/CaptureSinkModels.expected
similarity index 100%
rename from java/ql/test/utils/model-generator/dataflow/CaptureSinkModels.expected
rename to java/ql/test/utils/modelgenerator/dataflow/CaptureSinkModels.expected
diff --git a/java/ql/test/utils/model-generator/dataflow/CaptureSinkModels.qlref b/java/ql/test/utils/modelgenerator/dataflow/CaptureSinkModels.qlref
similarity index 100%
rename from java/ql/test/utils/model-generator/dataflow/CaptureSinkModels.qlref
rename to java/ql/test/utils/modelgenerator/dataflow/CaptureSinkModels.qlref
diff --git a/java/ql/test/utils/model-generator/dataflow/CaptureSourceModels.expected b/java/ql/test/utils/modelgenerator/dataflow/CaptureSourceModels.expected
similarity index 100%
rename from java/ql/test/utils/model-generator/dataflow/CaptureSourceModels.expected
rename to java/ql/test/utils/modelgenerator/dataflow/CaptureSourceModels.expected
diff --git a/java/ql/test/utils/model-generator/dataflow/CaptureSourceModels.qlref b/java/ql/test/utils/modelgenerator/dataflow/CaptureSourceModels.qlref
similarity index 100%
rename from java/ql/test/utils/model-generator/dataflow/CaptureSourceModels.qlref
rename to java/ql/test/utils/modelgenerator/dataflow/CaptureSourceModels.qlref
diff --git a/java/ql/test/utils/model-generator/dataflow/CaptureSummaryModels.expected b/java/ql/test/utils/modelgenerator/dataflow/CaptureSummaryModels.expected
similarity index 100%
rename from java/ql/test/utils/model-generator/dataflow/CaptureSummaryModels.expected
rename to java/ql/test/utils/modelgenerator/dataflow/CaptureSummaryModels.expected
diff --git a/java/ql/test/utils/model-generator/dataflow/CaptureSummaryModels.qlref b/java/ql/test/utils/modelgenerator/dataflow/CaptureSummaryModels.qlref
similarity index 100%
rename from java/ql/test/utils/model-generator/dataflow/CaptureSummaryModels.qlref
rename to java/ql/test/utils/modelgenerator/dataflow/CaptureSummaryModels.qlref
diff --git a/java/ql/test/utils/model-generator/dataflow/p/AbstractImplOfExternalSPI.java b/java/ql/test/utils/modelgenerator/dataflow/p/AbstractImplOfExternalSPI.java
similarity index 100%
rename from java/ql/test/utils/model-generator/dataflow/p/AbstractImplOfExternalSPI.java
rename to java/ql/test/utils/modelgenerator/dataflow/p/AbstractImplOfExternalSPI.java
diff --git a/java/ql/test/utils/model-generator/dataflow/p/Factory.java b/java/ql/test/utils/modelgenerator/dataflow/p/Factory.java
similarity index 100%
rename from java/ql/test/utils/model-generator/dataflow/p/Factory.java
rename to java/ql/test/utils/modelgenerator/dataflow/p/Factory.java
diff --git a/java/ql/test/utils/model-generator/dataflow/p/FinalClass.java b/java/ql/test/utils/modelgenerator/dataflow/p/FinalClass.java
similarity index 100%
rename from java/ql/test/utils/model-generator/dataflow/p/FinalClass.java
rename to java/ql/test/utils/modelgenerator/dataflow/p/FinalClass.java
diff --git a/java/ql/test/utils/model-generator/dataflow/p/FluentAPI.java b/java/ql/test/utils/modelgenerator/dataflow/p/FluentAPI.java
similarity index 100%
rename from java/ql/test/utils/model-generator/dataflow/p/FluentAPI.java
rename to java/ql/test/utils/modelgenerator/dataflow/p/FluentAPI.java
diff --git a/java/ql/test/utils/model-generator/dataflow/p/ImmutablePojo.java b/java/ql/test/utils/modelgenerator/dataflow/p/ImmutablePojo.java
similarity index 100%
rename from java/ql/test/utils/model-generator/dataflow/p/ImmutablePojo.java
rename to java/ql/test/utils/modelgenerator/dataflow/p/ImmutablePojo.java
diff --git a/java/ql/test/utils/model-generator/dataflow/p/ImplOfExternalSPI.java b/java/ql/test/utils/modelgenerator/dataflow/p/ImplOfExternalSPI.java
similarity index 100%
rename from java/ql/test/utils/model-generator/dataflow/p/ImplOfExternalSPI.java
rename to java/ql/test/utils/modelgenerator/dataflow/p/ImplOfExternalSPI.java
diff --git a/java/ql/test/utils/model-generator/dataflow/p/InnerClasses.java b/java/ql/test/utils/modelgenerator/dataflow/p/InnerClasses.java
similarity index 100%
rename from java/ql/test/utils/model-generator/dataflow/p/InnerClasses.java
rename to java/ql/test/utils/modelgenerator/dataflow/p/InnerClasses.java
diff --git a/java/ql/test/utils/model-generator/dataflow/p/InnerHolder.java b/java/ql/test/utils/modelgenerator/dataflow/p/InnerHolder.java
similarity index 100%
rename from java/ql/test/utils/model-generator/dataflow/p/InnerHolder.java
rename to java/ql/test/utils/modelgenerator/dataflow/p/InnerHolder.java
diff --git a/java/ql/test/utils/model-generator/dataflow/p/Joiner.java b/java/ql/test/utils/modelgenerator/dataflow/p/Joiner.java
similarity index 100%
rename from java/ql/test/utils/model-generator/dataflow/p/Joiner.java
rename to java/ql/test/utils/modelgenerator/dataflow/p/Joiner.java
diff --git a/java/ql/test/utils/model-generator/dataflow/p/MultipleImpls.java b/java/ql/test/utils/modelgenerator/dataflow/p/MultipleImpls.java
similarity index 100%
rename from java/ql/test/utils/model-generator/dataflow/p/MultipleImpls.java
rename to java/ql/test/utils/modelgenerator/dataflow/p/MultipleImpls.java
diff --git a/java/ql/test/utils/model-generator/dataflow/p/ParamFlow.java b/java/ql/test/utils/modelgenerator/dataflow/p/ParamFlow.java
similarity index 100%
rename from java/ql/test/utils/model-generator/dataflow/p/ParamFlow.java
rename to java/ql/test/utils/modelgenerator/dataflow/p/ParamFlow.java
diff --git a/java/ql/test/utils/model-generator/dataflow/p/Pojo.java b/java/ql/test/utils/modelgenerator/dataflow/p/Pojo.java
similarity index 100%
rename from java/ql/test/utils/model-generator/dataflow/p/Pojo.java
rename to java/ql/test/utils/modelgenerator/dataflow/p/Pojo.java
diff --git a/java/ql/test/utils/model-generator/dataflow/p/PrivateFlowViaPublicInterface.java b/java/ql/test/utils/modelgenerator/dataflow/p/PrivateFlowViaPublicInterface.java
similarity index 100%
rename from java/ql/test/utils/model-generator/dataflow/p/PrivateFlowViaPublicInterface.java
rename to java/ql/test/utils/modelgenerator/dataflow/p/PrivateFlowViaPublicInterface.java
diff --git a/java/ql/test/utils/model-generator/dataflow/p/Sinks.java b/java/ql/test/utils/modelgenerator/dataflow/p/Sinks.java
similarity index 100%
rename from java/ql/test/utils/model-generator/dataflow/p/Sinks.java
rename to java/ql/test/utils/modelgenerator/dataflow/p/Sinks.java
diff --git a/java/ql/test/utils/model-generator/dataflow/p/SomeEnum.java b/java/ql/test/utils/modelgenerator/dataflow/p/SomeEnum.java
similarity index 100%
rename from java/ql/test/utils/model-generator/dataflow/p/SomeEnum.java
rename to java/ql/test/utils/modelgenerator/dataflow/p/SomeEnum.java
diff --git a/java/ql/test/utils/model-generator/dataflow/p/Sources.java b/java/ql/test/utils/modelgenerator/dataflow/p/Sources.java
similarity index 100%
rename from java/ql/test/utils/model-generator/dataflow/p/Sources.java
rename to java/ql/test/utils/modelgenerator/dataflow/p/Sources.java
diff --git a/java/ql/test/utils/model-generator/typebasedflow/CaptureTypeBasedSummaryModels.expected b/java/ql/test/utils/modelgenerator/typebasedflow/CaptureTypeBasedSummaryModels.expected
similarity index 100%
rename from java/ql/test/utils/model-generator/typebasedflow/CaptureTypeBasedSummaryModels.expected
rename to java/ql/test/utils/modelgenerator/typebasedflow/CaptureTypeBasedSummaryModels.expected
diff --git a/java/ql/test/utils/model-generator/typebasedflow/CaptureTypeBasedSummaryModels.ql b/java/ql/test/utils/modelgenerator/typebasedflow/CaptureTypeBasedSummaryModels.ql
similarity index 100%
rename from java/ql/test/utils/model-generator/typebasedflow/CaptureTypeBasedSummaryModels.ql
rename to java/ql/test/utils/modelgenerator/typebasedflow/CaptureTypeBasedSummaryModels.ql
diff --git a/java/ql/test/utils/model-generator/typebasedflow/p/MyFunction.java b/java/ql/test/utils/modelgenerator/typebasedflow/p/MyFunction.java
similarity index 100%
rename from java/ql/test/utils/model-generator/typebasedflow/p/MyFunction.java
rename to java/ql/test/utils/modelgenerator/typebasedflow/p/MyFunction.java
diff --git a/java/ql/test/utils/model-generator/typebasedflow/p/Stream.java b/java/ql/test/utils/modelgenerator/typebasedflow/p/Stream.java
similarity index 100%
rename from java/ql/test/utils/model-generator/typebasedflow/p/Stream.java
rename to java/ql/test/utils/modelgenerator/typebasedflow/p/Stream.java
diff --git a/java/ql/test/utils/model-generator/typebasedflow/p/TypeBasedCollection.java b/java/ql/test/utils/modelgenerator/typebasedflow/p/TypeBasedCollection.java
similarity index 100%
rename from java/ql/test/utils/model-generator/typebasedflow/p/TypeBasedCollection.java
rename to java/ql/test/utils/modelgenerator/typebasedflow/p/TypeBasedCollection.java
diff --git a/java/ql/test/utils/model-generator/typebasedflow/p/TypeBasedComplex.java b/java/ql/test/utils/modelgenerator/typebasedflow/p/TypeBasedComplex.java
similarity index 100%
rename from java/ql/test/utils/model-generator/typebasedflow/p/TypeBasedComplex.java
rename to java/ql/test/utils/modelgenerator/typebasedflow/p/TypeBasedComplex.java
diff --git a/java/ql/test/utils/model-generator/typebasedflow/p/TypeBasedSimple.java b/java/ql/test/utils/modelgenerator/typebasedflow/p/TypeBasedSimple.java
similarity index 100%
rename from java/ql/test/utils/model-generator/typebasedflow/p/TypeBasedSimple.java
rename to java/ql/test/utils/modelgenerator/typebasedflow/p/TypeBasedSimple.java
From 11ca3f49f6058dbe98e878b6410bf27681f7c718 Mon Sep 17 00:00:00 2001
From: Michael Nebel
Date: Tue, 20 Dec 2022 14:27:09 +0100
Subject: [PATCH 178/381] C#/Java: Adjust imports after moving files.
---
.../src/utils/modelgenerator/CaptureDiscardedSummaryModels.ql | 4 ++--
csharp/ql/src/utils/modelgenerator/CaptureNeutralModels.ql | 4 ++--
csharp/ql/src/utils/modelgenerator/CaptureSinkModels.ql | 2 +-
csharp/ql/src/utils/modelgenerator/CaptureSourceModels.ql | 2 +-
csharp/ql/src/utils/modelgenerator/CaptureSummaryModels.ql | 4 ++--
.../src/utils/modelgenerator/CaptureTypeBasedSummaryModels.ql | 2 +-
java/ql/src/utils/modelgenerator/CaptureNeutralModels.ql | 4 ++--
java/ql/src/utils/modelgenerator/CaptureSinkModels.ql | 2 +-
java/ql/src/utils/modelgenerator/CaptureSourceModels.ql | 2 +-
java/ql/src/utils/modelgenerator/CaptureSummaryModels.ql | 4 ++--
.../src/utils/modelgenerator/CaptureTypeBasedSummaryModels.ql | 2 +-
11 files changed, 16 insertions(+), 16 deletions(-)
diff --git a/csharp/ql/src/utils/modelgenerator/CaptureDiscardedSummaryModels.ql b/csharp/ql/src/utils/modelgenerator/CaptureDiscardedSummaryModels.ql
index 9e71580b552..f16e75b588e 100644
--- a/csharp/ql/src/utils/modelgenerator/CaptureDiscardedSummaryModels.ql
+++ b/csharp/ql/src/utils/modelgenerator/CaptureDiscardedSummaryModels.ql
@@ -5,8 +5,8 @@
*/
import semmle.code.csharp.dataflow.ExternalFlow
-import utils.modelgenerator.internal.CaptureModels
-import utils.modelgenerator.internal.CaptureSummaryFlow
+import internal.CaptureModels
+import internal.CaptureSummaryFlow
from DataFlowTargetApi api, string flow
where flow = captureFlow(api) and hasSummary(api, false)
diff --git a/csharp/ql/src/utils/modelgenerator/CaptureNeutralModels.ql b/csharp/ql/src/utils/modelgenerator/CaptureNeutralModels.ql
index a7e4be6ff2e..9149a53116c 100644
--- a/csharp/ql/src/utils/modelgenerator/CaptureNeutralModels.ql
+++ b/csharp/ql/src/utils/modelgenerator/CaptureNeutralModels.ql
@@ -7,8 +7,8 @@
*/
import semmle.code.csharp.dataflow.ExternalFlow
-import utils.modelgenerator.internal.CaptureModels
-import utils.modelgenerator.internal.CaptureSummaryFlow
+import internal.CaptureModels
+import internal.CaptureSummaryFlow
from DataFlowTargetApi api, string noflow
where
diff --git a/csharp/ql/src/utils/modelgenerator/CaptureSinkModels.ql b/csharp/ql/src/utils/modelgenerator/CaptureSinkModels.ql
index c19971b098a..bba5081c223 100644
--- a/csharp/ql/src/utils/modelgenerator/CaptureSinkModels.ql
+++ b/csharp/ql/src/utils/modelgenerator/CaptureSinkModels.ql
@@ -6,7 +6,7 @@
* @tags modelgenerator
*/
-import utils.modelgenerator.internal.CaptureModels
+import internal.CaptureModels
class Activate extends ActiveConfiguration {
override predicate activateToSinkConfig() { any() }
diff --git a/csharp/ql/src/utils/modelgenerator/CaptureSourceModels.ql b/csharp/ql/src/utils/modelgenerator/CaptureSourceModels.ql
index 913624e315a..f504a291d7e 100644
--- a/csharp/ql/src/utils/modelgenerator/CaptureSourceModels.ql
+++ b/csharp/ql/src/utils/modelgenerator/CaptureSourceModels.ql
@@ -6,7 +6,7 @@
* @tags modelgenerator
*/
-import utils.modelgenerator.internal.CaptureModels
+import internal.CaptureModels
class Activate extends ActiveConfiguration {
override predicate activateFromSourceConfig() { any() }
diff --git a/csharp/ql/src/utils/modelgenerator/CaptureSummaryModels.ql b/csharp/ql/src/utils/modelgenerator/CaptureSummaryModels.ql
index eadb7e005f3..7002ead8fb4 100644
--- a/csharp/ql/src/utils/modelgenerator/CaptureSummaryModels.ql
+++ b/csharp/ql/src/utils/modelgenerator/CaptureSummaryModels.ql
@@ -7,8 +7,8 @@
*/
import semmle.code.csharp.dataflow.ExternalFlow
-import utils.modelgenerator.internal.CaptureModels
-import utils.modelgenerator.internal.CaptureSummaryFlow
+import internal.CaptureModels
+import internal.CaptureSummaryFlow
from DataFlowTargetApi api, string flow
where flow = captureFlow(api) and not hasSummary(api, false)
diff --git a/csharp/ql/src/utils/modelgenerator/CaptureTypeBasedSummaryModels.ql b/csharp/ql/src/utils/modelgenerator/CaptureTypeBasedSummaryModels.ql
index d2bb7c39826..19bec058d40 100644
--- a/csharp/ql/src/utils/modelgenerator/CaptureTypeBasedSummaryModels.ql
+++ b/csharp/ql/src/utils/modelgenerator/CaptureTypeBasedSummaryModels.ql
@@ -6,7 +6,7 @@
* @tags modelgenerator
*/
-import utils.modelgenerator.internal.CaptureTypeBasedSummaryModels
+import internal.CaptureTypeBasedSummaryModels
from TypeBasedFlowTargetApi api, string flow
where flow = captureFlow(api)
diff --git a/java/ql/src/utils/modelgenerator/CaptureNeutralModels.ql b/java/ql/src/utils/modelgenerator/CaptureNeutralModels.ql
index 32d4ceb3aa9..1f0c9fa5427 100644
--- a/java/ql/src/utils/modelgenerator/CaptureNeutralModels.ql
+++ b/java/ql/src/utils/modelgenerator/CaptureNeutralModels.ql
@@ -6,8 +6,8 @@
* @tags modelgenerator
*/
-import utils.modelgenerator.internal.CaptureModels
-import utils.modelgenerator.internal.CaptureSummaryFlow
+import internal.CaptureModels
+import internal.CaptureSummaryFlow
from DataFlowTargetApi api, string noflow
where noflow = captureNoFlow(api)
diff --git a/java/ql/src/utils/modelgenerator/CaptureSinkModels.ql b/java/ql/src/utils/modelgenerator/CaptureSinkModels.ql
index 3d2cd5933ff..8d273ba77f8 100644
--- a/java/ql/src/utils/modelgenerator/CaptureSinkModels.ql
+++ b/java/ql/src/utils/modelgenerator/CaptureSinkModels.ql
@@ -6,7 +6,7 @@
* @tags modelgenerator
*/
-import utils.modelgenerator.internal.CaptureModels
+import internal.CaptureModels
class Activate extends ActiveConfiguration {
override predicate activateToSinkConfig() { any() }
diff --git a/java/ql/src/utils/modelgenerator/CaptureSourceModels.ql b/java/ql/src/utils/modelgenerator/CaptureSourceModels.ql
index fffc43adc78..f4fc9982797 100644
--- a/java/ql/src/utils/modelgenerator/CaptureSourceModels.ql
+++ b/java/ql/src/utils/modelgenerator/CaptureSourceModels.ql
@@ -6,7 +6,7 @@
* @tags modelgenerator
*/
-import utils.modelgenerator.internal.CaptureModels
+import internal.CaptureModels
class Activate extends ActiveConfiguration {
override predicate activateFromSourceConfig() { any() }
diff --git a/java/ql/src/utils/modelgenerator/CaptureSummaryModels.ql b/java/ql/src/utils/modelgenerator/CaptureSummaryModels.ql
index 33a21940d39..33d07d5f2c1 100644
--- a/java/ql/src/utils/modelgenerator/CaptureSummaryModels.ql
+++ b/java/ql/src/utils/modelgenerator/CaptureSummaryModels.ql
@@ -6,8 +6,8 @@
* @tags modelgenerator
*/
-import utils.modelgenerator.internal.CaptureModels
-import utils.modelgenerator.internal.CaptureSummaryFlow
+import internal.CaptureModels
+import internal.CaptureSummaryFlow
from DataFlowTargetApi api, string flow
where flow = captureFlow(api)
diff --git a/java/ql/src/utils/modelgenerator/CaptureTypeBasedSummaryModels.ql b/java/ql/src/utils/modelgenerator/CaptureTypeBasedSummaryModels.ql
index 959b6dc7f78..f0a33731a87 100644
--- a/java/ql/src/utils/modelgenerator/CaptureTypeBasedSummaryModels.ql
+++ b/java/ql/src/utils/modelgenerator/CaptureTypeBasedSummaryModels.ql
@@ -6,7 +6,7 @@
* @tags modelgenerator
*/
-import utils.modelgenerator.internal.CaptureTypeBasedSummaryModels
+import internal.CaptureTypeBasedSummaryModels
from TypeBasedFlowTargetApi api, string flow
where flow = captureFlow(api)
From c115a9fee48f21ef877a5c8b1d2340900c5f79a5 Mon Sep 17 00:00:00 2001
From: Tony Torralba
Date: Mon, 19 Dec 2022 18:03:21 +0100
Subject: [PATCH 179/381] Add more path injection sinks
---
.../codeql/swift/security/PathInjection.qll | 9 +
.../Security/CWE-022/testPathInjection.swift | 186 +++++++++++-------
2 files changed, 128 insertions(+), 67 deletions(-)
diff --git a/swift/ql/lib/codeql/swift/security/PathInjection.qll b/swift/ql/lib/codeql/swift/security/PathInjection.qll
index 7b3554cf0ec..58eedc7c71e 100644
--- a/swift/ql/lib/codeql/swift/security/PathInjection.qll
+++ b/swift/ql/lib/codeql/swift/security/PathInjection.qll
@@ -105,6 +105,15 @@ private class PathInjectionSinks extends SinkModelCsv {
";NIOFileHandle;true;init(descriptor:);;;Argument[0];path-injection",
";NIOFileHandle;true;init(path:mode:flags:);;;Argument[0];path-injection",
";NIOFileHandle;true;init(path:);;;Argument[0];path-injection",
+ ";NSString;true;write(to:atomically:encoding:);;;Argument[0];path-injection",
+ ";NSString;true;write(toFile:atomically:encoding:);;;Argument[0];path-injection",
+ ";NSKeyedUnarchiver;true;unarchiveObject(withFile:);;;Argument[0];path-injection",
+ ";ArchiveByteStream;true;fileStream(fd:automaticClose:);;;Argument[0];path-injection",
+ ";ArchiveByteStream;true;withFileStream(fd:automaticClose:_:);;;Argument[0];path-injection",
+ ";ArchiveByteStream;true;fileStream(path:mode:options:permissions:);;;Argument[0];path-injection",
+ ";ArchiveByteStream;true;withFileStream(path:mode:options:permissions:_:);;;Argument[0];path-injection",
+ ";Bundle;true;init(url:);;;Argument[0];path-injection",
+ ";Bundle;true;init(path:);;;Argument[0];path-injection",
// GRDB
";Database;true;init(path:description:configuration:);;;Argument[0];path-injection",
";DatabasePool;true;init(path:configuration:);;;Argument[0];path-injection",
diff --git a/swift/ql/test/query-tests/Security/CWE-022/testPathInjection.swift b/swift/ql/test/query-tests/Security/CWE-022/testPathInjection.swift
index 1d9145a9e97..fbca64d0652 100644
--- a/swift/ql/test/query-tests/Security/CWE-022/testPathInjection.swift
+++ b/swift/ql/test/query-tests/Security/CWE-022/testPathInjection.swift
@@ -15,6 +15,11 @@ extension String {
}
}
+class NSString {
+ func write(toFile: String, atomically: Bool, encoding: UInt) {}
+ func write(to: URL, atomically: Bool, encoding: UInt) {}
+}
+
class Data {
struct WritingOptions : OptionSet { let rawValue: Int }
init(_ elements: S) {}
@@ -29,6 +34,10 @@ class NSData {
func write(toFile: String, options: NSData.WritingOptions) {}
}
+class NSKeyedUnarchiver {
+ func unarchiveObject(withFile: String) -> Any? { return nil }
+}
+
struct URLResourceKey {}
struct FileAttributeKey : Hashable {}
@@ -37,9 +46,10 @@ struct ObjCBool {}
struct AutoreleasingUnsafeMutablePointer {}
-struct FilePath {
+struct FilePath : ExpressibleByStringLiteral {
+ typealias StringLiteralType = String
init(stringLiteral: String) {}
- func lexicallyNormalized() -> FilePath { return FilePath(stringLiteral: "") }
+ func lexicallyNormalized() -> FilePath { return "" }
func starts(with: FilePath) -> Bool { return false }
}
@@ -91,6 +101,38 @@ class FileManager {
func replaceItemAtURL(originalItemURL: NSURL, withItemAtURL: NSURL, backupItemName: String?, options: FileManager.ItemReplacementOptions) -> NSURL? { return nil }
}
+struct FileDescriptor {
+ struct AccessMode : RawRepresentable {
+ static let readOnly = AccessMode(rawValue: 0)
+ let rawValue: UInt8
+ init(rawValue: UInt8) { self.rawValue = rawValue}
+ }
+
+ struct OpenOptions : RawRepresentable {
+ static let append = OpenOptions(rawValue: 0)
+ let rawValue: UInt8
+ init(rawValue: UInt8) { self.rawValue = rawValue}
+ }
+}
+
+struct FilePermissions : RawRepresentable {
+ static let ownerRead = FilePermissions(rawValue: 0)
+ let rawValue: UInt8
+ init(rawValue: UInt8) { self.rawValue = rawValue}
+}
+
+class ArchiveByteStream {
+ static func fileStream(fd: FileDescriptor, automaticClose: Bool = true) -> ArchiveByteStream? { return nil }
+ static func withFileStream(fd: FileDescriptor, automaticClose: Bool = true, _ body: (ArchiveByteStream) -> E) -> E { return body(ArchiveByteStream()) }
+ static func fileStream(path: FilePath, mode: FileDescriptor.AccessMode, options: FileDescriptor.OpenOptions, permissions: FilePermissions) -> ArchiveByteStream? { return nil }
+ static func withFileStream(path: FilePath, mode: FileDescriptor.AccessMode, options: FileDescriptor.OpenOptions, permissions: FilePermissions, _ body: (ArchiveByteStream) -> E) -> E { return body(ArchiveByteStream()) }
+}
+
+class Bundle {
+ init?(url: URL) {}
+ init?(path: String) {}
+}
+
// GRDB
struct Configuration {}
@@ -124,81 +166,91 @@ func test() {
let safeUrl = URL(string: "")!
let safeNsUrl = NSURL(string: "")!
- Data("").write(to: remoteUrl, options: []) // $ hasPathInjection=121
+ Data("").write(to: remoteUrl, options: []) // $ hasPathInjection=163
let nsData = NSData()
- let _ = nsData.write(to: remoteUrl, atomically: false) // $ hasPathInjection=121
- nsData.write(to: remoteUrl, options: []) // $ hasPathInjection=121
- let _ = nsData.write(toFile: remoteString, atomically: false) // $ hasPathInjection=121
- nsData.write(toFile: remoteString, options: []) // $ hasPathInjection=121
+ let _ = nsData.write(to: remoteUrl, atomically: false) // $ hasPathInjection=163
+ nsData.write(to: remoteUrl, options: []) // $ hasPathInjection=163
+ let _ = nsData.write(toFile: remoteString, atomically: false) // $ hasPathInjection=163
+ nsData.write(toFile: remoteString, options: []) // $ hasPathInjection=163
let fm = FileManager()
- let _ = fm.contentsOfDirectory(at: remoteUrl, includingPropertiesForKeys: [], options: []) // $ hasPathInjection=121
- let _ = fm.contentsOfDirectory(atPath: remoteString) // $ hasPathInjection=121
- let _ = fm.enumerator(at: remoteUrl, includingPropertiesForKeys: [], options: [], errorHandler: nil) // $ hasPathInjection=121
- let _ = fm.enumerator(atPath: remoteString) // $ hasPathInjection=121
- let _ = fm.subpathsOfDirectory(atPath: remoteString) // $ hasPathInjection=121
- let _ = fm.subpaths(atPath: remoteString) // $ hasPathInjection=121
- fm.createDirectory(at: remoteUrl, withIntermediateDirectories: false, attributes: [:]) // $ hasPathInjection=121
- let _ = fm.createDirectory(atPath: remoteString, attributes: [:]) // $ hasPathInjection=121
- let _ = fm.createFile(atPath: remoteString, contents: nil, attributes: [:]) // $ hasPathInjection=121
- fm.removeItem(at: remoteUrl) // $ hasPathInjection=121
- fm.removeItem(atPath: remoteString) // $ hasPathInjection=121
- fm.trashItem(at: remoteUrl, resultingItemURL: AutoreleasingUnsafeMutablePointer()) // $ hasPathInjection=121
- let _ = fm.replaceItemAt(remoteUrl, withItemAt: safeUrl, backupItemName: nil, options: []) // $ hasPathInjection=121
- let _ = fm.replaceItemAt(safeUrl, withItemAt: remoteUrl, backupItemName: nil, options: []) // $ hasPathInjection=121
- fm.replaceItem(at: remoteUrl, withItemAt: safeUrl, backupItemName: nil, options: [], resultingItemURL: AutoreleasingUnsafeMutablePointer()) // $ hasPathInjection=121
- fm.replaceItem(at: safeUrl, withItemAt: remoteUrl, backupItemName: nil, options: [], resultingItemURL: AutoreleasingUnsafeMutablePointer()) // $ hasPathInjection=121
- fm.copyItem(at: remoteUrl, to: safeUrl) // $ hasPathInjection=121
- fm.copyItem(at: safeUrl, to: remoteUrl) // $ hasPathInjection=121
- fm.copyItem(atPath: remoteString, toPath: "") // $ hasPathInjection=121
- fm.copyItem(atPath: "", toPath: remoteString) // $ hasPathInjection=121
- fm.moveItem(at: remoteUrl, to: safeUrl) // $ hasPathInjection=121
- fm.moveItem(at: safeUrl, to: remoteUrl) // $ hasPathInjection=121
- fm.moveItem(atPath: remoteString, toPath: "") // $ hasPathInjection=121
- fm.moveItem(atPath: "", toPath: remoteString) // $ hasPathInjection=121
- fm.createSymbolicLink(at: remoteUrl, withDestinationURL: safeUrl) // $ hasPathInjection=121
- fm.createSymbolicLink(at: safeUrl, withDestinationURL: remoteUrl) // $ hasPathInjection=121
- fm.createSymbolicLink(atPath: remoteString, withDestinationPath: "") // $ hasPathInjection=121
- fm.createSymbolicLink(atPath: "", withDestinationPath: remoteString) // $ hasPathInjection=121
- fm.linkItem(at: remoteUrl, to: safeUrl) // $ hasPathInjection=121
- fm.linkItem(at: safeUrl, to: remoteUrl) // $ hasPathInjection=121
- fm.linkItem(atPath: remoteString, toPath: "") // $ hasPathInjection=121
- fm.linkItem(atPath: "", toPath: remoteString) // $ hasPathInjection=121
- let _ = fm.destinationOfSymbolicLink(atPath: remoteString) // $ hasPathInjection=121
- let _ = fm.fileExists(atPath: remoteString) // $ hasPathInjection=121
- let _ = fm.fileExists(atPath: remoteString, isDirectory: UnsafeMutablePointer.init(bitPattern: 0)) // $ hasPathInjection=121
- fm.setAttributes([:], ofItemAtPath: remoteString) // $ hasPathInjection=121
- let _ = fm.contents(atPath: remoteString) // $ hasPathInjection=121
- let _ = fm.contentsEqual(atPath: remoteString, andPath: "") // $ hasPathInjection=121
- let _ = fm.contentsEqual(atPath: "", andPath: remoteString) // $ hasPathInjection=121
- let _ = fm.changeCurrentDirectoryPath(remoteString) // $ hasPathInjection=121
- let _ = fm.unmountVolume(at: remoteUrl, options: [], completionHandler: { _ in }) // $ hasPathInjection=121
+ let _ = fm.contentsOfDirectory(at: remoteUrl, includingPropertiesForKeys: [], options: []) // $ hasPathInjection=163
+ let _ = fm.contentsOfDirectory(atPath: remoteString) // $ hasPathInjection=163
+ let _ = fm.enumerator(at: remoteUrl, includingPropertiesForKeys: [], options: [], errorHandler: nil) // $ hasPathInjection=163
+ let _ = fm.enumerator(atPath: remoteString) // $ hasPathInjection=163
+ let _ = fm.subpathsOfDirectory(atPath: remoteString) // $ hasPathInjection=163
+ let _ = fm.subpaths(atPath: remoteString) // $ hasPathInjection=163
+ fm.createDirectory(at: remoteUrl, withIntermediateDirectories: false, attributes: [:]) // $ hasPathInjection=163
+ let _ = fm.createDirectory(atPath: remoteString, attributes: [:]) // $ hasPathInjection=163
+ let _ = fm.createFile(atPath: remoteString, contents: nil, attributes: [:]) // $ hasPathInjection=163
+ fm.removeItem(at: remoteUrl) // $ hasPathInjection=163
+ fm.removeItem(atPath: remoteString) // $ hasPathInjection=163
+ fm.trashItem(at: remoteUrl, resultingItemURL: AutoreleasingUnsafeMutablePointer()) // $ hasPathInjection=163
+ let _ = fm.replaceItemAt(remoteUrl, withItemAt: safeUrl, backupItemName: nil, options: []) // $ hasPathInjection=163
+ let _ = fm.replaceItemAt(safeUrl, withItemAt: remoteUrl, backupItemName: nil, options: []) // $ hasPathInjection=163
+ fm.replaceItem(at: remoteUrl, withItemAt: safeUrl, backupItemName: nil, options: [], resultingItemURL: AutoreleasingUnsafeMutablePointer()) // $ hasPathInjection=163
+ fm.replaceItem(at: safeUrl, withItemAt: remoteUrl, backupItemName: nil, options: [], resultingItemURL: AutoreleasingUnsafeMutablePointer()) // $ hasPathInjection=163
+ fm.copyItem(at: remoteUrl, to: safeUrl) // $ hasPathInjection=163
+ fm.copyItem(at: safeUrl, to: remoteUrl) // $ hasPathInjection=163
+ fm.copyItem(atPath: remoteString, toPath: "") // $ hasPathInjection=163
+ fm.copyItem(atPath: "", toPath: remoteString) // $ hasPathInjection=163
+ fm.moveItem(at: remoteUrl, to: safeUrl) // $ hasPathInjection=163
+ fm.moveItem(at: safeUrl, to: remoteUrl) // $ hasPathInjection=163
+ fm.moveItem(atPath: remoteString, toPath: "") // $ hasPathInjection=163
+ fm.moveItem(atPath: "", toPath: remoteString) // $ hasPathInjection=163
+ fm.createSymbolicLink(at: remoteUrl, withDestinationURL: safeUrl) // $ hasPathInjection=163
+ fm.createSymbolicLink(at: safeUrl, withDestinationURL: remoteUrl) // $ hasPathInjection=163
+ fm.createSymbolicLink(atPath: remoteString, withDestinationPath: "") // $ hasPathInjection=163
+ fm.createSymbolicLink(atPath: "", withDestinationPath: remoteString) // $ hasPathInjection=163
+ fm.linkItem(at: remoteUrl, to: safeUrl) // $ hasPathInjection=163
+ fm.linkItem(at: safeUrl, to: remoteUrl) // $ hasPathInjection=163
+ fm.linkItem(atPath: remoteString, toPath: "") // $ hasPathInjection=163
+ fm.linkItem(atPath: "", toPath: remoteString) // $ hasPathInjection=163
+ let _ = fm.destinationOfSymbolicLink(atPath: remoteString) // $ hasPathInjection=163
+ let _ = fm.fileExists(atPath: remoteString) // $ hasPathInjection=163
+ let _ = fm.fileExists(atPath: remoteString, isDirectory: UnsafeMutablePointer.init(bitPattern: 0)) // $ hasPathInjection=163
+ fm.setAttributes([:], ofItemAtPath: remoteString) // $ hasPathInjection=163
+ let _ = fm.contents(atPath: remoteString) // $ hasPathInjection=163
+ let _ = fm.contentsEqual(atPath: remoteString, andPath: "") // $ hasPathInjection=163
+ let _ = fm.contentsEqual(atPath: "", andPath: remoteString) // $ hasPathInjection=163
+ let _ = fm.changeCurrentDirectoryPath(remoteString) // $ hasPathInjection=163
+ let _ = fm.unmountVolume(at: remoteUrl, options: [], completionHandler: { _ in }) // $ hasPathInjection=163
// Deprecated methods
- let _ = fm.changeFileAttributes([:], atPath: remoteString) // $ hasPathInjection=121
- let _ = fm.directoryContents(atPath: remoteString) // $ hasPathInjection=121
- let _ = fm.createDirectory(atPath: remoteString, attributes: [:]) // $ hasPathInjection=121
- let _ = fm.createSymbolicLink(atPath: remoteString, pathContent: "") // $ hasPathInjection=121
- let _ = fm.createSymbolicLink(atPath: "", pathContent: remoteString) // $ hasPathInjection=121
- let _ = fm.pathContentOfSymbolicLink(atPath: remoteString) // $ hasPathInjection=121
- let _ = fm.replaceItemAtURL(originalItemURL: remoteNsUrl, withItemAtURL: safeNsUrl, backupItemName: nil, options: []) // $ hasPathInjection=121
- let _ = fm.replaceItemAtURL(originalItemURL: safeNsUrl, withItemAtURL: remoteNsUrl, backupItemName: nil, options: []) // $ hasPathInjection=121
+ let _ = fm.changeFileAttributes([:], atPath: remoteString) // $ hasPathInjection=163
+ let _ = fm.directoryContents(atPath: remoteString) // $ hasPathInjection=163
+ let _ = fm.createDirectory(atPath: remoteString, attributes: [:]) // $ hasPathInjection=163
+ let _ = fm.createSymbolicLink(atPath: remoteString, pathContent: "") // $ hasPathInjection=163
+ let _ = fm.createSymbolicLink(atPath: "", pathContent: remoteString) // $ hasPathInjection=163
+ let _ = fm.pathContentOfSymbolicLink(atPath: remoteString) // $ hasPathInjection=163
+ let _ = fm.replaceItemAtURL(originalItemURL: remoteNsUrl, withItemAtURL: safeNsUrl, backupItemName: nil, options: []) // $ hasPathInjection=163
+ let _ = fm.replaceItemAtURL(originalItemURL: safeNsUrl, withItemAtURL: remoteNsUrl, backupItemName: nil, options: []) // $ hasPathInjection=163
- let _ = Database(path: remoteString, description: "", configuration: Configuration()) // $ hasPathInjection=121
+ NSString().write(to: remoteUrl, atomically: true, encoding: 0) // $ hasPathInjection=163
+ NSString().write(toFile: remoteString, atomically: true, encoding: 0) // $ hasPathInjection=163
+ let _ = NSKeyedUnarchiver().unarchiveObject(withFile: remoteString) // $ hasPathInjection=163
+ let _ = ArchiveByteStream.fileStream(fd: remoteString as! FileDescriptor, automaticClose: true) // $ hasPathInjection=163
+ ArchiveByteStream.withFileStream(fd: remoteString as! FileDescriptor, automaticClose: true) { _ in } // $ hasPathInjection=163
+ let _ = ArchiveByteStream.fileStream(path: FilePath(stringLiteral: remoteString), mode: .readOnly, options: .append, permissions: .ownerRead) // $ hasPathInjection=163
+ ArchiveByteStream.withFileStream(path: FilePath(stringLiteral: remoteString), mode: .readOnly, options: .append, permissions: .ownerRead) { _ in } // $ hasPathInjection=163
+ let _ = Bundle(url: remoteUrl) // $ hasPathInjection=163
+ let _ = Bundle(path: remoteString) // $ hasPathInjection=163
+
+ let _ = Database(path: remoteString, description: "", configuration: Configuration()) // $ hasPathInjection=163
let _ = Database(path: "", description: "", configuration: Configuration()) // Safe
- let _ = DatabasePool(path: remoteString, configuration: Configuration()) // $ hasPathInjection=121
+ let _ = DatabasePool(path: remoteString, configuration: Configuration()) // $ hasPathInjection=163
let _ = DatabasePool(path: "", configuration: Configuration()) // Safe
- let _ = DatabaseQueue(path: remoteString, configuration: Configuration()) // $ hasPathInjection=121
+ let _ = DatabaseQueue(path: remoteString, configuration: Configuration()) // $ hasPathInjection=163
let _ = DatabaseQueue(path: "", configuration: Configuration()) // Safe
- let _ = DatabaseSnapshotPool(path: remoteString, configuration: Configuration()) // $ hasPathInjection=121
+ let _ = DatabaseSnapshotPool(path: remoteString, configuration: Configuration()) // $ hasPathInjection=163
let _ = DatabaseSnapshotPool(path: "", configuration: Configuration()) // Safe
- let _ = SerializedDatabase(path: remoteString, defaultLabel: "") // $ hasPathInjection=121
+ let _ = SerializedDatabase(path: remoteString, defaultLabel: "") // $ hasPathInjection=163
let _ = SerializedDatabase(path: "", defaultLabel: "") // Safe
- let _ = SerializedDatabase(path: remoteString, defaultLabel: "", purpose: nil) // $ hasPathInjection=121
+ let _ = SerializedDatabase(path: remoteString, defaultLabel: "", purpose: nil) // $ hasPathInjection=163
let _ = SerializedDatabase(path: "", defaultLabel: "", purpose: nil) // Safe
- let _ = SerializedDatabase(path: remoteString, configuration: Configuration(), defaultLabel: "") // $ hasPathInjection=121
+ let _ = SerializedDatabase(path: remoteString, configuration: Configuration(), defaultLabel: "") // $ hasPathInjection=163
let _ = SerializedDatabase(path: "", configuration: Configuration(), defaultLabel: "") // Safe
- let _ = SerializedDatabase(path: remoteString, configuration: Configuration(), defaultLabel: "", purpose: nil) // $ hasPathInjection=121
+ let _ = SerializedDatabase(path: remoteString, configuration: Configuration(), defaultLabel: "", purpose: nil) // $ hasPathInjection=163
let _ = SerializedDatabase(path: "", configuration: Configuration(), defaultLabel: "", purpose: nil) // Safe
}
@@ -208,8 +260,8 @@ func testSanitizers() {
let fm = FileManager()
let filePath = FilePath(stringLiteral: remoteString)
- if (filePath.lexicallyNormalized().starts(with: FilePath(stringLiteral: "/safe"))) {
- fm.contents(atPath: remoteString) // Safe
+ if (filePath.lexicallyNormalized().starts(with: "/safe")) {
+ let _ = fm.contents(atPath: remoteString) // Safe
}
- fm.contents(atPath: remoteString) // $ hasPathInjection=206
+ let _ = fm.contents(atPath: remoteString) // $ hasPathInjection=258
}
From 7422029e49d9e7302e0fa713406e8e426b10b303 Mon Sep 17 00:00:00 2001
From: Michael Nebel
Date: Fri, 16 Dec 2022 12:04:47 +0100
Subject: [PATCH 180/381] C#: Re-factor provenance related predicates for
summarized callable.
---
.../code/csharp/dataflow/ExternalFlow.qll | 5 ---
.../dataflow/internal/FlowSummaryImpl.qll | 33 +++++++-------
.../internal/FlowSummaryImplSpecific.qll | 43 ++++++-------------
.../CaptureDiscardedSummaryModels.ql | 6 ++-
.../modelgenerator/CaptureNeutralModels.ql | 4 +-
.../modelgenerator/CaptureSummaryModels.ql | 4 +-
6 files changed, 38 insertions(+), 57 deletions(-)
diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll
index 2db7eff0c75..196af2a449d 100644
--- a/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll
+++ b/csharp/ql/lib/semmle/code/csharp/dataflow/ExternalFlow.qll
@@ -410,11 +410,6 @@ Element interpretElement(
)
}
-/**
- * Holds if `c` has a `generated` summary.
- */
-predicate hasSummary(Callable c, boolean generated) { summaryElement(c, _, _, _, generated) }
-
cached
private module Cached {
/**
diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll
index d722aa68b70..b138fbf3417 100644
--- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll
+++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll
@@ -241,15 +241,19 @@ module Public {
}
/**
- * Holds if the summary is auto generated and not manually generated.
+ * Holds if the summaries that apply to `this` are auto generated and not manually generated.
*/
- predicate isAutoGenerated() { none() }
+ final predicate isAutoGenerated() { this.hasProvenance("generated") and not this.isManual() }
/**
- * Holds if the summary has the given provenance where `true` is
- * `generated` and `false` is `manual`.
+ * Holds if there exists a manual summary that applies to `this`.
*/
- predicate hasProvenance(boolean generated) { none() }
+ final predicate isManual() { this.hasProvenance("manual") }
+
+ /**
+ * Holds if there exists a summary that applies to `this` that has provenance `provenance`.
+ */
+ predicate hasProvenance(string provenance) { none() }
}
/** A callable where there is no flow via the callable. */
@@ -259,13 +263,12 @@ module Public {
/**
* Holds if the neutral is auto generated.
*/
- predicate isAutoGenerated() { neutralElement(this, true) }
+ predicate isAutoGenerated() { neutralElement(this, "generated") }
/**
- * Holds if the neutral has the given provenance where `true` is
- * `generated` and `false` is `manual`.
+ * Holds if the neutral has provenance `provenance`.
*/
- predicate hasProvenance(boolean generated) { neutralElement(this, generated) }
+ predicate hasProvenance(string provenance) { neutralElement(this, provenance) }
}
}
@@ -997,12 +1000,12 @@ module Private {
private predicate relevantSummaryElementGenerated(
AccessPath inSpec, AccessPath outSpec, string kind
) {
- summaryElement(this, inSpec, outSpec, kind, true) and
- not summaryElement(this, _, _, _, false)
+ summaryElement(this, inSpec, outSpec, kind, "generated") and
+ not summaryElement(this, _, _, _, "manual")
}
private predicate relevantSummaryElement(AccessPath inSpec, AccessPath outSpec, string kind) {
- summaryElement(this, inSpec, outSpec, kind, false)
+ summaryElement(this, inSpec, outSpec, kind, "manual")
or
this.relevantSummaryElementGenerated(inSpec, outSpec, kind)
}
@@ -1021,10 +1024,8 @@ module Private {
)
}
- override predicate isAutoGenerated() { this.relevantSummaryElementGenerated(_, _, _) }
-
- override predicate hasProvenance(boolean generated) {
- summaryElement(this, _, _, _, generated)
+ override predicate hasProvenance(string provenance) {
+ summaryElement(this, _, _, _, provenance)
}
}
diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/FlowSummaryImplSpecific.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/FlowSummaryImplSpecific.qll
index 251e9ebf5fe..a7511fdf0b0 100644
--- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/FlowSummaryImplSpecific.qll
+++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/FlowSummaryImplSpecific.qll
@@ -97,69 +97,52 @@ DataFlowType getSyntheticGlobalType(SummaryComponent::SyntheticGlobal sg) {
result = Gvn::getGlobalValueNumber(any(ObjectType t))
}
-bindingset[provenance]
-private boolean isGenerated(string provenance) {
- provenance = "generated" and result = true
- or
- provenance != "generated" and result = false
-}
-
/**
* Holds if an external flow summary exists for `c` with input specification
- * `input`, output specification `output`, kind `kind`, and a flag `generated`
- * stating whether the summary is autogenerated.
+ * `input`, output specification `output`, kind `kind`, and provenance `provenance`.
*/
-predicate summaryElement(Callable c, string input, string output, string kind, boolean generated) {
+predicate summaryElement(Callable c, string input, string output, string kind, string provenance) {
exists(
- string namespace, string type, boolean subtypes, string name, string signature, string ext,
- string provenance
+ string namespace, string type, boolean subtypes, string name, string signature, string ext
|
summaryModel(namespace, type, subtypes, name, signature, ext, input, output, kind, provenance) and
- generated = isGenerated(provenance) and
c = interpretElement(namespace, type, subtypes, name, signature, ext)
)
}
/**
- * Holds if a neutral model exists for `c`, which means that there is no
- * flow through `c`. The flag `generated` states whether the neutral model is autogenerated.
+ * Holds if a neutral model exists for `c` with provenance `provenace`,
+ * which means that there is no flow through `c`.
*/
-predicate neutralElement(Callable c, boolean generated) {
- exists(string namespace, string type, string name, string signature, string provenance |
+predicate neutralElement(Callable c, string provenance) {
+ exists(string namespace, string type, string name, string signature |
neutralModel(namespace, type, name, signature, provenance) and
- generated = isGenerated(provenance) and
c = interpretElement(namespace, type, false, name, signature, "")
)
}
/**
* Holds if an external source specification exists for `e` with output specification
- * `output`, kind `kind`, and a flag `generated` stating whether the source specification is
- * autogenerated.
+ * `output`, kind `kind`, and provenance `provenance`.
*/
-predicate sourceElement(Element e, string output, string kind, boolean generated) {
+predicate sourceElement(Element e, string output, string kind, string provenance) {
exists(
- string namespace, string type, boolean subtypes, string name, string signature, string ext,
- string provenance
+ string namespace, string type, boolean subtypes, string name, string signature, string ext
|
sourceModel(namespace, type, subtypes, name, signature, ext, output, kind, provenance) and
- generated = isGenerated(provenance) and
e = interpretElement(namespace, type, subtypes, name, signature, ext)
)
}
/**
* Holds if an external sink specification exists for `e` with input specification
- * `input`, kind `kind` and a flag `generated` stating whether the sink specification is
- * autogenerated.
+ * `input`, kind `kind` and provenance `provenance`.
*/
-predicate sinkElement(Element e, string input, string kind, boolean generated) {
+predicate sinkElement(Element e, string input, string kind, string provenance) {
exists(
- string namespace, string type, boolean subtypes, string name, string signature, string ext,
- string provenance
+ string namespace, string type, boolean subtypes, string name, string signature, string ext
|
sinkModel(namespace, type, subtypes, name, signature, ext, input, kind, provenance) and
- generated = isGenerated(provenance) and
e = interpretElement(namespace, type, subtypes, name, signature, ext)
)
}
diff --git a/csharp/ql/src/utils/modelgenerator/CaptureDiscardedSummaryModels.ql b/csharp/ql/src/utils/modelgenerator/CaptureDiscardedSummaryModels.ql
index f16e75b588e..3a2a3454900 100644
--- a/csharp/ql/src/utils/modelgenerator/CaptureDiscardedSummaryModels.ql
+++ b/csharp/ql/src/utils/modelgenerator/CaptureDiscardedSummaryModels.ql
@@ -4,10 +4,12 @@
* @id cs/utils/modelgenerator/discarded-summary-models
*/
-import semmle.code.csharp.dataflow.ExternalFlow
+import semmle.code.csharp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
import internal.CaptureModels
import internal.CaptureSummaryFlow
from DataFlowTargetApi api, string flow
-where flow = captureFlow(api) and hasSummary(api, false)
+where
+ flow = captureFlow(api) and
+ api.(FlowSummaryImpl::Public::SummarizedCallable).isManual()
select flow order by flow
diff --git a/csharp/ql/src/utils/modelgenerator/CaptureNeutralModels.ql b/csharp/ql/src/utils/modelgenerator/CaptureNeutralModels.ql
index 9149a53116c..933df8c765a 100644
--- a/csharp/ql/src/utils/modelgenerator/CaptureNeutralModels.ql
+++ b/csharp/ql/src/utils/modelgenerator/CaptureNeutralModels.ql
@@ -6,12 +6,12 @@
* @tags modelgenerator
*/
-import semmle.code.csharp.dataflow.ExternalFlow
+import semmle.code.csharp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
import internal.CaptureModels
import internal.CaptureSummaryFlow
from DataFlowTargetApi api, string noflow
where
noflow = captureNoFlow(api) and
- not hasSummary(api, false)
+ not api.(FlowSummaryImpl::Public::SummarizedCallable).isManual()
select noflow order by noflow
diff --git a/csharp/ql/src/utils/modelgenerator/CaptureSummaryModels.ql b/csharp/ql/src/utils/modelgenerator/CaptureSummaryModels.ql
index 7002ead8fb4..641c260adf8 100644
--- a/csharp/ql/src/utils/modelgenerator/CaptureSummaryModels.ql
+++ b/csharp/ql/src/utils/modelgenerator/CaptureSummaryModels.ql
@@ -6,10 +6,10 @@
* @tags modelgenerator
*/
-import semmle.code.csharp.dataflow.ExternalFlow
+import semmle.code.csharp.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
import internal.CaptureModels
import internal.CaptureSummaryFlow
from DataFlowTargetApi api, string flow
-where flow = captureFlow(api) and not hasSummary(api, false)
+where flow = captureFlow(api) and not api.(FlowSummaryImpl::Public::SummarizedCallable).isManual()
select flow order by flow
From ea173f951625da141ab141f67c75089f80b2c5c6 Mon Sep 17 00:00:00 2001
From: Michael Nebel
Date: Fri, 16 Dec 2022 13:12:11 +0100
Subject: [PATCH 181/381] Sync files.
---
.../go/dataflow/internal/FlowSummaryImpl.qll | 33 ++++++++++---------
.../dataflow/internal/FlowSummaryImpl.qll | 33 ++++++++++---------
.../dataflow/new/internal/FlowSummaryImpl.qll | 33 ++++++++++---------
.../dataflow/internal/FlowSummaryImpl.qll | 33 ++++++++++---------
.../dataflow/internal/FlowSummaryImpl.qll | 33 ++++++++++---------
5 files changed, 85 insertions(+), 80 deletions(-)
diff --git a/go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImpl.qll b/go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImpl.qll
index d722aa68b70..b138fbf3417 100644
--- a/go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImpl.qll
+++ b/go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImpl.qll
@@ -241,15 +241,19 @@ module Public {
}
/**
- * Holds if the summary is auto generated and not manually generated.
+ * Holds if the summaries that apply to `this` are auto generated and not manually generated.
*/
- predicate isAutoGenerated() { none() }
+ final predicate isAutoGenerated() { this.hasProvenance("generated") and not this.isManual() }
/**
- * Holds if the summary has the given provenance where `true` is
- * `generated` and `false` is `manual`.
+ * Holds if there exists a manual summary that applies to `this`.
*/
- predicate hasProvenance(boolean generated) { none() }
+ final predicate isManual() { this.hasProvenance("manual") }
+
+ /**
+ * Holds if there exists a summary that applies to `this` that has provenance `provenance`.
+ */
+ predicate hasProvenance(string provenance) { none() }
}
/** A callable where there is no flow via the callable. */
@@ -259,13 +263,12 @@ module Public {
/**
* Holds if the neutral is auto generated.
*/
- predicate isAutoGenerated() { neutralElement(this, true) }
+ predicate isAutoGenerated() { neutralElement(this, "generated") }
/**
- * Holds if the neutral has the given provenance where `true` is
- * `generated` and `false` is `manual`.
+ * Holds if the neutral has provenance `provenance`.
*/
- predicate hasProvenance(boolean generated) { neutralElement(this, generated) }
+ predicate hasProvenance(string provenance) { neutralElement(this, provenance) }
}
}
@@ -997,12 +1000,12 @@ module Private {
private predicate relevantSummaryElementGenerated(
AccessPath inSpec, AccessPath outSpec, string kind
) {
- summaryElement(this, inSpec, outSpec, kind, true) and
- not summaryElement(this, _, _, _, false)
+ summaryElement(this, inSpec, outSpec, kind, "generated") and
+ not summaryElement(this, _, _, _, "manual")
}
private predicate relevantSummaryElement(AccessPath inSpec, AccessPath outSpec, string kind) {
- summaryElement(this, inSpec, outSpec, kind, false)
+ summaryElement(this, inSpec, outSpec, kind, "manual")
or
this.relevantSummaryElementGenerated(inSpec, outSpec, kind)
}
@@ -1021,10 +1024,8 @@ module Private {
)
}
- override predicate isAutoGenerated() { this.relevantSummaryElementGenerated(_, _, _) }
-
- override predicate hasProvenance(boolean generated) {
- summaryElement(this, _, _, _, generated)
+ override predicate hasProvenance(string provenance) {
+ summaryElement(this, _, _, _, provenance)
}
}
diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImpl.qll b/java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImpl.qll
index d722aa68b70..b138fbf3417 100644
--- a/java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImpl.qll
+++ b/java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImpl.qll
@@ -241,15 +241,19 @@ module Public {
}
/**
- * Holds if the summary is auto generated and not manually generated.
+ * Holds if the summaries that apply to `this` are auto generated and not manually generated.
*/
- predicate isAutoGenerated() { none() }
+ final predicate isAutoGenerated() { this.hasProvenance("generated") and not this.isManual() }
/**
- * Holds if the summary has the given provenance where `true` is
- * `generated` and `false` is `manual`.
+ * Holds if there exists a manual summary that applies to `this`.
*/
- predicate hasProvenance(boolean generated) { none() }
+ final predicate isManual() { this.hasProvenance("manual") }
+
+ /**
+ * Holds if there exists a summary that applies to `this` that has provenance `provenance`.
+ */
+ predicate hasProvenance(string provenance) { none() }
}
/** A callable where there is no flow via the callable. */
@@ -259,13 +263,12 @@ module Public {
/**
* Holds if the neutral is auto generated.
*/
- predicate isAutoGenerated() { neutralElement(this, true) }
+ predicate isAutoGenerated() { neutralElement(this, "generated") }
/**
- * Holds if the neutral has the given provenance where `true` is
- * `generated` and `false` is `manual`.
+ * Holds if the neutral has provenance `provenance`.
*/
- predicate hasProvenance(boolean generated) { neutralElement(this, generated) }
+ predicate hasProvenance(string provenance) { neutralElement(this, provenance) }
}
}
@@ -997,12 +1000,12 @@ module Private {
private predicate relevantSummaryElementGenerated(
AccessPath inSpec, AccessPath outSpec, string kind
) {
- summaryElement(this, inSpec, outSpec, kind, true) and
- not summaryElement(this, _, _, _, false)
+ summaryElement(this, inSpec, outSpec, kind, "generated") and
+ not summaryElement(this, _, _, _, "manual")
}
private predicate relevantSummaryElement(AccessPath inSpec, AccessPath outSpec, string kind) {
- summaryElement(this, inSpec, outSpec, kind, false)
+ summaryElement(this, inSpec, outSpec, kind, "manual")
or
this.relevantSummaryElementGenerated(inSpec, outSpec, kind)
}
@@ -1021,10 +1024,8 @@ module Private {
)
}
- override predicate isAutoGenerated() { this.relevantSummaryElementGenerated(_, _, _) }
-
- override predicate hasProvenance(boolean generated) {
- summaryElement(this, _, _, _, generated)
+ override predicate hasProvenance(string provenance) {
+ summaryElement(this, _, _, _, provenance)
}
}
diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/FlowSummaryImpl.qll b/python/ql/lib/semmle/python/dataflow/new/internal/FlowSummaryImpl.qll
index d722aa68b70..b138fbf3417 100644
--- a/python/ql/lib/semmle/python/dataflow/new/internal/FlowSummaryImpl.qll
+++ b/python/ql/lib/semmle/python/dataflow/new/internal/FlowSummaryImpl.qll
@@ -241,15 +241,19 @@ module Public {
}
/**
- * Holds if the summary is auto generated and not manually generated.
+ * Holds if the summaries that apply to `this` are auto generated and not manually generated.
*/
- predicate isAutoGenerated() { none() }
+ final predicate isAutoGenerated() { this.hasProvenance("generated") and not this.isManual() }
/**
- * Holds if the summary has the given provenance where `true` is
- * `generated` and `false` is `manual`.
+ * Holds if there exists a manual summary that applies to `this`.
*/
- predicate hasProvenance(boolean generated) { none() }
+ final predicate isManual() { this.hasProvenance("manual") }
+
+ /**
+ * Holds if there exists a summary that applies to `this` that has provenance `provenance`.
+ */
+ predicate hasProvenance(string provenance) { none() }
}
/** A callable where there is no flow via the callable. */
@@ -259,13 +263,12 @@ module Public {
/**
* Holds if the neutral is auto generated.
*/
- predicate isAutoGenerated() { neutralElement(this, true) }
+ predicate isAutoGenerated() { neutralElement(this, "generated") }
/**
- * Holds if the neutral has the given provenance where `true` is
- * `generated` and `false` is `manual`.
+ * Holds if the neutral has provenance `provenance`.
*/
- predicate hasProvenance(boolean generated) { neutralElement(this, generated) }
+ predicate hasProvenance(string provenance) { neutralElement(this, provenance) }
}
}
@@ -997,12 +1000,12 @@ module Private {
private predicate relevantSummaryElementGenerated(
AccessPath inSpec, AccessPath outSpec, string kind
) {
- summaryElement(this, inSpec, outSpec, kind, true) and
- not summaryElement(this, _, _, _, false)
+ summaryElement(this, inSpec, outSpec, kind, "generated") and
+ not summaryElement(this, _, _, _, "manual")
}
private predicate relevantSummaryElement(AccessPath inSpec, AccessPath outSpec, string kind) {
- summaryElement(this, inSpec, outSpec, kind, false)
+ summaryElement(this, inSpec, outSpec, kind, "manual")
or
this.relevantSummaryElementGenerated(inSpec, outSpec, kind)
}
@@ -1021,10 +1024,8 @@ module Private {
)
}
- override predicate isAutoGenerated() { this.relevantSummaryElementGenerated(_, _, _) }
-
- override predicate hasProvenance(boolean generated) {
- summaryElement(this, _, _, _, generated)
+ override predicate hasProvenance(string provenance) {
+ summaryElement(this, _, _, _, provenance)
}
}
diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/FlowSummaryImpl.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/FlowSummaryImpl.qll
index d722aa68b70..b138fbf3417 100644
--- a/ruby/ql/lib/codeql/ruby/dataflow/internal/FlowSummaryImpl.qll
+++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/FlowSummaryImpl.qll
@@ -241,15 +241,19 @@ module Public {
}
/**
- * Holds if the summary is auto generated and not manually generated.
+ * Holds if the summaries that apply to `this` are auto generated and not manually generated.
*/
- predicate isAutoGenerated() { none() }
+ final predicate isAutoGenerated() { this.hasProvenance("generated") and not this.isManual() }
/**
- * Holds if the summary has the given provenance where `true` is
- * `generated` and `false` is `manual`.
+ * Holds if there exists a manual summary that applies to `this`.
*/
- predicate hasProvenance(boolean generated) { none() }
+ final predicate isManual() { this.hasProvenance("manual") }
+
+ /**
+ * Holds if there exists a summary that applies to `this` that has provenance `provenance`.
+ */
+ predicate hasProvenance(string provenance) { none() }
}
/** A callable where there is no flow via the callable. */
@@ -259,13 +263,12 @@ module Public {
/**
* Holds if the neutral is auto generated.
*/
- predicate isAutoGenerated() { neutralElement(this, true) }
+ predicate isAutoGenerated() { neutralElement(this, "generated") }
/**
- * Holds if the neutral has the given provenance where `true` is
- * `generated` and `false` is `manual`.
+ * Holds if the neutral has provenance `provenance`.
*/
- predicate hasProvenance(boolean generated) { neutralElement(this, generated) }
+ predicate hasProvenance(string provenance) { neutralElement(this, provenance) }
}
}
@@ -997,12 +1000,12 @@ module Private {
private predicate relevantSummaryElementGenerated(
AccessPath inSpec, AccessPath outSpec, string kind
) {
- summaryElement(this, inSpec, outSpec, kind, true) and
- not summaryElement(this, _, _, _, false)
+ summaryElement(this, inSpec, outSpec, kind, "generated") and
+ not summaryElement(this, _, _, _, "manual")
}
private predicate relevantSummaryElement(AccessPath inSpec, AccessPath outSpec, string kind) {
- summaryElement(this, inSpec, outSpec, kind, false)
+ summaryElement(this, inSpec, outSpec, kind, "manual")
or
this.relevantSummaryElementGenerated(inSpec, outSpec, kind)
}
@@ -1021,10 +1024,8 @@ module Private {
)
}
- override predicate isAutoGenerated() { this.relevantSummaryElementGenerated(_, _, _) }
-
- override predicate hasProvenance(boolean generated) {
- summaryElement(this, _, _, _, generated)
+ override predicate hasProvenance(string provenance) {
+ summaryElement(this, _, _, _, provenance)
}
}
diff --git a/swift/ql/lib/codeql/swift/dataflow/internal/FlowSummaryImpl.qll b/swift/ql/lib/codeql/swift/dataflow/internal/FlowSummaryImpl.qll
index d722aa68b70..b138fbf3417 100644
--- a/swift/ql/lib/codeql/swift/dataflow/internal/FlowSummaryImpl.qll
+++ b/swift/ql/lib/codeql/swift/dataflow/internal/FlowSummaryImpl.qll
@@ -241,15 +241,19 @@ module Public {
}
/**
- * Holds if the summary is auto generated and not manually generated.
+ * Holds if the summaries that apply to `this` are auto generated and not manually generated.
*/
- predicate isAutoGenerated() { none() }
+ final predicate isAutoGenerated() { this.hasProvenance("generated") and not this.isManual() }
/**
- * Holds if the summary has the given provenance where `true` is
- * `generated` and `false` is `manual`.
+ * Holds if there exists a manual summary that applies to `this`.
*/
- predicate hasProvenance(boolean generated) { none() }
+ final predicate isManual() { this.hasProvenance("manual") }
+
+ /**
+ * Holds if there exists a summary that applies to `this` that has provenance `provenance`.
+ */
+ predicate hasProvenance(string provenance) { none() }
}
/** A callable where there is no flow via the callable. */
@@ -259,13 +263,12 @@ module Public {
/**
* Holds if the neutral is auto generated.
*/
- predicate isAutoGenerated() { neutralElement(this, true) }
+ predicate isAutoGenerated() { neutralElement(this, "generated") }
/**
- * Holds if the neutral has the given provenance where `true` is
- * `generated` and `false` is `manual`.
+ * Holds if the neutral has provenance `provenance`.
*/
- predicate hasProvenance(boolean generated) { neutralElement(this, generated) }
+ predicate hasProvenance(string provenance) { neutralElement(this, provenance) }
}
}
@@ -997,12 +1000,12 @@ module Private {
private predicate relevantSummaryElementGenerated(
AccessPath inSpec, AccessPath outSpec, string kind
) {
- summaryElement(this, inSpec, outSpec, kind, true) and
- not summaryElement(this, _, _, _, false)
+ summaryElement(this, inSpec, outSpec, kind, "generated") and
+ not summaryElement(this, _, _, _, "manual")
}
private predicate relevantSummaryElement(AccessPath inSpec, AccessPath outSpec, string kind) {
- summaryElement(this, inSpec, outSpec, kind, false)
+ summaryElement(this, inSpec, outSpec, kind, "manual")
or
this.relevantSummaryElementGenerated(inSpec, outSpec, kind)
}
@@ -1021,10 +1024,8 @@ module Private {
)
}
- override predicate isAutoGenerated() { this.relevantSummaryElementGenerated(_, _, _) }
-
- override predicate hasProvenance(boolean generated) {
- summaryElement(this, _, _, _, generated)
+ override predicate hasProvenance(string provenance) {
+ summaryElement(this, _, _, _, provenance)
}
}
From 6a047d6916428cc5d7cdafcafe2d03f0cc1850aa Mon Sep 17 00:00:00 2001
From: Michael Nebel
Date: Fri, 16 Dec 2022 13:36:32 +0100
Subject: [PATCH 182/381] Java: Re-factor provenance related predicates for
summarized callable.
---
.../internal/FlowSummaryImplSpecific.qll | 40 ++++++-------------
.../Summaries/GeneratedVsManualCoverage.ql | 19 ++++-----
2 files changed, 23 insertions(+), 36 deletions(-)
diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImplSpecific.qll b/java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImplSpecific.qll
index 883b791835b..eac1c5379e1 100644
--- a/java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImplSpecific.qll
+++ b/java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImplSpecific.qll
@@ -66,13 +66,6 @@ DataFlowType getSyntheticGlobalType(SummaryComponent::SyntheticGlobal sg) {
result instanceof TypeObject
}
-bindingset[provenance]
-private boolean isGenerated(string provenance) {
- provenance = "generated" and result = true
- or
- provenance != "generated" and result = false
-}
-
private predicate relatedArgSpec(Callable c, string spec) {
exists(
string namespace, string type, boolean subtypes, string name, string signature, string ext
@@ -138,19 +131,17 @@ private predicate correspondingKotlinParameterDefaultsArgSpec(
/**
* Holds if an external flow summary exists for `c` with input specification
- * `input`, output specification `output`, kind `kind`, and a flag `generated`
- * stating whether the summary is autogenerated.
+ * `input`, output specification `output`, kind `kind`, and provenance `provenance`.
*/
predicate summaryElement(
- SummarizedCallableBase c, string input, string output, string kind, boolean generated
+ SummarizedCallableBase c, string input, string output, string kind, string provenance
) {
exists(
string namespace, string type, boolean subtypes, string name, string signature, string ext,
- string provenance, string originalInput, string originalOutput, Callable baseCallable
+ string originalInput, string originalOutput, Callable baseCallable
|
summaryModel(namespace, type, subtypes, name, signature, ext, originalInput, originalOutput,
kind, provenance) and
- generated = isGenerated(provenance) and
baseCallable = interpretElement(namespace, type, subtypes, name, signature, ext) and
(
c.asCallable() = baseCallable and input = originalInput and output = originalOutput
@@ -163,13 +154,12 @@ predicate summaryElement(
}
/**
- * Holds if a neutral model exists for `c`, which means that there is no
- * flow through `c`. The flag `generated` states whether the model is autogenerated.
+ * Holds if a neutral model exists for `c` with provenance `provenance`,
+ * which means that there is no flow through `c`.
*/
-predicate neutralElement(SummarizedCallableBase c, boolean generated) {
- exists(string namespace, string type, string name, string signature, string provenance |
+predicate neutralElement(SummarizedCallableBase c, string provenance) {
+ exists(string namespace, string type, string name, string signature |
neutralModel(namespace, type, name, signature, provenance) and
- generated = isGenerated(provenance) and
c.asCallable() = interpretElement(namespace, type, false, name, signature, "")
)
}
@@ -222,16 +212,14 @@ class SourceOrSinkElement = Top;
/**
* Holds if an external source specification exists for `e` with output specification
- * `output`, kind `kind`, and a flag `generated` stating whether the source specification is
- * autogenerated.
+ * `output`, kind `kind`, and provenance `provenance`.
*/
-predicate sourceElement(SourceOrSinkElement e, string output, string kind, boolean generated) {
+predicate sourceElement(SourceOrSinkElement e, string output, string kind, string provenance) {
exists(
string namespace, string type, boolean subtypes, string name, string signature, string ext,
- string provenance, SourceOrSinkElement baseSource, string originalOutput
+ SourceOrSinkElement baseSource, string originalOutput
|
sourceModel(namespace, type, subtypes, name, signature, ext, originalOutput, kind, provenance) and
- generated = isGenerated(provenance) and
baseSource = interpretElement(namespace, type, subtypes, name, signature, ext) and
(
e = baseSource and output = originalOutput
@@ -243,16 +231,14 @@ predicate sourceElement(SourceOrSinkElement e, string output, string kind, boole
/**
* Holds if an external sink specification exists for `e` with input specification
- * `input`, kind `kind` and a flag `generated` stating whether the sink specification is
- * autogenerated.
+ * `input`, kind `kind` and provenance `provenance`.
*/
-predicate sinkElement(SourceOrSinkElement e, string input, string kind, boolean generated) {
+predicate sinkElement(SourceOrSinkElement e, string input, string kind, string provenance) {
exists(
string namespace, string type, boolean subtypes, string name, string signature, string ext,
- string provenance, SourceOrSinkElement baseSink, string originalInput
+ SourceOrSinkElement baseSink, string originalInput
|
sinkModel(namespace, type, subtypes, name, signature, ext, originalInput, kind, provenance) and
- generated = isGenerated(provenance) and
baseSink = interpretElement(namespace, type, subtypes, name, signature, ext) and
(
e = baseSink and originalInput = input
diff --git a/java/ql/src/Metrics/Summaries/GeneratedVsManualCoverage.ql b/java/ql/src/Metrics/Summaries/GeneratedVsManualCoverage.ql
index eb03a785702..a37f2c005ac 100644
--- a/java/ql/src/Metrics/Summaries/GeneratedVsManualCoverage.ql
+++ b/java/ql/src/Metrics/Summaries/GeneratedVsManualCoverage.ql
@@ -26,15 +26,16 @@ private int getNumMadModeledApis(string package, string provenance) {
sc.isAutoGenerated() and
provenance = "generated"
or
- // "manual-only"
- sc.hasProvenance(false) and
- not sc.hasProvenance(true) and
- provenance = "manual"
- or
- // "both"
- sc.hasProvenance(false) and
- sc.hasProvenance(true) and
- provenance = "both"
+ sc.isManual() and
+ (
+ if sc.hasProvenance("generated")
+ then
+ // "both"
+ provenance = "both"
+ else
+ // "manual-only"
+ provenance = "manual"
+ )
)
)
}
From 6622eda04c51c986020290861b3bb31f6937c6df Mon Sep 17 00:00:00 2001
From: Michael Nebel
Date: Fri, 16 Dec 2022 14:53:15 +0100
Subject: [PATCH 183/381] Go: Re-factor provenance related predicates for
summarized callable.
---
go/ql/lib/semmle/go/dataflow/ExternalFlow.qll | 43 ++++++++-----------
.../internal/FlowSummaryImplSpecific.qll | 27 ++++++------
2 files changed, 31 insertions(+), 39 deletions(-)
diff --git a/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll b/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll
index 556c5d3b726..2d7081c46eb 100644
--- a/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll
+++ b/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll
@@ -124,17 +124,10 @@ predicate sinkModel(string row) { any(SinkModelCsv s).row(row) }
/** Holds if `row` is a summary model. */
predicate summaryModel(string row) { any(SummaryModelCsv s).row(row) }
-bindingset[input]
-private predicate getKind(string input, string kind, boolean generated) {
- input.splitAt(":", 0) = "generated" and kind = input.splitAt(":", 1) and generated = true
- or
- not input.matches("%:%") and kind = input and generated = false
-}
-
/** Holds if a source model exists for the given parameters. */
predicate sourceModel(
string namespace, string type, boolean subtypes, string name, string signature, string ext,
- string output, string kind, boolean generated
+ string output, string kind, string provenance
) {
exists(string row |
sourceModel(row) and
@@ -146,14 +139,15 @@ predicate sourceModel(
row.splitAt(";", 4) = signature and
row.splitAt(";", 5) = ext and
row.splitAt(";", 6) = output and
- exists(string k | row.splitAt(";", 7) = k and getKind(k, kind, generated))
+ row.splitAt(";", 7) = kind and
+ provenance = "manual"
)
}
/** Holds if a sink model exists for the given parameters. */
predicate sinkModel(
string namespace, string type, boolean subtypes, string name, string signature, string ext,
- string input, string kind, boolean generated
+ string input, string kind, string provenance
) {
exists(string row |
sinkModel(row) and
@@ -165,22 +159,23 @@ predicate sinkModel(
row.splitAt(";", 4) = signature and
row.splitAt(";", 5) = ext and
row.splitAt(";", 6) = input and
- exists(string k | row.splitAt(";", 7) = k and getKind(k, kind, generated))
+ row.splitAt(";", 7) = kind and
+ provenance = "manual"
)
}
/** Holds if a summary model exists for the given parameters. */
predicate summaryModel(
string namespace, string type, boolean subtypes, string name, string signature, string ext,
- string input, string output, string kind, boolean generated
+ string input, string output, string kind, string provenance
) {
- summaryModel(namespace, type, subtypes, name, signature, ext, input, output, kind, generated, _)
+ summaryModel(namespace, type, subtypes, name, signature, ext, input, output, kind, provenance, _)
}
/** Holds if a summary model `row` exists for the given parameters. */
predicate summaryModel(
string namespace, string type, boolean subtypes, string name, string signature, string ext,
- string input, string output, string kind, boolean generated, string row
+ string input, string output, string kind, string provenance, string row
) {
summaryModel(row) and
row.splitAt(";", 0) = namespace and
@@ -192,7 +187,8 @@ predicate summaryModel(
row.splitAt(";", 5) = ext and
row.splitAt(";", 6) = input and
row.splitAt(";", 7) = output and
- exists(string k | row.splitAt(";", 8) = k and getKind(k, kind, generated))
+ row.splitAt(";", 8) = kind and
+ provenance = "manual"
}
/** Holds if `package` have CSV framework coverage. */
@@ -241,25 +237,25 @@ predicate modelCoverage(string package, int pkgs, string kind, string part, int
part = "source" and
n =
strictcount(string subpkg, string type, boolean subtypes, string name, string signature,
- string ext, string output, boolean generated |
+ string ext, string output, string provenance |
canonicalPackageHasASubpackage(package, subpkg) and
- sourceModel(subpkg, type, subtypes, name, signature, ext, output, kind, generated)
+ sourceModel(subpkg, type, subtypes, name, signature, ext, output, kind, provenance)
)
or
part = "sink" and
n =
strictcount(string subpkg, string type, boolean subtypes, string name, string signature,
- string ext, string input, boolean generated |
+ string ext, string input, string provenance |
canonicalPackageHasASubpackage(package, subpkg) and
- sinkModel(subpkg, type, subtypes, name, signature, ext, input, kind, generated)
+ sinkModel(subpkg, type, subtypes, name, signature, ext, input, kind, provenance)
)
or
part = "summary" and
n =
strictcount(string subpkg, string type, boolean subtypes, string name, string signature,
- string ext, string input, string output, boolean generated |
+ string ext, string input, string output, string provenance |
canonicalPackageHasASubpackage(package, subpkg) and
- summaryModel(subpkg, type, subtypes, name, signature, ext, input, output, kind, generated)
+ summaryModel(subpkg, type, subtypes, name, signature, ext, input, output, kind, provenance)
)
)
}
@@ -298,9 +294,8 @@ module CsvValidation {
}
private string getInvalidModelKind() {
- exists(string row, string k, string kind | summaryModel(row) |
- k = row.splitAt(";", 8) and
- getKind(k, kind, _) and
+ exists(string row, string kind | summaryModel(row) |
+ kind = row.splitAt(";", 8) and
not kind = ["taint", "value"] and
result = "Invalid kind \"" + kind + "\" in summary model."
)
diff --git a/go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImplSpecific.qll b/go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImplSpecific.qll
index fd82938968a..5e3768d52f4 100644
--- a/go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImplSpecific.qll
+++ b/go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImplSpecific.qll
@@ -60,26 +60,25 @@ DataFlowType getSyntheticGlobalType(SummaryComponent::SyntheticGlobal sg) { any(
/**
* Holds if an external flow summary exists for `c` with input specification
- * `input`, output specification `output`, kind `kind`, and a flag `generated`
- * stating whether the summary is autogenerated.
+ * `input`, output specification `output`, kind `kind`, and provenance `provenance`.
*/
predicate summaryElement(
- SummarizedCallableBase c, string input, string output, string kind, boolean generated
+ SummarizedCallableBase c, string input, string output, string kind, string provenance
) {
exists(
string namespace, string type, boolean subtypes, string name, string signature, string ext
|
- summaryModel(namespace, type, subtypes, name, signature, ext, input, output, kind, generated) and
+ summaryModel(namespace, type, subtypes, name, signature, ext, input, output, kind, provenance) and
c.asFunction() = interpretElement(namespace, type, subtypes, name, signature, ext).asEntity()
)
}
/**
- * Holds if a neutral model exists for `c`, which means that there is no
- * flow through `c`. The flag `generated` states whether the model is autogenerated.
+ * Holds if a neutral model exists for `c` with provenance `provenance`,
+ * which means that there is no flow through `c`.
* Note. Neutral models have not been implemented for Go.
*/
-predicate neutralElement(SummarizedCallable c, boolean generated) { none() }
+predicate neutralElement(SummarizedCallable c, string provenance) { none() }
/** Gets the summary component for specification component `c`, if any. */
bindingset[c]
@@ -152,28 +151,26 @@ class SourceOrSinkElement extends TSourceOrSinkElement {
/**
* Holds if an external source specification exists for `e` with output specification
- * `output`, kind `kind`, and a flag `generated` stating whether the source specification is
- * autogenerated.
+ * `output`, kind `kind`, and provenance `provenance`.
*/
-predicate sourceElement(SourceOrSinkElement e, string output, string kind, boolean generated) {
+predicate sourceElement(SourceOrSinkElement e, string output, string kind, string provenance) {
exists(
string namespace, string type, boolean subtypes, string name, string signature, string ext
|
- sourceModel(namespace, type, subtypes, name, signature, ext, output, kind, generated) and
+ sourceModel(namespace, type, subtypes, name, signature, ext, output, kind, provenance) and
e = interpretElement(namespace, type, subtypes, name, signature, ext)
)
}
/**
* Holds if an external sink specification exists for `e` with input specification
- * `input`, kind `kind` and a flag `generated` stating whether the sink specification is
- * autogenerated.
+ * `input`, kind `kind` and provenance `provenance`.
*/
-predicate sinkElement(SourceOrSinkElement e, string input, string kind, boolean generated) {
+predicate sinkElement(SourceOrSinkElement e, string input, string kind, string provenance) {
exists(
string namespace, string type, boolean subtypes, string name, string signature, string ext
|
- sinkModel(namespace, type, subtypes, name, signature, ext, input, kind, generated) and
+ sinkModel(namespace, type, subtypes, name, signature, ext, input, kind, provenance) and
e = interpretElement(namespace, type, subtypes, name, signature, ext)
)
}
From 59a9e255c758d32231af0696751daa5ce9ad58cb Mon Sep 17 00:00:00 2001
From: Michael Nebel
Date: Mon, 19 Dec 2022 12:56:39 +0100
Subject: [PATCH 184/381] Python: Re-factor provenance related predicates for
summarized callable.
---
.../new/internal/FlowSummaryImplSpecific.qll | 23 ++++++++-----------
1 file changed, 10 insertions(+), 13 deletions(-)
diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/FlowSummaryImplSpecific.qll b/python/ql/lib/semmle/python/dataflow/new/internal/FlowSummaryImplSpecific.qll
index c78fe0c857d..858f7c372a5 100644
--- a/python/ql/lib/semmle/python/dataflow/new/internal/FlowSummaryImplSpecific.qll
+++ b/python/ql/lib/semmle/python/dataflow/new/internal/FlowSummaryImplSpecific.qll
@@ -78,25 +78,24 @@ DataFlowType getSyntheticGlobalType(SummaryComponent::SyntheticGlobal sg) { any(
/**
* Holds if an external flow summary exists for `c` with input specification
- * `input`, output specification `output`, kind `kind`, and a flag `generated`
- * stating whether the summary is autogenerated.
+ * `input`, output specification `output`, kind `kind`, and provenance `provenance`.
*/
predicate summaryElement(
- FlowSummary::SummarizedCallable c, string input, string output, string kind, boolean generated
+ FlowSummary::SummarizedCallable c, string input, string output, string kind, string provenance
) {
exists(boolean preservesValue |
c.propagatesFlowExt(input, output, preservesValue) and
(if preservesValue = true then kind = "value" else kind = "taint") and
- generated = false
+ provenance = "manual"
)
}
/**
- * Holds if a neutral model exists for `c`, which means that there is no
- * flow through `c`. The flag `generated` states whether the neutral model is autogenerated.
+ * Holds if a neutral model exists for `c` with provenance `provenance`,
+ * which means that there is no flow through `c`.
* Note. Neutral models have not been implemented for Python.
*/
-predicate neutralElement(FlowSummary::SummarizedCallable c, boolean generated) { none() }
+predicate neutralElement(FlowSummary::SummarizedCallable c, string provenance) { none() }
/**
* Gets the summary component for specification component `c`, if any.
@@ -137,17 +136,15 @@ ReturnKind getReturnValueKind() { any() }
private module UnusedSourceSinkInterpretation {
/**
* Holds if an external source specification exists for `n` with output specification
- * `output`, kind `kind`, and a flag `generated` stating whether the source specification is
- * autogenerated.
+ * `output`, kind `kind`, and provenance `provenance`.
*/
- predicate sourceElement(AstNode n, string output, string kind, boolean generated) { none() }
+ predicate sourceElement(AstNode n, string output, string kind, string provenance) { none() }
/**
* Holds if an external sink specification exists for `n` with input specification
- * `input`, kind `kind` and a flag `generated` stating whether the sink specification is
- * autogenerated.
+ * `input`, kind `kind` and provenance `provenance`.
*/
- predicate sinkElement(AstNode n, string input, string kind, boolean generated) { none() }
+ predicate sinkElement(AstNode n, string input, string kind, string provenance) { none() }
class SourceOrSinkElement = AstNode;
From c01361a1fd8b23dbda4349a9c746121e7be409de Mon Sep 17 00:00:00 2001
From: Michael Nebel
Date: Mon, 19 Dec 2022 13:00:46 +0100
Subject: [PATCH 185/381] Ruby: Re-factor provenance related predicates for
summarized callable.
---
.../internal/FlowSummaryImplSpecific.qll | 24 ++++++++-----------
1 file changed, 10 insertions(+), 14 deletions(-)
diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/FlowSummaryImplSpecific.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/FlowSummaryImplSpecific.qll
index 7e569972bb6..00e0a15ef77 100644
--- a/ruby/ql/lib/codeql/ruby/dataflow/internal/FlowSummaryImplSpecific.qll
+++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/FlowSummaryImplSpecific.qll
@@ -49,25 +49,23 @@ DataFlowType getSyntheticGlobalType(SummaryComponent::SyntheticGlobal sg) { any(
/**
* Holds if an external flow summary exists for `c` with input specification
- * `input`, output specification `output`, kind `kind`, and a flag `generated`
- * stating whether the summary is autogenerated.
+ * `input`, output specification `output`, kind `kind`, and provenance `provenance`.
*/
predicate summaryElement(
- FlowSummary::SummarizedCallable c, string input, string output, string kind, boolean generated
+ FlowSummary::SummarizedCallable c, string input, string output, string kind, string provenance
) {
exists(boolean preservesValue |
c.propagatesFlowExt(input, output, preservesValue) and
(if preservesValue = true then kind = "value" else kind = "taint") and
- generated = false
+ provenance = "manual"
)
}
/**
- * Holds if a neutral model exists for `c`, which means that there is no
- * flow through `c`. The flag `generated` states whether the neutral model is autogenerated.
- * Note. Neutral models have not been implemented for ruby.
+ * Holds if a neutral model exists for `c` with provenance `provenance`,
+ * which means that there is no flow through `c`.
*/
-predicate neutralElement(FlowSummary::SummarizedCallable c, boolean generated) { none() }
+predicate neutralElement(FlowSummary::SummarizedCallable c, string provenance) { none() }
bindingset[arg]
private SummaryComponent interpretElementArg(string arg) {
@@ -207,17 +205,15 @@ NormalReturnKind getReturnValueKind() { any() }
private module UnusedSourceSinkInterpretation {
/**
* Holds if an external source specification exists for `n` with output specification
- * `output`, kind `kind`, and a flag `generated` stating whether the source specification is
- * autogenerated.
+ * `output`, kind `kind`, and provenance `provenance`.
*/
- predicate sourceElement(AstNode n, string output, string kind, boolean generated) { none() }
+ predicate sourceElement(AstNode n, string output, string kind, string provenance) { none() }
/**
* Holds if an external sink specification exists for `n` with input specification
- * `input`, kind `kind` and a flag `generated` stating whether the sink specification is
- * autogenerated.
+ * `input`, kind `kind` and provenance `provenance`.
*/
- predicate sinkElement(AstNode n, string input, string kind, boolean generated) { none() }
+ predicate sinkElement(AstNode n, string input, string kind, string provenance) { none() }
class SourceOrSinkElement = AstNode;
From 80a4197604eebd68e246f26ac1d874d5e7b6f0ea Mon Sep 17 00:00:00 2001
From: Michael Nebel
Date: Mon, 19 Dec 2022 13:13:56 +0100
Subject: [PATCH 186/381] Swift: Re-factor provenance related predicates for
summarized callable.
---
.../codeql/swift/dataflow/ExternalFlow.qll | 24 ++++++++--------
.../internal/FlowSummaryImplSpecific.qll | 28 ++++++++-----------
2 files changed, 24 insertions(+), 28 deletions(-)
diff --git a/swift/ql/lib/codeql/swift/dataflow/ExternalFlow.qll b/swift/ql/lib/codeql/swift/dataflow/ExternalFlow.qll
index 2c90d1e7351..89db67289f6 100644
--- a/swift/ql/lib/codeql/swift/dataflow/ExternalFlow.qll
+++ b/swift/ql/lib/codeql/swift/dataflow/ExternalFlow.qll
@@ -135,7 +135,7 @@ predicate summaryModel(string row) { any(SummaryModelCsv s).row(row) }
/** Holds if a source model exists for the given parameters. */
predicate sourceModel(
string namespace, string type, boolean subtypes, string name, string signature, string ext,
- string output, string kind, boolean generated
+ string output, string kind, string provenance
) {
exists(string row |
sourceModel(row) and
@@ -149,13 +149,13 @@ predicate sourceModel(
row.splitAt(";", 6) = output and
row.splitAt(";", 7) = kind
) and
- generated = false
+ provenance = "manual"
}
/** Holds if a sink model exists for the given parameters. */
predicate sinkModel(
string namespace, string type, boolean subtypes, string name, string signature, string ext,
- string input, string kind, boolean generated
+ string input, string kind, string provenance
) {
exists(string row |
sinkModel(row) and
@@ -169,13 +169,13 @@ predicate sinkModel(
row.splitAt(";", 6) = input and
row.splitAt(";", 7) = kind
) and
- generated = false
+ provenance = "manual"
}
/** Holds if a summary model exists for the given parameters. */
predicate summaryModel(
string namespace, string type, boolean subtypes, string name, string signature, string ext,
- string input, string output, string kind, boolean generated
+ string input, string output, string kind, string provenance
) {
exists(string row |
summaryModel(row) and
@@ -190,7 +190,7 @@ predicate summaryModel(
row.splitAt(";", 7) = output and
row.splitAt(";", 8) = kind
) and
- generated = false
+ provenance = "manual"
}
private predicate relevantNamespace(string namespace) {
@@ -224,25 +224,25 @@ predicate modelCoverage(string namespace, int namespaces, string kind, string pa
part = "source" and
n =
strictcount(string subns, string type, boolean subtypes, string name, string signature,
- string ext, string output, boolean generated |
+ string ext, string output, string provenance |
canonicalNamespaceLink(namespace, subns) and
- sourceModel(subns, type, subtypes, name, signature, ext, output, kind, generated)
+ sourceModel(subns, type, subtypes, name, signature, ext, output, kind, provenance)
)
or
part = "sink" and
n =
strictcount(string subns, string type, boolean subtypes, string name, string signature,
- string ext, string input, boolean generated |
+ string ext, string input, string provenance |
canonicalNamespaceLink(namespace, subns) and
- sinkModel(subns, type, subtypes, name, signature, ext, input, kind, generated)
+ sinkModel(subns, type, subtypes, name, signature, ext, input, kind, provenance)
)
or
part = "summary" and
n =
strictcount(string subns, string type, boolean subtypes, string name, string signature,
- string ext, string input, string output, boolean generated |
+ string ext, string input, string output, string provenance |
canonicalNamespaceLink(namespace, subns) and
- summaryModel(subns, type, subtypes, name, signature, ext, input, output, kind, generated)
+ summaryModel(subns, type, subtypes, name, signature, ext, input, output, kind, provenance)
)
)
}
diff --git a/swift/ql/lib/codeql/swift/dataflow/internal/FlowSummaryImplSpecific.qll b/swift/ql/lib/codeql/swift/dataflow/internal/FlowSummaryImplSpecific.qll
index cdaded55342..5a364c3f63b 100644
--- a/swift/ql/lib/codeql/swift/dataflow/internal/FlowSummaryImplSpecific.qll
+++ b/swift/ql/lib/codeql/swift/dataflow/internal/FlowSummaryImplSpecific.qll
@@ -56,51 +56,47 @@ DataFlowType getSyntheticGlobalType(SummaryComponent::SyntheticGlobal sg) { any(
/**
* Holds if an external flow summary exists for `c` with input specification
- * `input`, output specification `output`, kind `kind`, and a flag `generated`
- * stating whether the summary is autogenerated.
+ * `input`, output specification `output`, kind `kind`, and provenance `provenance`.
*/
predicate summaryElement(
- AbstractFunctionDecl c, string input, string output, string kind, boolean generated
+ AbstractFunctionDecl c, string input, string output, string kind, string provenance
) {
exists(
string namespace, string type, boolean subtypes, string name, string signature, string ext
|
- summaryModel(namespace, type, subtypes, name, signature, ext, input, output, kind, generated) and
+ summaryModel(namespace, type, subtypes, name, signature, ext, input, output, kind, provenance) and
c = interpretElement(namespace, type, subtypes, name, signature, ext)
)
}
/**
- * Holds if a neutral model exists for `c`, which means that there is no
- * flow through `c`. The flag `generated` states whether the neutral model is autogenerated.
- * Note. Neutral models have not been implemented for swift.
+ * Holds if a neutral model exists for `c` with provenance `provenance`,
+ * which means that there is no flow through `c`.
*/
-predicate neutralElement(AbstractFunctionDecl c, boolean generated) { none() }
+predicate neutralElement(AbstractFunctionDecl c, string provenance) { none() }
/**
* Holds if an external source specification exists for `e` with output specification
- * `output`, kind `kind`, and a flag `generated` stating whether the source specification is
- * autogenerated.
+ * `output`, kind `kind`, and provenance `provenance`.
*/
-predicate sourceElement(Element e, string output, string kind, boolean generated) {
+predicate sourceElement(Element e, string output, string kind, string provenance) {
exists(
string namespace, string type, boolean subtypes, string name, string signature, string ext
|
- sourceModel(namespace, type, subtypes, name, signature, ext, output, kind, generated) and
+ sourceModel(namespace, type, subtypes, name, signature, ext, output, kind, provenance) and
e = interpretElement(namespace, type, subtypes, name, signature, ext)
)
}
/**
* Holds if an external sink specification exists for `e` with input specification
- * `input`, kind `kind` and a flag `generated` stating whether the sink specification is
- * autogenerated.
+ * `input`, kind `kind` and provenance `provenance`.
*/
-predicate sinkElement(Element e, string input, string kind, boolean generated) {
+predicate sinkElement(Element e, string input, string kind, string provenance) {
exists(
string namespace, string type, boolean subtypes, string name, string signature, string ext
|
- sinkModel(namespace, type, subtypes, name, signature, ext, input, kind, generated) and
+ sinkModel(namespace, type, subtypes, name, signature, ext, input, kind, provenance) and
e = interpretElement(namespace, type, subtypes, name, signature, ext)
)
}
From 372ecf402fba34db9b660ae2dafaac89244b117b Mon Sep 17 00:00:00 2001
From: Michael Nebel
Date: Mon, 19 Dec 2022 13:30:38 +0100
Subject: [PATCH 187/381] Go: Delete unused summaryModel predicate.
---
go/ql/lib/semmle/go/dataflow/ExternalFlow.qll | 32 ++++++++-----------
1 file changed, 13 insertions(+), 19 deletions(-)
diff --git a/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll b/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll
index 2d7081c46eb..f3213e78627 100644
--- a/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll
+++ b/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll
@@ -169,25 +169,19 @@ predicate summaryModel(
string namespace, string type, boolean subtypes, string name, string signature, string ext,
string input, string output, string kind, string provenance
) {
- summaryModel(namespace, type, subtypes, name, signature, ext, input, output, kind, provenance, _)
-}
-
-/** Holds if a summary model `row` exists for the given parameters. */
-predicate summaryModel(
- string namespace, string type, boolean subtypes, string name, string signature, string ext,
- string input, string output, string kind, string provenance, string row
-) {
- summaryModel(row) and
- row.splitAt(";", 0) = namespace and
- row.splitAt(";", 1) = type and
- row.splitAt(";", 2) = subtypes.toString() and
- subtypes = [true, false] and
- row.splitAt(";", 3) = name and
- row.splitAt(";", 4) = signature and
- row.splitAt(";", 5) = ext and
- row.splitAt(";", 6) = input and
- row.splitAt(";", 7) = output and
- row.splitAt(";", 8) = kind and
+ exists(string row |
+ summaryModel(row) and
+ row.splitAt(";", 0) = namespace and
+ row.splitAt(";", 1) = type and
+ row.splitAt(";", 2) = subtypes.toString() and
+ subtypes = [true, false] and
+ row.splitAt(";", 3) = name and
+ row.splitAt(";", 4) = signature and
+ row.splitAt(";", 5) = ext and
+ row.splitAt(";", 6) = input and
+ row.splitAt(";", 7) = output and
+ row.splitAt(";", 8) = kind
+ ) and
provenance = "manual"
}
From 8112058a0a9352ca30c6f1d06e2e49c087b0eeae Mon Sep 17 00:00:00 2001
From: Michael Nebel
Date: Wed, 4 Jan 2023 10:35:17 +0100
Subject: [PATCH 188/381] Java: Adapt TopJdpApi library to the re-factor.
---
.../semmle/code/java/dataflow/internal/FlowSummaryImpl.qll | 7 ++++++-
java/ql/test/ext/TopJdkApis/TopJdkApis.qll | 4 ++--
2 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImpl.qll b/java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImpl.qll
index b138fbf3417..016ee69f66b 100644
--- a/java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImpl.qll
+++ b/java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImpl.qll
@@ -261,10 +261,15 @@ module Public {
NeutralCallable() { neutralElement(this, _) }
/**
- * Holds if the neutral is auto generated.
+ * Holds if the neutral is auto generated.
*/
predicate isAutoGenerated() { neutralElement(this, "generated") }
+ /**
+ * Holds if there exists a manual neutral that applies to `this`.
+ */
+ final predicate isManual() { this.hasProvenance("manual") }
+
/**
* Holds if the neutral has provenance `provenance`.
*/
diff --git a/java/ql/test/ext/TopJdkApis/TopJdkApis.qll b/java/ql/test/ext/TopJdkApis/TopJdkApis.qll
index 76892845054..5b20b1c67c3 100644
--- a/java/ql/test/ext/TopJdkApis/TopJdkApis.qll
+++ b/java/ql/test/ext/TopJdkApis/TopJdkApis.qll
@@ -78,11 +78,11 @@ class TopJdkApi extends SummarizedCallableBase {
}
/** Holds if this API has a manual summary model. */
- private predicate hasManualSummary() { this.(SummarizedCallable).hasProvenance(false) }
+ private predicate hasManualSummary() { this.(SummarizedCallable).isManual() }
/** Holds if this API has a manual neutral model. */
private predicate hasManualNeutral() {
- this.(FlowSummaryImpl::Public::NeutralCallable).hasProvenance(false)
+ this.(FlowSummaryImpl::Public::NeutralCallable).isManual()
}
/** Holds if this API has a manual MaD model. */
From 67cbe382551151c2c6f308c348079af32b339c88 Mon Sep 17 00:00:00 2001
From: Michael Nebel
Date: Wed, 4 Jan 2023 10:49:35 +0100
Subject: [PATCH 189/381] Sync files.
---
.../code/csharp/dataflow/internal/FlowSummaryImpl.qll | 7 ++++++-
go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImpl.qll | 7 ++++++-
.../python/dataflow/new/internal/FlowSummaryImpl.qll | 7 ++++++-
.../lib/codeql/ruby/dataflow/internal/FlowSummaryImpl.qll | 7 ++++++-
.../lib/codeql/swift/dataflow/internal/FlowSummaryImpl.qll | 7 ++++++-
5 files changed, 30 insertions(+), 5 deletions(-)
diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll
index b138fbf3417..016ee69f66b 100644
--- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll
+++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll
@@ -261,10 +261,15 @@ module Public {
NeutralCallable() { neutralElement(this, _) }
/**
- * Holds if the neutral is auto generated.
+ * Holds if the neutral is auto generated.
*/
predicate isAutoGenerated() { neutralElement(this, "generated") }
+ /**
+ * Holds if there exists a manual neutral that applies to `this`.
+ */
+ final predicate isManual() { this.hasProvenance("manual") }
+
/**
* Holds if the neutral has provenance `provenance`.
*/
diff --git a/go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImpl.qll b/go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImpl.qll
index b138fbf3417..016ee69f66b 100644
--- a/go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImpl.qll
+++ b/go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImpl.qll
@@ -261,10 +261,15 @@ module Public {
NeutralCallable() { neutralElement(this, _) }
/**
- * Holds if the neutral is auto generated.
+ * Holds if the neutral is auto generated.
*/
predicate isAutoGenerated() { neutralElement(this, "generated") }
+ /**
+ * Holds if there exists a manual neutral that applies to `this`.
+ */
+ final predicate isManual() { this.hasProvenance("manual") }
+
/**
* Holds if the neutral has provenance `provenance`.
*/
diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/FlowSummaryImpl.qll b/python/ql/lib/semmle/python/dataflow/new/internal/FlowSummaryImpl.qll
index b138fbf3417..016ee69f66b 100644
--- a/python/ql/lib/semmle/python/dataflow/new/internal/FlowSummaryImpl.qll
+++ b/python/ql/lib/semmle/python/dataflow/new/internal/FlowSummaryImpl.qll
@@ -261,10 +261,15 @@ module Public {
NeutralCallable() { neutralElement(this, _) }
/**
- * Holds if the neutral is auto generated.
+ * Holds if the neutral is auto generated.
*/
predicate isAutoGenerated() { neutralElement(this, "generated") }
+ /**
+ * Holds if there exists a manual neutral that applies to `this`.
+ */
+ final predicate isManual() { this.hasProvenance("manual") }
+
/**
* Holds if the neutral has provenance `provenance`.
*/
diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/FlowSummaryImpl.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/FlowSummaryImpl.qll
index b138fbf3417..016ee69f66b 100644
--- a/ruby/ql/lib/codeql/ruby/dataflow/internal/FlowSummaryImpl.qll
+++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/FlowSummaryImpl.qll
@@ -261,10 +261,15 @@ module Public {
NeutralCallable() { neutralElement(this, _) }
/**
- * Holds if the neutral is auto generated.
+ * Holds if the neutral is auto generated.
*/
predicate isAutoGenerated() { neutralElement(this, "generated") }
+ /**
+ * Holds if there exists a manual neutral that applies to `this`.
+ */
+ final predicate isManual() { this.hasProvenance("manual") }
+
/**
* Holds if the neutral has provenance `provenance`.
*/
diff --git a/swift/ql/lib/codeql/swift/dataflow/internal/FlowSummaryImpl.qll b/swift/ql/lib/codeql/swift/dataflow/internal/FlowSummaryImpl.qll
index b138fbf3417..016ee69f66b 100644
--- a/swift/ql/lib/codeql/swift/dataflow/internal/FlowSummaryImpl.qll
+++ b/swift/ql/lib/codeql/swift/dataflow/internal/FlowSummaryImpl.qll
@@ -261,10 +261,15 @@ module Public {
NeutralCallable() { neutralElement(this, _) }
/**
- * Holds if the neutral is auto generated.
+ * Holds if the neutral is auto generated.
*/
predicate isAutoGenerated() { neutralElement(this, "generated") }
+ /**
+ * Holds if there exists a manual neutral that applies to `this`.
+ */
+ final predicate isManual() { this.hasProvenance("manual") }
+
/**
* Holds if the neutral has provenance `provenance`.
*/
From 7e4f7a0c17eb09a8e4a57b82d95d66c7c4ed6c43 Mon Sep 17 00:00:00 2001
From: Michael Nebel
Date: Wed, 11 Jan 2023 16:28:47 +0100
Subject: [PATCH 190/381] C#: Address review comments and sync files.
---
.../semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll | 2 +-
go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImpl.qll | 2 +-
.../lib/semmle/code/java/dataflow/internal/FlowSummaryImpl.qll | 2 +-
.../lib/semmle/python/dataflow/new/internal/FlowSummaryImpl.qll | 2 +-
ruby/ql/lib/codeql/ruby/dataflow/internal/FlowSummaryImpl.qll | 2 +-
swift/ql/lib/codeql/swift/dataflow/internal/FlowSummaryImpl.qll | 2 +-
6 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll
index 016ee69f66b..82db0889ace 100644
--- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll
+++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll
@@ -241,7 +241,7 @@ module Public {
}
/**
- * Holds if the summaries that apply to `this` are auto generated and not manually generated.
+ * Holds if all the summaries that apply to `this` are auto generated and not manually created.
*/
final predicate isAutoGenerated() { this.hasProvenance("generated") and not this.isManual() }
diff --git a/go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImpl.qll b/go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImpl.qll
index 016ee69f66b..82db0889ace 100644
--- a/go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImpl.qll
+++ b/go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImpl.qll
@@ -241,7 +241,7 @@ module Public {
}
/**
- * Holds if the summaries that apply to `this` are auto generated and not manually generated.
+ * Holds if all the summaries that apply to `this` are auto generated and not manually created.
*/
final predicate isAutoGenerated() { this.hasProvenance("generated") and not this.isManual() }
diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImpl.qll b/java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImpl.qll
index 016ee69f66b..82db0889ace 100644
--- a/java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImpl.qll
+++ b/java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImpl.qll
@@ -241,7 +241,7 @@ module Public {
}
/**
- * Holds if the summaries that apply to `this` are auto generated and not manually generated.
+ * Holds if all the summaries that apply to `this` are auto generated and not manually created.
*/
final predicate isAutoGenerated() { this.hasProvenance("generated") and not this.isManual() }
diff --git a/python/ql/lib/semmle/python/dataflow/new/internal/FlowSummaryImpl.qll b/python/ql/lib/semmle/python/dataflow/new/internal/FlowSummaryImpl.qll
index 016ee69f66b..82db0889ace 100644
--- a/python/ql/lib/semmle/python/dataflow/new/internal/FlowSummaryImpl.qll
+++ b/python/ql/lib/semmle/python/dataflow/new/internal/FlowSummaryImpl.qll
@@ -241,7 +241,7 @@ module Public {
}
/**
- * Holds if the summaries that apply to `this` are auto generated and not manually generated.
+ * Holds if all the summaries that apply to `this` are auto generated and not manually created.
*/
final predicate isAutoGenerated() { this.hasProvenance("generated") and not this.isManual() }
diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/FlowSummaryImpl.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/FlowSummaryImpl.qll
index 016ee69f66b..82db0889ace 100644
--- a/ruby/ql/lib/codeql/ruby/dataflow/internal/FlowSummaryImpl.qll
+++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/FlowSummaryImpl.qll
@@ -241,7 +241,7 @@ module Public {
}
/**
- * Holds if the summaries that apply to `this` are auto generated and not manually generated.
+ * Holds if all the summaries that apply to `this` are auto generated and not manually created.
*/
final predicate isAutoGenerated() { this.hasProvenance("generated") and not this.isManual() }
diff --git a/swift/ql/lib/codeql/swift/dataflow/internal/FlowSummaryImpl.qll b/swift/ql/lib/codeql/swift/dataflow/internal/FlowSummaryImpl.qll
index 016ee69f66b..82db0889ace 100644
--- a/swift/ql/lib/codeql/swift/dataflow/internal/FlowSummaryImpl.qll
+++ b/swift/ql/lib/codeql/swift/dataflow/internal/FlowSummaryImpl.qll
@@ -241,7 +241,7 @@ module Public {
}
/**
- * Holds if the summaries that apply to `this` are auto generated and not manually generated.
+ * Holds if all the summaries that apply to `this` are auto generated and not manually created.
*/
final predicate isAutoGenerated() { this.hasProvenance("generated") and not this.isManual() }
From ac064ac2a78aae7c7096a519949e30765f3c58ad Mon Sep 17 00:00:00 2001
From: Jami Cogswell
Date: Wed, 11 Jan 2023 10:30:49 -0500
Subject: [PATCH 191/381] Java: remove model for Collectors.joining
---
java/ql/lib/ext/java.util.stream.model.yml | 1 -
java/ql/test/ext/TestModels/Test.java | 3 ---
java/ql/test/ext/TopJdkApis/TopJdkApis.qll | 7 ++++---
java/ql/test/ext/TopJdkApis/TopJdkApisTest.expected | 1 +
4 files changed, 5 insertions(+), 7 deletions(-)
diff --git a/java/ql/lib/ext/java.util.stream.model.yml b/java/ql/lib/ext/java.util.stream.model.yml
index 7df9272f4be..190cc2709b4 100644
--- a/java/ql/lib/ext/java.util.stream.model.yml
+++ b/java/ql/lib/ext/java.util.stream.model.yml
@@ -9,7 +9,6 @@ extensions:
- ["java.util.stream", "BaseStream", True, "sequential", "()", "", "Argument[-1].Element", "ReturnValue.Element", "value", "manual"]
- ["java.util.stream", "BaseStream", True, "spliterator", "()", "", "Argument[-1].Element", "ReturnValue.Element", "value", "manual"]
- ["java.util.stream", "BaseStream", True, "unordered", "()", "", "Argument[-1].Element", "ReturnValue.Element", "value", "manual"]
- - ["java.util.stream", "Collectors", False, "joining", "(CharSequence)", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["java.util.stream", "Stream", True, "allMatch", "(Predicate)", "", "Argument[-1].Element", "Argument[0].Parameter[0]", "value", "manual"]
- ["java.util.stream", "Stream", True, "anyMatch", "(Predicate)", "", "Argument[-1].Element", "Argument[0].Parameter[0]", "value", "manual"]
- ["java.util.stream", "Stream", True, "collect", "(Supplier,BiConsumer,BiConsumer)", "", "Argument[-1].Element", "Argument[1].Parameter[1]", "value", "manual"]
diff --git a/java/ql/test/ext/TestModels/Test.java b/java/ql/test/ext/TestModels/Test.java
index 7be2728b190..3afd2c80897 100644
--- a/java/ql/test/ext/TestModels/Test.java
+++ b/java/ql/test/ext/TestModels/Test.java
@@ -129,9 +129,6 @@ public class Test {
AtomicReference ar = new AtomicReference(source());
sink(ar.get()); // $hasValueFlow
- // java.util.stream
- sink(Collectors.joining((CharSequence)source())); // $hasTaintFlow
-
// java.util.concurrent
CountDownLatch cdl = new CountDownLatch((int)source());
sink(cdl.getCount()); // $hasValueFlow
diff --git a/java/ql/test/ext/TopJdkApis/TopJdkApis.qll b/java/ql/test/ext/TopJdkApis/TopJdkApis.qll
index dca6afb4035..858659634f5 100644
--- a/java/ql/test/ext/TopJdkApis/TopJdkApis.qll
+++ b/java/ql/test/ext/TopJdkApis/TopJdkApis.qll
@@ -143,9 +143,10 @@ class TopJdkApi extends SummarizedCallableBase {
predicate hasManualMadModel() { this.hasManualSummary() or this.hasManualNeutral() }
/*
* Note: the following top-100 APIs are not modeled with MaD:
- * java.util.stream.Stream#collect(Collector) : handled separately on a case-by-case basis as it is too complex for MaD
- * java.lang.String#valueOf(Object) : also a complex case; an alias for `Object.toString`, except the dispatch is hidden
- * java.lang.Throwable#printStackTrace() : should probably not be a general step, but there might be specialised queries that care
+ * `java.util.stream.Stream#collect(Collector)`: handled separately on a case-by-case basis as it is too complex for MaD
+ * `java.util.stream.Collectors#joining(CharSequence)`: cannot be modeled completely without a model for `java.util.stream.Stream#collect(Collector)` as well
+ * `java.lang.String#valueOf(Object)`: also a complex case; an alias for `Object.toString`, except the dispatch is hidden
+ * `java.lang.Throwable#printStackTrace()`: should probably not be a general step, but there might be specialised queries that care
*/
}
diff --git a/java/ql/test/ext/TopJdkApis/TopJdkApisTest.expected b/java/ql/test/ext/TopJdkApis/TopJdkApisTest.expected
index 773d9b2bfae..abe2044906d 100644
--- a/java/ql/test/ext/TopJdkApis/TopJdkApisTest.expected
+++ b/java/ql/test/ext/TopJdkApis/TopJdkApisTest.expected
@@ -1,3 +1,4 @@
| java.lang.String#valueOf(Object) | no manual model |
| java.lang.Throwable#printStackTrace() | no manual model |
+| java.util.stream.Collectors#joining(CharSequence) | no manual model |
| java.util.stream.Stream#collect(Collector) | no manual model |
From 99ee6c95a1f4b6af127cb173ab28cffe9d7251ae Mon Sep 17 00:00:00 2001
From: Jami Cogswell
Date: Wed, 11 Jan 2023 10:44:38 -0500
Subject: [PATCH 192/381] Java: remove models for Consumer.accept and
Collectors.toMap
---
java/ql/lib/ext/java.util.function.model.yml | 6 ------
java/ql/lib/ext/java.util.stream.model.yml | 1 -
java/ql/test/ext/TopJdkApis/TopJdkApis.qll | 8 +++++---
java/ql/test/ext/TopJdkApis/TopJdkApisTest.expected | 2 ++
4 files changed, 7 insertions(+), 10 deletions(-)
diff --git a/java/ql/lib/ext/java.util.function.model.yml b/java/ql/lib/ext/java.util.function.model.yml
index 44c01b611d2..9ee54700752 100644
--- a/java/ql/lib/ext/java.util.function.model.yml
+++ b/java/ql/lib/ext/java.util.function.model.yml
@@ -11,9 +11,3 @@ extensions:
data:
- ["java.util.function", "Function", True, "apply", "(Object)", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["java.util.function", "Supplier", False, "get", "()", "", "Argument[-1]", "ReturnValue", "value", "manual"]
-
- - addsTo:
- pack: codeql/java-all
- extensible: neutralModel
- data:
- - ["java.util.function", "Consumer", "accept", "(Object)", "manual"]
diff --git a/java/ql/lib/ext/java.util.stream.model.yml b/java/ql/lib/ext/java.util.stream.model.yml
index 190cc2709b4..b44c3391075 100644
--- a/java/ql/lib/ext/java.util.stream.model.yml
+++ b/java/ql/lib/ext/java.util.stream.model.yml
@@ -93,5 +93,4 @@ extensions:
extensible: neutralModel
data:
- ["java.util.stream", "Collectors", "toList", "()", "manual"]
- - ["java.util.stream", "Collectors", "toMap", "(Function,Function)", "manual"]
- ["java.util.stream", "Collectors", "toSet", "()", "manual"]
diff --git a/java/ql/test/ext/TopJdkApis/TopJdkApis.qll b/java/ql/test/ext/TopJdkApis/TopJdkApis.qll
index 858659634f5..b00cfb4cad7 100644
--- a/java/ql/test/ext/TopJdkApis/TopJdkApis.qll
+++ b/java/ql/test/ext/TopJdkApis/TopJdkApis.qll
@@ -143,10 +143,12 @@ class TopJdkApi extends SummarizedCallableBase {
predicate hasManualMadModel() { this.hasManualSummary() or this.hasManualNeutral() }
/*
* Note: the following top-100 APIs are not modeled with MaD:
- * `java.util.stream.Stream#collect(Collector)`: handled separately on a case-by-case basis as it is too complex for MaD
- * `java.util.stream.Collectors#joining(CharSequence)`: cannot be modeled completely without a model for `java.util.stream.Stream#collect(Collector)` as well
- * `java.lang.String#valueOf(Object)`: also a complex case; an alias for `Object.toString`, except the dispatch is hidden
+ * `java.lang.String#valueOf(Object)`: a complex case; an alias for `Object.toString`, except the dispatch is hidden
* `java.lang.Throwable#printStackTrace()`: should probably not be a general step, but there might be specialised queries that care
+ * `java.util.function.Consumer#accept(Object)`: specialized lambda flow
+ * `java.util.stream.Collectors#joining(CharSequence)`: cannot be modeled completely without a model for `java.util.stream.Stream#collect(Collector)` as well
+ * `java.util.stream.Collectors#toMap(Function,Function)`: specialized collectors flow
+ * `java.util.stream.Stream#collect(Collector)`: handled separately on a case-by-case basis as it is too complex for MaD
*/
}
diff --git a/java/ql/test/ext/TopJdkApis/TopJdkApisTest.expected b/java/ql/test/ext/TopJdkApis/TopJdkApisTest.expected
index abe2044906d..2023810b44d 100644
--- a/java/ql/test/ext/TopJdkApis/TopJdkApisTest.expected
+++ b/java/ql/test/ext/TopJdkApis/TopJdkApisTest.expected
@@ -1,4 +1,6 @@
| java.lang.String#valueOf(Object) | no manual model |
| java.lang.Throwable#printStackTrace() | no manual model |
+| java.util.function.Consumer#accept(Object) | no manual model |
| java.util.stream.Collectors#joining(CharSequence) | no manual model |
+| java.util.stream.Collectors#toMap(Function,Function) | no manual model |
| java.util.stream.Stream#collect(Collector) | no manual model |
From 2a99af0e6da80a307875489ab1cc646fdc881e46 Mon Sep 17 00:00:00 2001
From: Jami Cogswell
Date: Wed, 11 Jan 2023 10:58:46 -0500
Subject: [PATCH 193/381] Java: remove summary model for String.endsWith
---
java/ql/lib/ext/java.lang.model.yml | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/java/ql/lib/ext/java.lang.model.yml b/java/ql/lib/ext/java.lang.model.yml
index 259c5bcaf06..26e3c50ac9e 100644
--- a/java/ql/lib/ext/java.lang.model.yml
+++ b/java/ql/lib/ext/java.lang.model.yml
@@ -63,7 +63,6 @@ extensions:
- ["java.lang", "String", False, "concat", "(String)", "", "Argument[-1]", "ReturnValue", "taint", "manual"]
- ["java.lang", "String", False, "concat", "(String)", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["java.lang", "String", False, "copyValueOf", "", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- - ["java.lang", "String", False, "endsWith", "", "", "Argument[-1]", "ReturnValue", "taint", "manual"] # ! why is this a summary model and not a neutral model instead? it returns a boolean
- ["java.lang", "String", False, "format", "(Locale,String,Object[])", "", "Argument[1]", "ReturnValue", "taint", "manual"]
- ["java.lang", "String", False, "format", "(Locale,String,Object[])", "", "Argument[2].ArrayElement", "ReturnValue", "taint", "manual"]
- ["java.lang", "String", False, "format", "(String,Object[])", "", "Argument[0]", "ReturnValue", "taint", "manual"]
@@ -129,7 +128,7 @@ extensions:
- ["java.lang", "Object", "hashCode", "()", "manual"]
- ["java.lang", "Object", "toString", "()", "manual"]
- ["java.lang", "String", "contains", "(CharSequence)", "manual"]
- - ["java.lang", "String", "endsWith", "(String)", "manual"] # ! see question on line 65 above
+ - ["java.lang", "String", "endsWith", "(String)", "manual"]
- ["java.lang", "String", "equals", "(Object)", "manual"]
- ["java.lang", "String", "equalsIgnoreCase", "(String)", "manual"]
- ["java.lang", "String", "hashCode", "()", "manual"]
From 0c7ffb055471c116ed26e0e244b3b517aa61d4ce Mon Sep 17 00:00:00 2001
From: Jami Cogswell
Date: Wed, 11 Jan 2023 12:04:22 -0500
Subject: [PATCH 194/381] Java: update System.getProperty model
---
java/ql/lib/ext/java.lang.model.yml | 5 ++++-
java/ql/test/ext/TestModels/Test.java | 3 +++
2 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/java/ql/lib/ext/java.lang.model.yml b/java/ql/lib/ext/java.lang.model.yml
index 26e3c50ac9e..ae383705be1 100644
--- a/java/ql/lib/ext/java.lang.model.yml
+++ b/java/ql/lib/ext/java.lang.model.yml
@@ -103,7 +103,10 @@ extensions:
- ["java.lang", "StringBuffer", True, "StringBuffer", "(String)", "", "Argument[0]", "Argument[-1]", "taint", "manual"]
- ["java.lang", "StringBuilder", True, "StringBuilder", "", "", "Argument[0]", "Argument[-1]", "taint", "manual"]
- ["java.lang", "System", False, "arraycopy", "", "", "Argument[0]", "Argument[2]", "taint", "manual"]
- - ["java.lang", "System", False, "getProperty", "(String)", "", "Argument[-1].MapValue", "ReturnValue", "value", "manual"]
+ - ["java.lang", "System", False, "getProperty", "(String)", "", "SyntheticGlobal[java.lang.System.properties].MapValue", "ReturnValue", "value", "manual"]
+ - ["java.lang", "System", False, "setProperty", "(String,String)", "", "SyntheticGlobal[java.lang.System.properties].MapValue", "ReturnValue", "value", "manual"]
+ - ["java.lang", "System", False, "setProperty", "(String,String)", "", "Argument[0]", "SyntheticGlobal[java.lang.System.properties].MapKey", "value", "manual"]
+ - ["java.lang", "System", False, "setProperty", "(String,String)", "", "Argument[1]", "SyntheticGlobal[java.lang.System.properties].MapValue", "value", "manual"]
- ["java.lang", "Throwable", False, "Throwable", "(Throwable)", "", "Argument[0]", "Argument[-1].SyntheticField[java.lang.Throwable.cause]", "value", "manual"]
- ["java.lang", "Throwable", True, "getCause", "()", "", "Argument[-1].SyntheticField[java.lang.Throwable.cause]", "ReturnValue", "value", "manual"]
- ["java.lang", "Throwable", True, "getMessage", "()", "", "Argument[-1].SyntheticField[java.lang.Throwable.message]", "ReturnValue", "value", "manual"]
diff --git a/java/ql/test/ext/TestModels/Test.java b/java/ql/test/ext/TestModels/Test.java
index 3afd2c80897..55c531d99bf 100644
--- a/java/ql/test/ext/TestModels/Test.java
+++ b/java/ql/test/ext/TestModels/Test.java
@@ -97,6 +97,9 @@ public class Test {
long l3 = (long)source();
sink(String.valueOf(l3)); // $hasTaintFlow
+ System.setProperty("testKey", (String)source());
+ sink(System.getProperty("testKey")); // $hasValueFlow
+
// java.math
long l4 = (long)source();
sink(BigDecimal.valueOf(l4)); // $hasTaintFlow
From 82f9903bf0aaeec07b09af2029ad620387b55cc6 Mon Sep 17 00:00:00 2001
From: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
Date: Mon, 9 Jan 2023 14:37:24 +0000
Subject: [PATCH 195/381] Swift: Additional test cases for
swift/cleartext-storage-database on Core Data.
---
.../Security/CWE-311/SensitiveExprs.expected | 28 ++++++++
.../Security/CWE-311/testCoreData2.swift | 67 +++++++++++++++++++
2 files changed, 95 insertions(+)
create mode 100644 swift/ql/test/query-tests/Security/CWE-311/testCoreData2.swift
diff --git a/swift/ql/test/query-tests/Security/CWE-311/SensitiveExprs.expected b/swift/ql/test/query-tests/Security/CWE-311/SensitiveExprs.expected
index 3c61ec86e95..89f9b9ac32a 100644
--- a/swift/ql/test/query-tests/Security/CWE-311/SensitiveExprs.expected
+++ b/swift/ql/test/query-tests/Security/CWE-311/SensitiveExprs.expected
@@ -8,6 +8,34 @@
| testAlamofire.swift:195:64:195:64 | password | label:password, type:credential |
| testAlamofire.swift:205:62:205:62 | password | label:password, type:credential |
| testAlamofire.swift:213:65:213:65 | password | label:password, type:credential |
+| testCoreData2.swift:37:16:37:16 | bankAccountNo | label:bankAccountNo, type:private information |
+| testCoreData2.swift:38:2:38:6 | .myBankAccountNumber | label:myBankAccountNumber, type:private information |
+| testCoreData2.swift:39:2:39:6 | .myBankAccountNumber | label:myBankAccountNumber, type:private information |
+| testCoreData2.swift:39:28:39:28 | bankAccountNo | label:bankAccountNo, type:private information |
+| testCoreData2.swift:40:2:40:6 | .myBankAccountNumber2 | label:myBankAccountNumber2, type:private information |
+| testCoreData2.swift:41:2:41:6 | .myBankAccountNumber2 | label:myBankAccountNumber2, type:private information |
+| testCoreData2.swift:41:29:41:29 | bankAccountNo | label:bankAccountNo, type:private information |
+| testCoreData2.swift:42:2:42:6 | .notStoredBankAccountNumber | label:notStoredBankAccountNumber, type:private information |
+| testCoreData2.swift:43:2:43:6 | .notStoredBankAccountNumber | label:notStoredBankAccountNumber, type:private information |
+| testCoreData2.swift:43:35:43:35 | bankAccountNo | label:bankAccountNo, type:private information |
+| testCoreData2.swift:46:22:46:22 | bankAccountNo | label:bankAccountNo, type:private information |
+| testCoreData2.swift:47:2:47:12 | .myBankAccountNumber | label:myBankAccountNumber, type:private information |
+| testCoreData2.swift:48:2:48:12 | .myBankAccountNumber | label:myBankAccountNumber, type:private information |
+| testCoreData2.swift:48:34:48:34 | bankAccountNo | label:bankAccountNo, type:private information |
+| testCoreData2.swift:49:2:49:12 | .myBankAccountNumber2 | label:myBankAccountNumber2, type:private information |
+| testCoreData2.swift:50:2:50:12 | .myBankAccountNumber2 | label:myBankAccountNumber2, type:private information |
+| testCoreData2.swift:50:35:50:35 | bankAccountNo | label:bankAccountNo, type:private information |
+| testCoreData2.swift:51:2:51:12 | .notStoredBankAccountNumber | label:notStoredBankAccountNumber, type:private information |
+| testCoreData2.swift:52:2:52:12 | .notStoredBankAccountNumber | label:notStoredBankAccountNumber, type:private information |
+| testCoreData2.swift:52:41:52:41 | bankAccountNo | label:bankAccountNo, type:private information |
+| testCoreData2.swift:57:3:57:7 | .myBankAccountNumber | label:myBankAccountNumber, type:private information |
+| testCoreData2.swift:57:29:57:29 | bankAccountNo | label:bankAccountNo, type:private information |
+| testCoreData2.swift:60:4:60:8 | .myBankAccountNumber | label:myBankAccountNumber, type:private information |
+| testCoreData2.swift:60:30:60:30 | bankAccountNo | label:bankAccountNo, type:private information |
+| testCoreData2.swift:62:4:62:8 | .myBankAccountNumber | label:myBankAccountNumber, type:private information |
+| testCoreData2.swift:62:30:62:30 | bankAccountNo | label:bankAccountNo, type:private information |
+| testCoreData2.swift:65:3:65:7 | .myBankAccountNumber | label:myBankAccountNumber, type:private information |
+| testCoreData2.swift:65:29:65:29 | bankAccountNo | label:bankAccountNo, type:private information |
| testCoreData.swift:48:15:48:15 | password | label:password, type:credential |
| testCoreData.swift:51:24:51:24 | password | label:password, type:credential |
| testCoreData.swift:58:15:58:15 | password | label:password, type:credential |
diff --git a/swift/ql/test/query-tests/Security/CWE-311/testCoreData2.swift b/swift/ql/test/query-tests/Security/CWE-311/testCoreData2.swift
new file mode 100644
index 00000000000..3a79e82b7eb
--- /dev/null
+++ b/swift/ql/test/query-tests/Security/CWE-311/testCoreData2.swift
@@ -0,0 +1,67 @@
+
+// --- stubs ---
+
+class NSObject
+{
+}
+
+@propertyWrapper
+struct NSManaged { // note: this may not be an accurate stub for `NSManaged`.
+ var wrappedValue: Any {
+ didSet {}
+ }
+}
+
+class NSManagedObject : NSObject
+{
+}
+
+class MyManagedObject2 : NSManagedObject
+{
+ @NSManaged public var myValue: Int
+ @NSManaged public var myBankAccountNumber : Int
+ public var notStoredBankAccountNumber: Int = 0
+}
+
+extension MyManagedObject2
+{
+ @NSManaged public var myBankAccountNumber2 : Int
+}
+
+// --- tests ---
+
+func testCoreData2_1(obj: MyManagedObject2, maybeObj: MyManagedObject2?, value: Int, bankAccountNo: Int)
+{
+ // @NSManaged fields of an NSManagedObject...
+ obj.myValue = value // GOOD (not sensitive)
+ obj.myValue = bankAccountNo // BAD [NOT DETECTED]
+ obj.myBankAccountNumber = value // BAD [NOT DETECTED]
+ obj.myBankAccountNumber = bankAccountNo // BAD [NOT DETECTED]
+ obj.myBankAccountNumber2 = value // BAD [NOT DETECTED]
+ obj.myBankAccountNumber2 = bankAccountNo // BAD [NOT DETECTED]
+ obj.notStoredBankAccountNumber = value // GOOD (not stored in the database)
+ obj.notStoredBankAccountNumber = bankAccountNo // GOOD (not stored in the datbase)
+
+ maybeObj?.myValue = value // GOOD (not sensitive)
+ maybeObj?.myValue = bankAccountNo // BAD [NOT DETECTED]
+ maybeObj?.myBankAccountNumber = value // BAD [NOT DETECTED]
+ maybeObj?.myBankAccountNumber = bankAccountNo // BAD [NOT DETECTED]
+ maybeObj?.myBankAccountNumber2 = value // BAD [NOT DETECTED]
+ maybeObj?.myBankAccountNumber2 = bankAccountNo // BAD [NOT DETECTED]
+ maybeObj?.notStoredBankAccountNumber = value // GOOD (not stored in the database)
+ maybeObj?.notStoredBankAccountNumber = bankAccountNo // GOOD (not stored in the datbase)
+}
+
+class testCoreData2_2 {
+ func myFunc(obj: MyManagedObject2, bankAccountNo: Int) {
+ obj.myBankAccountNumber = bankAccountNo // BAD [NOT DETECTED]
+
+ if #available(iOS 10.0, *) {
+ obj.myBankAccountNumber = bankAccountNo // BAD [NOT DETECTED]
+ } else {
+ obj.myBankAccountNumber = bankAccountNo // BAD [NOT DETECTED]
+ }
+
+ obj.myBankAccountNumber = bankAccountNo // BAD [NOT DETECTED]
+ }
+}
From 2622de97471382763ad8af384fe9893ed3b6212f Mon Sep 17 00:00:00 2001
From: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
Date: Tue, 10 Jan 2023 13:45:54 +0000
Subject: [PATCH 196/381] Swift: Improve Core Data coverage.
---
.../CWE-311/CleartextStorageDatabase.ql | 18 ++++--
.../CWE-311/CleartextStorageDatabase.expected | 56 +++++++++++++++++++
.../Security/CWE-311/testCoreData.swift | 4 +-
.../Security/CWE-311/testCoreData2.swift | 14 ++---
4 files changed, 79 insertions(+), 13 deletions(-)
diff --git a/swift/ql/src/queries/Security/CWE-311/CleartextStorageDatabase.ql b/swift/ql/src/queries/Security/CWE-311/CleartextStorageDatabase.ql
index e858e6dd357..b34f1b0c6cf 100644
--- a/swift/ql/src/queries/Security/CWE-311/CleartextStorageDatabase.ql
+++ b/swift/ql/src/queries/Security/CWE-311/CleartextStorageDatabase.ql
@@ -27,13 +27,23 @@ abstract class Stored extends DataFlow::Node { }
*/
class CoreDataStore extends Stored {
CoreDataStore() {
- // values written into Core Data objects are a sink
+ // values written into Core Data objects through `set*Value` methods are a sink.
exists(CallExpr call |
call.getStaticTarget()
.(MethodDecl)
.hasQualifiedName("NSManagedObject",
["setValue(_:forKey:)", "setPrimitiveValue(_:forKey:)"]) and
call.getArgument(0).getExpr() = this.asExpr()
+ ) or
+ // any write into a class derived from `NSManagedObject` is a sink. For
+ // example in `coreDataObj.data = sensitive` the post-update node corresponding
+ // with `coreDataObj.data` is a sink.
+ // (ideally this would be only members with the `@NSManaged` attribute)
+ exists(ClassOrStructDecl cd, Expr e |
+ cd.getABaseTypeDecl*().getName() = "NSManagedObject" and
+ this.(DataFlow::PostUpdateNode).getPreUpdateNode().asExpr() = e and
+ e.getFullyConverted().getType() = cd.getType() and
+ not e.(DeclRefExpr).getDecl() instanceof SelfParamDecl
)
}
}
@@ -78,12 +88,12 @@ class CleartextStorageConfig extends TaintTracking::Configuration {
}
override predicate allowImplicitRead(DataFlow::Node node, DataFlow::ContentSet c) {
- // flow out from fields of a `RealmSwiftObject` at the sink, for example in
- // `realmObj.data = sensitive`.
+ // flow out from fields of an `NSManagedObject` or `RealmSwiftObject` at the sink,
+ // for example in `realmObj.data = sensitive`.
isSink(node) and
exists(ClassOrStructDecl cd |
c.getAReadContent().(DataFlow::Content::FieldContent).getField() = cd.getAMember() and
- cd.getABaseTypeDecl*().getName() = "RealmSwiftObject"
+ cd.getABaseTypeDecl*().getName() = ["NSManagedObject", "RealmSwiftObject"]
)
or
// any default implicit reads
diff --git a/swift/ql/test/query-tests/Security/CWE-311/CleartextStorageDatabase.expected b/swift/ql/test/query-tests/Security/CWE-311/CleartextStorageDatabase.expected
index fa0af25eec9..d5b33a22ba1 100644
--- a/swift/ql/test/query-tests/Security/CWE-311/CleartextStorageDatabase.expected
+++ b/swift/ql/test/query-tests/Security/CWE-311/CleartextStorageDatabase.expected
@@ -1,9 +1,29 @@
edges
| file://:0:0:0:0 | value : | file://:0:0:0:0 | [post] self [data] : |
+| file://:0:0:0:0 | value : | file://:0:0:0:0 | [post] self [notStoredBankAccountNumber] : |
+| testCoreData2.swift:23:13:23:13 | value : | file://:0:0:0:0 | value : |
+| testCoreData2.swift:37:2:37:2 | [post] obj [myValue] : | testCoreData2.swift:37:2:37:2 | [post] obj |
+| testCoreData2.swift:37:16:37:16 | bankAccountNo : | testCoreData2.swift:37:2:37:2 | [post] obj [myValue] : |
+| testCoreData2.swift:39:2:39:2 | [post] obj [myBankAccountNumber] : | testCoreData2.swift:39:2:39:2 | [post] obj |
+| testCoreData2.swift:39:28:39:28 | bankAccountNo : | testCoreData2.swift:39:2:39:2 | [post] obj [myBankAccountNumber] : |
+| testCoreData2.swift:43:2:43:2 | [post] obj [notStoredBankAccountNumber] : | testCoreData2.swift:43:2:43:2 | [post] obj |
+| testCoreData2.swift:43:35:43:35 | bankAccountNo : | testCoreData2.swift:23:13:23:13 | value : |
+| testCoreData2.swift:43:35:43:35 | bankAccountNo : | testCoreData2.swift:43:2:43:2 | [post] obj [notStoredBankAccountNumber] : |
+| testCoreData2.swift:46:2:46:10 | [post] ...? [myValue] : | testCoreData2.swift:46:2:46:10 | [post] ...? |
+| testCoreData2.swift:46:22:46:22 | bankAccountNo : | testCoreData2.swift:46:2:46:10 | [post] ...? [myValue] : |
+| testCoreData2.swift:48:2:48:10 | [post] ...? [myBankAccountNumber] : | testCoreData2.swift:48:2:48:10 | [post] ...? |
+| testCoreData2.swift:48:34:48:34 | bankAccountNo : | testCoreData2.swift:48:2:48:10 | [post] ...? [myBankAccountNumber] : |
+| testCoreData2.swift:52:2:52:10 | [post] ...? [notStoredBankAccountNumber] : | testCoreData2.swift:52:2:52:10 | [post] ...? |
+| testCoreData2.swift:52:41:52:41 | bankAccountNo : | testCoreData2.swift:23:13:23:13 | value : |
+| testCoreData2.swift:52:41:52:41 | bankAccountNo : | testCoreData2.swift:52:2:52:10 | [post] ...? [notStoredBankAccountNumber] : |
+| testCoreData2.swift:57:3:57:3 | [post] obj [myBankAccountNumber] : | testCoreData2.swift:57:3:57:3 | [post] obj |
+| testCoreData2.swift:57:29:57:29 | bankAccountNo : | testCoreData2.swift:57:3:57:3 | [post] obj [myBankAccountNumber] : |
| testCoreData.swift:18:19:18:26 | value : | testCoreData.swift:19:12:19:12 | value |
| testCoreData.swift:31:3:31:3 | newValue : | testCoreData.swift:32:13:32:13 | newValue |
| testCoreData.swift:61:25:61:25 | password : | testCoreData.swift:18:19:18:26 | value : |
+| testCoreData.swift:64:2:64:2 | [post] obj [myValue] : | testCoreData.swift:64:2:64:2 | [post] obj |
| testCoreData.swift:64:16:64:16 | password : | testCoreData.swift:31:3:31:3 | newValue : |
+| testCoreData.swift:64:16:64:16 | password : | testCoreData.swift:64:2:64:2 | [post] obj [myValue] : |
| testCoreData.swift:77:24:77:24 | x : | testCoreData.swift:78:15:78:15 | x |
| testCoreData.swift:80:10:80:22 | call to getPassword() : | testCoreData.swift:81:15:81:15 | y |
| testCoreData.swift:91:10:91:10 | passwd : | testCoreData.swift:95:15:95:15 | x |
@@ -24,7 +44,31 @@ edges
| testRealm.swift:59:11:59:11 | myPassword : | testRealm.swift:59:2:59:2 | [post] g [data] : |
nodes
| file://:0:0:0:0 | [post] self [data] : | semmle.label | [post] self [data] : |
+| file://:0:0:0:0 | [post] self [notStoredBankAccountNumber] : | semmle.label | [post] self [notStoredBankAccountNumber] : |
| file://:0:0:0:0 | value : | semmle.label | value : |
+| file://:0:0:0:0 | value : | semmle.label | value : |
+| testCoreData2.swift:23:13:23:13 | value : | semmle.label | value : |
+| testCoreData2.swift:37:2:37:2 | [post] obj | semmle.label | [post] obj |
+| testCoreData2.swift:37:2:37:2 | [post] obj [myValue] : | semmle.label | [post] obj [myValue] : |
+| testCoreData2.swift:37:16:37:16 | bankAccountNo : | semmle.label | bankAccountNo : |
+| testCoreData2.swift:39:2:39:2 | [post] obj | semmle.label | [post] obj |
+| testCoreData2.swift:39:2:39:2 | [post] obj [myBankAccountNumber] : | semmle.label | [post] obj [myBankAccountNumber] : |
+| testCoreData2.swift:39:28:39:28 | bankAccountNo : | semmle.label | bankAccountNo : |
+| testCoreData2.swift:43:2:43:2 | [post] obj | semmle.label | [post] obj |
+| testCoreData2.swift:43:2:43:2 | [post] obj [notStoredBankAccountNumber] : | semmle.label | [post] obj [notStoredBankAccountNumber] : |
+| testCoreData2.swift:43:35:43:35 | bankAccountNo : | semmle.label | bankAccountNo : |
+| testCoreData2.swift:46:2:46:10 | [post] ...? | semmle.label | [post] ...? |
+| testCoreData2.swift:46:2:46:10 | [post] ...? [myValue] : | semmle.label | [post] ...? [myValue] : |
+| testCoreData2.swift:46:22:46:22 | bankAccountNo : | semmle.label | bankAccountNo : |
+| testCoreData2.swift:48:2:48:10 | [post] ...? | semmle.label | [post] ...? |
+| testCoreData2.swift:48:2:48:10 | [post] ...? [myBankAccountNumber] : | semmle.label | [post] ...? [myBankAccountNumber] : |
+| testCoreData2.swift:48:34:48:34 | bankAccountNo : | semmle.label | bankAccountNo : |
+| testCoreData2.swift:52:2:52:10 | [post] ...? | semmle.label | [post] ...? |
+| testCoreData2.swift:52:2:52:10 | [post] ...? [notStoredBankAccountNumber] : | semmle.label | [post] ...? [notStoredBankAccountNumber] : |
+| testCoreData2.swift:52:41:52:41 | bankAccountNo : | semmle.label | bankAccountNo : |
+| testCoreData2.swift:57:3:57:3 | [post] obj | semmle.label | [post] obj |
+| testCoreData2.swift:57:3:57:3 | [post] obj [myBankAccountNumber] : | semmle.label | [post] obj [myBankAccountNumber] : |
+| testCoreData2.swift:57:29:57:29 | bankAccountNo : | semmle.label | bankAccountNo : |
| testCoreData.swift:18:19:18:26 | value : | semmle.label | value : |
| testCoreData.swift:19:12:19:12 | value | semmle.label | value |
| testCoreData.swift:31:3:31:3 | newValue : | semmle.label | newValue : |
@@ -33,6 +77,8 @@ nodes
| testCoreData.swift:51:24:51:24 | password | semmle.label | password |
| testCoreData.swift:58:15:58:15 | password | semmle.label | password |
| testCoreData.swift:61:25:61:25 | password : | semmle.label | password : |
+| testCoreData.swift:64:2:64:2 | [post] obj | semmle.label | [post] obj |
+| testCoreData.swift:64:2:64:2 | [post] obj [myValue] : | semmle.label | [post] obj [myValue] : |
| testCoreData.swift:64:16:64:16 | password : | semmle.label | password : |
| testCoreData.swift:77:24:77:24 | x : | semmle.label | x : |
| testCoreData.swift:78:15:78:15 | x | semmle.label | x |
@@ -59,16 +105,26 @@ nodes
| testRealm.swift:59:2:59:2 | [post] g [data] : | semmle.label | [post] g [data] : |
| testRealm.swift:59:11:59:11 | myPassword : | semmle.label | myPassword : |
subpaths
+| testCoreData2.swift:43:35:43:35 | bankAccountNo : | testCoreData2.swift:23:13:23:13 | value : | file://:0:0:0:0 | [post] self [notStoredBankAccountNumber] : | testCoreData2.swift:43:2:43:2 | [post] obj [notStoredBankAccountNumber] : |
+| testCoreData2.swift:52:41:52:41 | bankAccountNo : | testCoreData2.swift:23:13:23:13 | value : | file://:0:0:0:0 | [post] self [notStoredBankAccountNumber] : | testCoreData2.swift:52:2:52:10 | [post] ...? [notStoredBankAccountNumber] : |
| testRealm.swift:34:11:34:11 | myPassword : | testRealm.swift:16:6:16:6 | value : | file://:0:0:0:0 | [post] self [data] : | testRealm.swift:34:2:34:2 | [post] a [data] : |
| testRealm.swift:42:11:42:11 | myPassword : | testRealm.swift:16:6:16:6 | value : | file://:0:0:0:0 | [post] self [data] : | testRealm.swift:42:2:42:2 | [post] c [data] : |
| testRealm.swift:52:12:52:12 | myPassword : | testRealm.swift:16:6:16:6 | value : | file://:0:0:0:0 | [post] self [data] : | testRealm.swift:52:2:52:3 | [post] ...! [data] : |
| testRealm.swift:59:11:59:11 | myPassword : | testRealm.swift:16:6:16:6 | value : | file://:0:0:0:0 | [post] self [data] : | testRealm.swift:59:2:59:2 | [post] g [data] : |
#select
+| testCoreData2.swift:37:2:37:2 | obj | testCoreData2.swift:37:16:37:16 | bankAccountNo : | testCoreData2.swift:37:2:37:2 | [post] obj | This operation stores '[post] obj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:37:16:37:16 | bankAccountNo : | bankAccountNo |
+| testCoreData2.swift:39:2:39:2 | obj | testCoreData2.swift:39:28:39:28 | bankAccountNo : | testCoreData2.swift:39:2:39:2 | [post] obj | This operation stores '[post] obj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:39:28:39:28 | bankAccountNo : | bankAccountNo |
+| testCoreData2.swift:43:2:43:2 | obj | testCoreData2.swift:43:35:43:35 | bankAccountNo : | testCoreData2.swift:43:2:43:2 | [post] obj | This operation stores '[post] obj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:43:35:43:35 | bankAccountNo : | bankAccountNo |
+| testCoreData2.swift:46:2:46:10 | ...? | testCoreData2.swift:46:22:46:22 | bankAccountNo : | testCoreData2.swift:46:2:46:10 | [post] ...? | This operation stores '[post] ...?' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:46:22:46:22 | bankAccountNo : | bankAccountNo |
+| testCoreData2.swift:48:2:48:10 | ...? | testCoreData2.swift:48:34:48:34 | bankAccountNo : | testCoreData2.swift:48:2:48:10 | [post] ...? | This operation stores '[post] ...?' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:48:34:48:34 | bankAccountNo : | bankAccountNo |
+| testCoreData2.swift:52:2:52:10 | ...? | testCoreData2.swift:52:41:52:41 | bankAccountNo : | testCoreData2.swift:52:2:52:10 | [post] ...? | This operation stores '[post] ...?' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:52:41:52:41 | bankAccountNo : | bankAccountNo |
+| testCoreData2.swift:57:3:57:3 | obj | testCoreData2.swift:57:29:57:29 | bankAccountNo : | testCoreData2.swift:57:3:57:3 | [post] obj | This operation stores '[post] obj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:57:29:57:29 | bankAccountNo : | bankAccountNo |
| testCoreData.swift:19:12:19:12 | value | testCoreData.swift:61:25:61:25 | password : | testCoreData.swift:19:12:19:12 | value | This operation stores 'value' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:61:25:61:25 | password : | password |
| testCoreData.swift:32:13:32:13 | newValue | testCoreData.swift:64:16:64:16 | password : | testCoreData.swift:32:13:32:13 | newValue | This operation stores 'newValue' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:64:16:64:16 | password : | password |
| testCoreData.swift:48:15:48:15 | password | testCoreData.swift:48:15:48:15 | password | testCoreData.swift:48:15:48:15 | password | This operation stores 'password' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:48:15:48:15 | password | password |
| testCoreData.swift:51:24:51:24 | password | testCoreData.swift:51:24:51:24 | password | testCoreData.swift:51:24:51:24 | password | This operation stores 'password' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:51:24:51:24 | password | password |
| testCoreData.swift:58:15:58:15 | password | testCoreData.swift:58:15:58:15 | password | testCoreData.swift:58:15:58:15 | password | This operation stores 'password' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:58:15:58:15 | password | password |
+| testCoreData.swift:64:2:64:2 | obj | testCoreData.swift:64:16:64:16 | password : | testCoreData.swift:64:2:64:2 | [post] obj | This operation stores '[post] obj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:64:16:64:16 | password : | password |
| testCoreData.swift:78:15:78:15 | x | testCoreData.swift:77:24:77:24 | x : | testCoreData.swift:78:15:78:15 | x | This operation stores 'x' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:77:24:77:24 | x : | x |
| testCoreData.swift:81:15:81:15 | y | testCoreData.swift:80:10:80:22 | call to getPassword() : | testCoreData.swift:81:15:81:15 | y | This operation stores 'y' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:80:10:80:22 | call to getPassword() : | call to getPassword() |
| testCoreData.swift:85:15:85:17 | .password | testCoreData.swift:85:15:85:17 | .password | testCoreData.swift:85:15:85:17 | .password | This operation stores '.password' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:85:15:85:17 | .password | .password |
diff --git a/swift/ql/test/query-tests/Security/CWE-311/testCoreData.swift b/swift/ql/test/query-tests/Security/CWE-311/testCoreData.swift
index 60ee3147018..dbd02398aae 100644
--- a/swift/ql/test/query-tests/Security/CWE-311/testCoreData.swift
+++ b/swift/ql/test/query-tests/Security/CWE-311/testCoreData.swift
@@ -29,7 +29,7 @@ class MyManagedObject : NSManagedObject
}
}
set {
- setValue(newValue, forKey: "myKey")
+ setValue(newValue, forKey: "myKey") // [additional result reported here]
}
}
}
@@ -61,7 +61,7 @@ func test2(obj : MyManagedObject, password : String, password_file : String) {
obj.setIndirect(value: password) // BAD [reported on line 19]
obj.setIndirect(value: password_file) // GOOD (not sensitive)
- obj.myValue = password // BAD [reported on line 32]
+ obj.myValue = password // BAD [also reported on line 32]
obj.myValue = password_file // GOOD (not sensitive)
}
diff --git a/swift/ql/test/query-tests/Security/CWE-311/testCoreData2.swift b/swift/ql/test/query-tests/Security/CWE-311/testCoreData2.swift
index 3a79e82b7eb..6cf2afb8094 100644
--- a/swift/ql/test/query-tests/Security/CWE-311/testCoreData2.swift
+++ b/swift/ql/test/query-tests/Security/CWE-311/testCoreData2.swift
@@ -34,27 +34,27 @@ func testCoreData2_1(obj: MyManagedObject2, maybeObj: MyManagedObject2?, value:
{
// @NSManaged fields of an NSManagedObject...
obj.myValue = value // GOOD (not sensitive)
- obj.myValue = bankAccountNo // BAD [NOT DETECTED]
+ obj.myValue = bankAccountNo // BAD
obj.myBankAccountNumber = value // BAD [NOT DETECTED]
- obj.myBankAccountNumber = bankAccountNo // BAD [NOT DETECTED]
+ obj.myBankAccountNumber = bankAccountNo // BAD
obj.myBankAccountNumber2 = value // BAD [NOT DETECTED]
obj.myBankAccountNumber2 = bankAccountNo // BAD [NOT DETECTED]
obj.notStoredBankAccountNumber = value // GOOD (not stored in the database)
- obj.notStoredBankAccountNumber = bankAccountNo // GOOD (not stored in the datbase)
+ obj.notStoredBankAccountNumber = bankAccountNo // GOOD (not stored in the datbase) [FALSE POSITIVE]
maybeObj?.myValue = value // GOOD (not sensitive)
- maybeObj?.myValue = bankAccountNo // BAD [NOT DETECTED]
+ maybeObj?.myValue = bankAccountNo // BAD
maybeObj?.myBankAccountNumber = value // BAD [NOT DETECTED]
- maybeObj?.myBankAccountNumber = bankAccountNo // BAD [NOT DETECTED]
+ maybeObj?.myBankAccountNumber = bankAccountNo // BAD
maybeObj?.myBankAccountNumber2 = value // BAD [NOT DETECTED]
maybeObj?.myBankAccountNumber2 = bankAccountNo // BAD [NOT DETECTED]
maybeObj?.notStoredBankAccountNumber = value // GOOD (not stored in the database)
- maybeObj?.notStoredBankAccountNumber = bankAccountNo // GOOD (not stored in the datbase)
+ maybeObj?.notStoredBankAccountNumber = bankAccountNo // GOOD (not stored in the datbase) [FALSE POSITIVE]
}
class testCoreData2_2 {
func myFunc(obj: MyManagedObject2, bankAccountNo: Int) {
- obj.myBankAccountNumber = bankAccountNo // BAD [NOT DETECTED]
+ obj.myBankAccountNumber = bankAccountNo // BAD
if #available(iOS 10.0, *) {
obj.myBankAccountNumber = bankAccountNo // BAD [NOT DETECTED]
From 6a0b56bf408b81b99ed571b95efa77778fd22a6a Mon Sep 17 00:00:00 2001
From: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
Date: Tue, 10 Jan 2023 18:21:09 +0000
Subject: [PATCH 197/381] Swift: Fix for extensions.
---
.../Security/CWE-311/CleartextStorageDatabase.ql | 9 ++++++---
.../CWE-311/CleartextStorageDatabase.expected | 12 ++++++++++++
.../query-tests/Security/CWE-311/testCoreData2.swift | 4 ++--
3 files changed, 20 insertions(+), 5 deletions(-)
diff --git a/swift/ql/src/queries/Security/CWE-311/CleartextStorageDatabase.ql b/swift/ql/src/queries/Security/CWE-311/CleartextStorageDatabase.ql
index b34f1b0c6cf..2eddbeeedaf 100644
--- a/swift/ql/src/queries/Security/CWE-311/CleartextStorageDatabase.ql
+++ b/swift/ql/src/queries/Security/CWE-311/CleartextStorageDatabase.ql
@@ -34,7 +34,8 @@ class CoreDataStore extends Stored {
.hasQualifiedName("NSManagedObject",
["setValue(_:forKey:)", "setPrimitiveValue(_:forKey:)"]) and
call.getArgument(0).getExpr() = this.asExpr()
- ) or
+ )
+ or
// any write into a class derived from `NSManagedObject` is a sink. For
// example in `coreDataObj.data = sensitive` the post-update node corresponding
// with `coreDataObj.data` is a sink.
@@ -91,8 +92,10 @@ class CleartextStorageConfig extends TaintTracking::Configuration {
// flow out from fields of an `NSManagedObject` or `RealmSwiftObject` at the sink,
// for example in `realmObj.data = sensitive`.
isSink(node) and
- exists(ClassOrStructDecl cd |
- c.getAReadContent().(DataFlow::Content::FieldContent).getField() = cd.getAMember() and
+ exists(ClassOrStructDecl cd, IterableDeclContext cx |
+ (cx = cd or cx.(ExtensionDecl).getExtendedTypeDecl() = cd) and
+ c.getAReadContent().(DataFlow::Content::FieldContent).getField() = cx.getAMember() and
+ // TODO: add a `getAMember` version that accounts for extensions?
cd.getABaseTypeDecl*().getName() = ["NSManagedObject", "RealmSwiftObject"]
)
or
diff --git a/swift/ql/test/query-tests/Security/CWE-311/CleartextStorageDatabase.expected b/swift/ql/test/query-tests/Security/CWE-311/CleartextStorageDatabase.expected
index d5b33a22ba1..3c019a1be54 100644
--- a/swift/ql/test/query-tests/Security/CWE-311/CleartextStorageDatabase.expected
+++ b/swift/ql/test/query-tests/Security/CWE-311/CleartextStorageDatabase.expected
@@ -6,6 +6,8 @@ edges
| testCoreData2.swift:37:16:37:16 | bankAccountNo : | testCoreData2.swift:37:2:37:2 | [post] obj [myValue] : |
| testCoreData2.swift:39:2:39:2 | [post] obj [myBankAccountNumber] : | testCoreData2.swift:39:2:39:2 | [post] obj |
| testCoreData2.swift:39:28:39:28 | bankAccountNo : | testCoreData2.swift:39:2:39:2 | [post] obj [myBankAccountNumber] : |
+| testCoreData2.swift:41:2:41:2 | [post] obj [myBankAccountNumber2] : | testCoreData2.swift:41:2:41:2 | [post] obj |
+| testCoreData2.swift:41:29:41:29 | bankAccountNo : | testCoreData2.swift:41:2:41:2 | [post] obj [myBankAccountNumber2] : |
| testCoreData2.swift:43:2:43:2 | [post] obj [notStoredBankAccountNumber] : | testCoreData2.swift:43:2:43:2 | [post] obj |
| testCoreData2.swift:43:35:43:35 | bankAccountNo : | testCoreData2.swift:23:13:23:13 | value : |
| testCoreData2.swift:43:35:43:35 | bankAccountNo : | testCoreData2.swift:43:2:43:2 | [post] obj [notStoredBankAccountNumber] : |
@@ -13,6 +15,8 @@ edges
| testCoreData2.swift:46:22:46:22 | bankAccountNo : | testCoreData2.swift:46:2:46:10 | [post] ...? [myValue] : |
| testCoreData2.swift:48:2:48:10 | [post] ...? [myBankAccountNumber] : | testCoreData2.swift:48:2:48:10 | [post] ...? |
| testCoreData2.swift:48:34:48:34 | bankAccountNo : | testCoreData2.swift:48:2:48:10 | [post] ...? [myBankAccountNumber] : |
+| testCoreData2.swift:50:2:50:10 | [post] ...? [myBankAccountNumber2] : | testCoreData2.swift:50:2:50:10 | [post] ...? |
+| testCoreData2.swift:50:35:50:35 | bankAccountNo : | testCoreData2.swift:50:2:50:10 | [post] ...? [myBankAccountNumber2] : |
| testCoreData2.swift:52:2:52:10 | [post] ...? [notStoredBankAccountNumber] : | testCoreData2.swift:52:2:52:10 | [post] ...? |
| testCoreData2.swift:52:41:52:41 | bankAccountNo : | testCoreData2.swift:23:13:23:13 | value : |
| testCoreData2.swift:52:41:52:41 | bankAccountNo : | testCoreData2.swift:52:2:52:10 | [post] ...? [notStoredBankAccountNumber] : |
@@ -54,6 +58,9 @@ nodes
| testCoreData2.swift:39:2:39:2 | [post] obj | semmle.label | [post] obj |
| testCoreData2.swift:39:2:39:2 | [post] obj [myBankAccountNumber] : | semmle.label | [post] obj [myBankAccountNumber] : |
| testCoreData2.swift:39:28:39:28 | bankAccountNo : | semmle.label | bankAccountNo : |
+| testCoreData2.swift:41:2:41:2 | [post] obj | semmle.label | [post] obj |
+| testCoreData2.swift:41:2:41:2 | [post] obj [myBankAccountNumber2] : | semmle.label | [post] obj [myBankAccountNumber2] : |
+| testCoreData2.swift:41:29:41:29 | bankAccountNo : | semmle.label | bankAccountNo : |
| testCoreData2.swift:43:2:43:2 | [post] obj | semmle.label | [post] obj |
| testCoreData2.swift:43:2:43:2 | [post] obj [notStoredBankAccountNumber] : | semmle.label | [post] obj [notStoredBankAccountNumber] : |
| testCoreData2.swift:43:35:43:35 | bankAccountNo : | semmle.label | bankAccountNo : |
@@ -63,6 +70,9 @@ nodes
| testCoreData2.swift:48:2:48:10 | [post] ...? | semmle.label | [post] ...? |
| testCoreData2.swift:48:2:48:10 | [post] ...? [myBankAccountNumber] : | semmle.label | [post] ...? [myBankAccountNumber] : |
| testCoreData2.swift:48:34:48:34 | bankAccountNo : | semmle.label | bankAccountNo : |
+| testCoreData2.swift:50:2:50:10 | [post] ...? | semmle.label | [post] ...? |
+| testCoreData2.swift:50:2:50:10 | [post] ...? [myBankAccountNumber2] : | semmle.label | [post] ...? [myBankAccountNumber2] : |
+| testCoreData2.swift:50:35:50:35 | bankAccountNo : | semmle.label | bankAccountNo : |
| testCoreData2.swift:52:2:52:10 | [post] ...? | semmle.label | [post] ...? |
| testCoreData2.swift:52:2:52:10 | [post] ...? [notStoredBankAccountNumber] : | semmle.label | [post] ...? [notStoredBankAccountNumber] : |
| testCoreData2.swift:52:41:52:41 | bankAccountNo : | semmle.label | bankAccountNo : |
@@ -114,9 +124,11 @@ subpaths
#select
| testCoreData2.swift:37:2:37:2 | obj | testCoreData2.swift:37:16:37:16 | bankAccountNo : | testCoreData2.swift:37:2:37:2 | [post] obj | This operation stores '[post] obj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:37:16:37:16 | bankAccountNo : | bankAccountNo |
| testCoreData2.swift:39:2:39:2 | obj | testCoreData2.swift:39:28:39:28 | bankAccountNo : | testCoreData2.swift:39:2:39:2 | [post] obj | This operation stores '[post] obj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:39:28:39:28 | bankAccountNo : | bankAccountNo |
+| testCoreData2.swift:41:2:41:2 | obj | testCoreData2.swift:41:29:41:29 | bankAccountNo : | testCoreData2.swift:41:2:41:2 | [post] obj | This operation stores '[post] obj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:41:29:41:29 | bankAccountNo : | bankAccountNo |
| testCoreData2.swift:43:2:43:2 | obj | testCoreData2.swift:43:35:43:35 | bankAccountNo : | testCoreData2.swift:43:2:43:2 | [post] obj | This operation stores '[post] obj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:43:35:43:35 | bankAccountNo : | bankAccountNo |
| testCoreData2.swift:46:2:46:10 | ...? | testCoreData2.swift:46:22:46:22 | bankAccountNo : | testCoreData2.swift:46:2:46:10 | [post] ...? | This operation stores '[post] ...?' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:46:22:46:22 | bankAccountNo : | bankAccountNo |
| testCoreData2.swift:48:2:48:10 | ...? | testCoreData2.swift:48:34:48:34 | bankAccountNo : | testCoreData2.swift:48:2:48:10 | [post] ...? | This operation stores '[post] ...?' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:48:34:48:34 | bankAccountNo : | bankAccountNo |
+| testCoreData2.swift:50:2:50:10 | ...? | testCoreData2.swift:50:35:50:35 | bankAccountNo : | testCoreData2.swift:50:2:50:10 | [post] ...? | This operation stores '[post] ...?' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:50:35:50:35 | bankAccountNo : | bankAccountNo |
| testCoreData2.swift:52:2:52:10 | ...? | testCoreData2.swift:52:41:52:41 | bankAccountNo : | testCoreData2.swift:52:2:52:10 | [post] ...? | This operation stores '[post] ...?' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:52:41:52:41 | bankAccountNo : | bankAccountNo |
| testCoreData2.swift:57:3:57:3 | obj | testCoreData2.swift:57:29:57:29 | bankAccountNo : | testCoreData2.swift:57:3:57:3 | [post] obj | This operation stores '[post] obj' in a database. It may contain unencrypted sensitive data from $@. | testCoreData2.swift:57:29:57:29 | bankAccountNo : | bankAccountNo |
| testCoreData.swift:19:12:19:12 | value | testCoreData.swift:61:25:61:25 | password : | testCoreData.swift:19:12:19:12 | value | This operation stores 'value' in a database. It may contain unencrypted sensitive data from $@. | testCoreData.swift:61:25:61:25 | password : | password |
diff --git a/swift/ql/test/query-tests/Security/CWE-311/testCoreData2.swift b/swift/ql/test/query-tests/Security/CWE-311/testCoreData2.swift
index 6cf2afb8094..a08b4994965 100644
--- a/swift/ql/test/query-tests/Security/CWE-311/testCoreData2.swift
+++ b/swift/ql/test/query-tests/Security/CWE-311/testCoreData2.swift
@@ -38,7 +38,7 @@ func testCoreData2_1(obj: MyManagedObject2, maybeObj: MyManagedObject2?, value:
obj.myBankAccountNumber = value // BAD [NOT DETECTED]
obj.myBankAccountNumber = bankAccountNo // BAD
obj.myBankAccountNumber2 = value // BAD [NOT DETECTED]
- obj.myBankAccountNumber2 = bankAccountNo // BAD [NOT DETECTED]
+ obj.myBankAccountNumber2 = bankAccountNo // BAD
obj.notStoredBankAccountNumber = value // GOOD (not stored in the database)
obj.notStoredBankAccountNumber = bankAccountNo // GOOD (not stored in the datbase) [FALSE POSITIVE]
@@ -47,7 +47,7 @@ func testCoreData2_1(obj: MyManagedObject2, maybeObj: MyManagedObject2?, value:
maybeObj?.myBankAccountNumber = value // BAD [NOT DETECTED]
maybeObj?.myBankAccountNumber = bankAccountNo // BAD
maybeObj?.myBankAccountNumber2 = value // BAD [NOT DETECTED]
- maybeObj?.myBankAccountNumber2 = bankAccountNo // BAD [NOT DETECTED]
+ maybeObj?.myBankAccountNumber2 = bankAccountNo // BAD
maybeObj?.notStoredBankAccountNumber = value // GOOD (not stored in the database)
maybeObj?.notStoredBankAccountNumber = bankAccountNo // GOOD (not stored in the datbase) [FALSE POSITIVE]
}
From 6bb865ad0511c7114453b8d076135f9e85fdbcbf Mon Sep 17 00:00:00 2001
From: Jami Cogswell
Date: Wed, 11 Jan 2023 18:04:43 -0500
Subject: [PATCH 198/381] Java: make numeric flow models neutral
---
java/ql/lib/ext/java.lang.model.yml | 23 ++++----
java/ql/lib/ext/java.math.model.yml | 14 ++---
java/ql/lib/ext/java.sql.model.yml | 7 ++-
.../ext/java.util.concurrent.atomic.model.yml | 11 +++-
.../ql/lib/ext/java.util.concurrent.model.yml | 7 ++-
java/ql/lib/ext/java.util.model.yml | 7 ++-
java/ql/src/Telemetry/ExternalApi.qll | 1 +
java/ql/test/ext/TestModels/Test.java | 59 -------------------
8 files changed, 44 insertions(+), 85 deletions(-)
diff --git a/java/ql/lib/ext/java.lang.model.yml b/java/ql/lib/ext/java.lang.model.yml
index ae383705be1..8d6fa3956ac 100644
--- a/java/ql/lib/ext/java.lang.model.yml
+++ b/java/ql/lib/ext/java.lang.model.yml
@@ -41,17 +41,9 @@ extensions:
- ["java.lang", "IllegalArgumentException", False, "IllegalArgumentException", "(String)", "", "Argument[0]", "Argument[-1].SyntheticField[java.lang.Throwable.message]", "value", "manual"]
- ["java.lang", "IllegalStateException", False, "IllegalStateException", "(String)", "", "Argument[0]", "Argument[-1].SyntheticField[java.lang.Throwable.message]", "value", "manual"]
- ["java.lang", "IndexOutOfBoundsException", False, "IndexOutOfBoundsException", "(String)", "", "Argument[0]", "Argument[-1].SyntheticField[java.lang.Throwable.message]", "value", "manual"]
- - ["java.lang", "Integer", False, "intValue", "()", "", "Argument[-1]", "ReturnValue", "taint", "manual"]
- - ["java.lang", "Integer", False, "parseInt", "(String)", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- - ["java.lang", "Integer", False, "toString", "(int)", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- - ["java.lang", "Integer", False, "valueOf", "(int)", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["java.lang", "Iterable", True, "forEach", "(Consumer)", "", "Argument[-1].Element", "Argument[0].Parameter[0]", "value", "manual"]
- ["java.lang", "Iterable", True, "iterator", "()", "", "Argument[-1].Element", "ReturnValue.Element", "value", "manual"]
- ["java.lang", "Iterable", True, "spliterator", "()", "", "Argument[-1].Element", "ReturnValue.Element", "value", "manual"]
- - ["java.lang", "Long", False, "longValue", "()", "", "Argument[-1]", "ReturnValue", "taint", "manual"]
- - ["java.lang", "Long", False, "parseLong", "(String)", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- - ["java.lang", "Long", False, "toString", "()", "", "Argument[-1]", "ReturnValue", "taint", "manual"]
- - ["java.lang", "Math", False, "min", "(int,int)", "", "Argument[0..1]", "ReturnValue", "value", "manual"]
- ["java.lang", "Object", True, "clone", "", "", "Argument[-1].Element", "ReturnValue.Element", "value", "manual"]
- ["java.lang", "Object", True, "clone", "", "", "Argument[-1].MapKey", "ReturnValue.MapKey", "value", "manual"]
- ["java.lang", "Object", True, "clone", "", "", "Argument[-1].MapValue", "ReturnValue.MapValue", "value", "manual"]
@@ -97,8 +89,6 @@ extensions:
- ["java.lang", "String", False, "valueOf", "(char)", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["java.lang", "String", False, "valueOf", "(char[])", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["java.lang", "String", False, "valueOf", "(char[],int,int)", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- - ["java.lang", "String", False, "valueOf", "(int)", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- - ["java.lang", "String", False, "valueOf", "(long)", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["java.lang", "StringBuffer", True, "StringBuffer", "(CharSequence)", "", "Argument[0]", "Argument[-1]", "taint", "manual"]
- ["java.lang", "StringBuffer", True, "StringBuffer", "(String)", "", "Argument[0]", "Argument[-1]", "taint", "manual"]
- ["java.lang", "StringBuilder", True, "StringBuilder", "", "", "Argument[0]", "Argument[-1]", "taint", "manual"]
@@ -143,3 +133,16 @@ extensions:
- ["java.lang", "System", "nanoTime", "()", "manual"]
- ["java.lang", "Thread", "currentThread", "()", "manual"]
- ["java.lang", "Thread", "sleep", "(long)", "manual"]
+
+ # The below APIs have numeric flow and are currently being stored as neutral models.
+ # These may be changed to summary models with kinds "value-numeric" and "taint-numeric" (or similar) in the future.
+ - ["java.lang", "Integer", "intValue", "()", "manual"] # taint-numeric
+ - ["java.lang", "Integer", "parseInt", "(String)", "manual"] # taint-numeric
+ - ["java.lang", "Integer", "toString", "(int)", "manual"] # taint-numeric
+ - ["java.lang", "Integer", "valueOf", "(int)", "manual"] # taint-numeric
+ - ["java.lang", "Long", "longValue", "()", "manual"] # taint-numeric
+ - ["java.lang", "Long", "parseLong", "(String)", "manual"] # taint-numeric
+ - ["java.lang", "Long", "toString", "()", "manual"] # taint-numeric
+ - ["java.lang", "Math", "min", "(int,int)", "manual"] # value-numeric
+ - ["java.lang", "String", "valueOf", "(int)", "manual"] # taint-numeric
+ - ["java.lang", "String", "valueOf", "(long)", "manual"] # taint-numeric
diff --git a/java/ql/lib/ext/java.math.model.yml b/java/ql/lib/ext/java.math.model.yml
index 3056e04182a..1d45a4076bf 100644
--- a/java/ql/lib/ext/java.math.model.yml
+++ b/java/ql/lib/ext/java.math.model.yml
@@ -1,14 +1,12 @@
extensions:
- - addsTo:
- pack: codeql/java-all
- extensible: summaryModel
- data:
- - ["java.math", "BigDecimal", False, "BigDecimal", "(String)", "", "Argument[0]", "Argument[-1]", "taint", "manual"]
- - ["java.math", "BigDecimal", False, "valueOf", "(double)", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- - ["java.math", "BigDecimal", False, "valueOf", "(long)", "", "Argument[0]", "ReturnValue", "taint", "manual"]
-
- addsTo:
pack: codeql/java-all
extensible: neutralModel
data:
- ["java.math", "BigDecimal", "compareTo", "(BigDecimal)", "manual"]
+
+ # The below APIs have numeric flow and are currently being stored as neutral models.
+ # These may be changed to summary models with kinds "value-numeric" and "taint-numeric" (or similar) in the future.
+ - ["java.math", "BigDecimal", "BigDecimal", "(String)", "manual"] # taint-numeric
+ - ["java.math", "BigDecimal", "valueOf", "(double)", "manual"] # taint-numeric
+ - ["java.math", "BigDecimal", "valueOf", "(long)", "manual"] # taint-numeric
diff --git a/java/ql/lib/ext/java.sql.model.yml b/java/ql/lib/ext/java.sql.model.yml
index 9dd0e7d948c..bf544fdb8e7 100644
--- a/java/ql/lib/ext/java.sql.model.yml
+++ b/java/ql/lib/ext/java.sql.model.yml
@@ -19,9 +19,7 @@ extensions:
pack: codeql/java-all
extensible: summaryModel
data:
- - ["java.sql", "PreparedStatement", True, "setInt", "(int,int)", "", "Argument[1]", "Argument[-1]", "value", "manual"]
- ["java.sql", "PreparedStatement", True, "setString", "(int,String)", "", "Argument[1]", "Argument[-1]", "value", "manual"]
- - ["java.sql", "ResultSet", True, "getInt", "(String)", "", "Argument[-1]", "ReturnValue", "taint", "manual"]
- ["java.sql", "ResultSet", True, "getString", "(String)", "", "Argument[-1]", "ReturnValue", "taint", "manual"]
- addsTo:
@@ -29,3 +27,8 @@ extensions:
extensible: neutralModel
data:
- ["java.sql", "ResultSet", "next", "()", "manual"]
+
+ # The below APIs have numeric flow and are currently being stored as neutral models.
+ # These may be changed to summary models with kinds "value-numeric" and "taint-numeric" (or similar) in the future.
+ - ["java.sql", "PreparedStatement", "setInt", "(int,int)", "manual"] # value-numeric
+ - ["java.sql", "ResultSet", "getInt", "(String)", "manual"] # taint-numeric
diff --git a/java/ql/lib/ext/java.util.concurrent.atomic.model.yml b/java/ql/lib/ext/java.util.concurrent.atomic.model.yml
index 4dc1318c4d8..7dd3d13b301 100644
--- a/java/ql/lib/ext/java.util.concurrent.atomic.model.yml
+++ b/java/ql/lib/ext/java.util.concurrent.atomic.model.yml
@@ -3,7 +3,14 @@ extensions:
pack: codeql/java-all
extensible: summaryModel
data:
- - ["java.util.concurrent.atomic", "AtomicInteger", False, "AtomicInteger", "(int)", "", "Argument[0]", "Argument[-1].SyntheticField[java.util.concurrent.atomic.AtomicInteger.value]", "value", "manual"]
- - ["java.util.concurrent.atomic", "AtomicInteger", False, "get", "()", "", "Argument[-1].SyntheticField[java.util.concurrent.atomic.AtomicInteger.value]", "ReturnValue", "value", "manual"]
- ["java.util.concurrent.atomic", "AtomicReference", False, "AtomicReference", "(Object)", "", "Argument[0]", "Argument[-1].SyntheticField[java.util.concurrent.atomic.AtomicReference.value]", "value", "manual"]
- ["java.util.concurrent.atomic", "AtomicReference", False, "get", "()", "", "Argument[-1].SyntheticField[java.util.concurrent.atomic.AtomicReference.value]", "ReturnValue", "value", "manual"]
+
+ - addsTo:
+ pack: codeql/java-all
+ extensible: neutralModel
+ data:
+ # The below APIs have numeric flow and are currently being stored as neutral models.
+ # These may be changed to summary models with kinds "value-numeric" and "taint-numeric" (or similar) in the future.
+ - ["java.util.concurrent.atomic", "AtomicInteger", "AtomicInteger", "(int)", "manual"] # value-numeric
+ - ["java.util.concurrent.atomic", "AtomicInteger", "get", "()", "manual"] # value-numeric
diff --git a/java/ql/lib/ext/java.util.concurrent.model.yml b/java/ql/lib/ext/java.util.concurrent.model.yml
index bfffc342558..3d199321dd6 100644
--- a/java/ql/lib/ext/java.util.concurrent.model.yml
+++ b/java/ql/lib/ext/java.util.concurrent.model.yml
@@ -18,8 +18,6 @@ extensions:
- ["java.util.concurrent", "BlockingQueue", True, "put", "(Object)", "", "Argument[0]", "Argument[-1].Element", "value", "manual"]
- ["java.util.concurrent", "BlockingQueue", True, "take", "()", "", "Argument[-1].Element", "ReturnValue", "value", "manual"]
- ["java.util.concurrent", "ConcurrentHashMap", True, "elements", "()", "", "Argument[-1].MapValue", "ReturnValue.Element", "value", "manual"]
- - ["java.util.concurrent", "CountDownLatch", False, "CountDownLatch", "(int)", "", "Argument[0]", "Argument[-1].SyntheticField[java.util.concurrent.CountDownLatch.count]", "value", "manual"]
- - ["java.util.concurrent", "CountDownLatch", False, "getCount", "()", "", "Argument[-1].SyntheticField[java.util.concurrent.CountDownLatch.count]", "ReturnValue", "value", "manual"]
- ["java.util.concurrent", "TransferQueue", True, "transfer", "(Object)", "", "Argument[0]", "Argument[-1].Element", "value", "manual"]
- ["java.util.concurrent", "TransferQueue", True, "tryTransfer", "(Object)", "", "Argument[0]", "Argument[-1].Element", "value", "manual"]
- ["java.util.concurrent", "TransferQueue", True, "tryTransfer", "(Object,long,TimeUnit)", "", "Argument[0]", "Argument[-1].Element", "value", "manual"]
@@ -29,3 +27,8 @@ extensions:
extensible: neutralModel
data:
- ["java.util.concurrent", "CountDownLatch", "countDown", "()", "manual"]
+
+ # The below APIs have numeric flow and are currently being stored as neutral models.
+ # These may be changed to summary models with kinds "value-numeric" and "taint-numeric" (or similar) in the future.
+ - ["java.util.concurrent", "CountDownLatch", "CountDownLatch", "(int)", "manual"] # value-numeric
+ - ["java.util.concurrent", "CountDownLatch", "getCount", "()", "manual"] # value-numeric
diff --git a/java/ql/lib/ext/java.util.model.yml b/java/ql/lib/ext/java.util.model.yml
index ec45266409a..df75f791ced 100644
--- a/java/ql/lib/ext/java.util.model.yml
+++ b/java/ql/lib/ext/java.util.model.yml
@@ -369,8 +369,6 @@ extensions:
- ["java.util", "Collections", "emptyList", "()", "manual"]
- ["java.util", "Collections", "emptyMap", "()", "manual"]
- ["java.util", "Collections", "emptySet", "()", "manual"]
- - ["java.util", "Date", "Date", "(long)", "manual"]
- - ["java.util", "Date", "getTime", "()", "manual"]
- ["java.util", "Iterator", "hasNext", "()", "manual"]
- ["java.util", "List", "clear", "()", "manual"]
- ["java.util", "List", "contains", "(Object)", "manual"]
@@ -390,3 +388,8 @@ extensions:
- ["java.util", "Set", "size", "()", "manual"]
- ["java.util", "UUID", "randomUUID", "()", "manual"]
- ["java.util", "UUID", "toString", "()", "manual"]
+
+ # The below APIs have numeric flow and are currently being stored as neutral models.
+ # These may be changed to summary models with kinds "value-numeric" and "taint-numeric" (or similar) in the future.
+ - ["java.util", "Date", "Date", "(long)", "manual"] # taint-numeric
+ - ["java.util", "Date", "getTime", "()", "manual"] # taint-numeric
diff --git a/java/ql/src/Telemetry/ExternalApi.qll b/java/ql/src/Telemetry/ExternalApi.qll
index 2f7ebcc9d19..6a51d20e8f5 100644
--- a/java/ql/src/Telemetry/ExternalApi.qll
+++ b/java/ql/src/Telemetry/ExternalApi.qll
@@ -47,6 +47,7 @@ class ExternalApi extends Callable {
* Gets information about the external API in the form expected by the CSV modeling framework.
*/
string getApiName() {
+ this.getName() = "append" and
result =
this.getDeclaringType().getPackage() + "." + this.getDeclaringType().getSourceDeclaration() +
"#" + this.getName() + paramsString(this)
diff --git a/java/ql/test/ext/TestModels/Test.java b/java/ql/test/ext/TestModels/Test.java
index 55c531d99bf..c2053d67929 100644
--- a/java/ql/test/ext/TestModels/Test.java
+++ b/java/ql/test/ext/TestModels/Test.java
@@ -6,8 +6,6 @@ import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.StringJoiner;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Function;
import java.util.function.Supplier;
@@ -38,20 +36,10 @@ public class Test {
Throwable t = new Throwable((Throwable)source());
sink((Throwable)t.getCause()); // $hasValueFlow
- Integer x = (Integer)source();
- int y = x;
- sink(String.valueOf(y)); // $hasTaintFlow
-
- String s1 = (String)source();
- sink(Integer.parseInt(s1)); // $hasTaintFlow
-
String s2 = (String)source();
int i = 0;
sink(s2.charAt(i)); // $hasTaintFlow
- String s3 = (String)source();
- sink(new BigDecimal(s3)); // $hasTaintFlow
-
ResultSet rs = (ResultSet)source();
sink(rs.getString("")); // $hasTaintFlow
}
@@ -76,66 +64,19 @@ public class Test {
sink((String)e4.getMessage()); // $hasValueFlow
sink((Throwable)e4.getCause()); // $hasValueFlow
- Integer i1 = (Integer)source();
- sink(i1.intValue()); // $hasTaintFlow
-
- int i2 = (int)source();
- sink(Integer.toString(i2)); // $hasTaintFlow
-
- int i3 = (int)source();
- sink(Integer.valueOf(i3)); // $hasTaintFlow
-
- Long l1 = (Long)source();
- sink(l1.longValue()); // $hasTaintFlow
-
- String s1 = (String)source();
- sink(Long.parseLong(s1)); // $hasTaintFlow
-
- Long l2 = (Long)source();
- sink(l2.toString()); // $hasTaintFlow
-
- long l3 = (long)source();
- sink(String.valueOf(l3)); // $hasTaintFlow
-
System.setProperty("testKey", (String)source());
sink(System.getProperty("testKey")); // $hasValueFlow
- // java.math
- long l4 = (long)source();
- sink(BigDecimal.valueOf(l4)); // $hasTaintFlow
-
- double d1 = (double)source();
- sink(BigDecimal.valueOf(d1)); // $hasTaintFlow
-
- int i4 = (int)source();
- int i5 = (int)source();
- sink(Math.min(i4, i5)); // $hasValueFlow
- sink(Math.min(i4, 42)); // $hasValueFlow
- sink(Math.min(42, i5)); // $hasValueFlow
-
// java.sql
Connection con = DriverManager.getConnection("");
PreparedStatement ps1 = con.prepareStatement("UPDATE EMPLOYEES SET NAME = ? WHERE ID = ?");
ps1.setString(1, (String)source());
sink(ps1); // $hasValueFlow
- PreparedStatement ps2 = con.prepareStatement("UPDATE EMPLOYEES SET NAME = ? WHERE ID = ?");
- ps2.setInt(2, (int)source());
- sink(ps2); // $hasValueFlow
-
- ResultSet rs = (ResultSet)source();
- sink(rs.getInt("")); // $hasTaintFlow
// java.util.concurrent.atomic
- AtomicInteger ai = new AtomicInteger((int)source());
- sink(ai.get()); // $hasValueFlow
-
AtomicReference ar = new AtomicReference(source());
sink(ar.get()); // $hasValueFlow
- // java.util.concurrent
- CountDownLatch cdl = new CountDownLatch((int)source());
- sink(cdl.getCount()); // $hasValueFlow
-
// java.util.function
Function func = a -> a + "";
sink(func.apply(source())); // $hasTaintFlow
From ce74c9d9592cb2044ddbef93d393021cb857ff37 Mon Sep 17 00:00:00 2001
From: Jami Cogswell
Date: Wed, 11 Jan 2023 22:15:41 -0500
Subject: [PATCH 199/381] Java: Date models as neutral
---
java/ql/lib/ext/java.text.model.yml | 6 ++++--
java/ql/lib/ext/java.time.model.yml | 5 ++++-
java/ql/src/Telemetry/ExternalApi.qll | 1 -
3 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/java/ql/lib/ext/java.text.model.yml b/java/ql/lib/ext/java.text.model.yml
index edf2a4c7d60..bbb01596f17 100644
--- a/java/ql/lib/ext/java.text.model.yml
+++ b/java/ql/lib/ext/java.text.model.yml
@@ -3,5 +3,7 @@ extensions:
pack: codeql/java-all
extensible: neutralModel
data:
- - ["java.text", "DateFormat", "format", "(Date)", "manual"]
- - ["java.text", "SimpleDateFormat", "SimpleDateFormat", "(String)", "manual"]
+ # The below APIs have numeric flow and are currently being stored as neutral models.
+ # These may be changed to summary models with kinds "value-numeric" and "taint-numeric" (or similar) in the future.
+ - ["java.text", "DateFormat", "format", "(Date)", "manual"] # taint-numeric
+ - ["java.text", "SimpleDateFormat", "SimpleDateFormat", "(String)", "manual"] # taint-numeric
diff --git a/java/ql/lib/ext/java.time.model.yml b/java/ql/lib/ext/java.time.model.yml
index 1a9b745f403..002240c6488 100644
--- a/java/ql/lib/ext/java.time.model.yml
+++ b/java/ql/lib/ext/java.time.model.yml
@@ -4,5 +4,8 @@ extensions:
extensible: neutralModel
data:
- ["java.time", "Instant", "now", "()", "manual"]
- - ["java.time", "LocalDate", "of", "(int,int,int)", "manual"]
- ["java.time", "ZonedDateTime", "now", "()", "manual"]
+
+ # The below APIs have numeric flow and are currently being stored as neutral models.
+ # These may be changed to summary models with kinds "value-numeric" and "taint-numeric" (or similar) in the future.
+ - ["java.time", "LocalDate", "of", "(int,int,int)", "manual"] # taint-numeric
diff --git a/java/ql/src/Telemetry/ExternalApi.qll b/java/ql/src/Telemetry/ExternalApi.qll
index 6a51d20e8f5..2f7ebcc9d19 100644
--- a/java/ql/src/Telemetry/ExternalApi.qll
+++ b/java/ql/src/Telemetry/ExternalApi.qll
@@ -47,7 +47,6 @@ class ExternalApi extends Callable {
* Gets information about the external API in the form expected by the CSV modeling framework.
*/
string getApiName() {
- this.getName() = "append" and
result =
this.getDeclaringType().getPackage() + "." + this.getDeclaringType().getSourceDeclaration() +
"#" + this.getName() + paramsString(this)
From fd593fd4f05b4dd1a6498ae33cc75621d896edd8 Mon Sep 17 00:00:00 2001
From: Jami Cogswell
Date: Wed, 11 Jan 2023 22:34:19 -0500
Subject: [PATCH 200/381] Java: undo changes to tests that were affected by
numeric-flow summary models
---
.../security/CWE-400/ThreadResourceAbuse.expected | 10 ----------
.../security/CWE-755/NFEAndroidDoS.expected | 6 ------
...roperValidationOfArrayConstructionLocal.expected | 4 ----
.../ImproperValidationOfArrayIndexLocal.expected | 3 ---
.../semmle/tests/ArithmeticTaintedLocal.expected | 13 -------------
.../semmle/tests/NumericCastTaintedLocal.expected | 3 ---
6 files changed, 39 deletions(-)
diff --git a/java/ql/test/experimental/query-tests/security/CWE-400/ThreadResourceAbuse.expected b/java/ql/test/experimental/query-tests/security/CWE-400/ThreadResourceAbuse.expected
index f8d18994ac0..a510070daf9 100644
--- a/java/ql/test/experimental/query-tests/security/CWE-400/ThreadResourceAbuse.expected
+++ b/java/ql/test/experimental/query-tests/security/CWE-400/ThreadResourceAbuse.expected
@@ -12,14 +12,8 @@ edges
| ThreadResourceAbuse.java:71:15:71:17 | parameter this [waitTime] : Number | ThreadResourceAbuse.java:74:18:74:25 | this <.field> [waitTime] : Number |
| ThreadResourceAbuse.java:74:18:74:25 | this <.field> [waitTime] : Number | ThreadResourceAbuse.java:74:18:74:25 | waitTime |
| ThreadResourceAbuse.java:141:27:141:43 | getValue(...) : String | ThreadResourceAbuse.java:144:34:144:42 | delayTime |
-| ThreadResourceAbuse.java:172:19:172:50 | getHeader(...) : String | ThreadResourceAbuse.java:173:37:173:42 | header : String |
| ThreadResourceAbuse.java:172:19:172:50 | getHeader(...) : String | ThreadResourceAbuse.java:176:17:176:26 | retryAfter |
-| ThreadResourceAbuse.java:173:20:173:43 | parseInt(...) : Number | ThreadResourceAbuse.java:176:17:176:26 | retryAfter |
-| ThreadResourceAbuse.java:173:37:173:42 | header : String | ThreadResourceAbuse.java:173:20:173:43 | parseInt(...) : Number |
-| ThreadResourceAbuse.java:206:28:206:56 | getParameter(...) : String | ThreadResourceAbuse.java:207:39:207:52 | uploadDelayStr : String |
| ThreadResourceAbuse.java:206:28:206:56 | getParameter(...) : String | ThreadResourceAbuse.java:209:49:209:59 | uploadDelay : Number |
-| ThreadResourceAbuse.java:207:22:207:53 | parseInt(...) : Number | ThreadResourceAbuse.java:209:49:209:59 | uploadDelay : Number |
-| ThreadResourceAbuse.java:207:39:207:52 | uploadDelayStr : String | ThreadResourceAbuse.java:207:22:207:53 | parseInt(...) : Number |
| ThreadResourceAbuse.java:209:30:209:87 | new UploadListener(...) [slowUploads] : Number | UploadListener.java:28:14:28:19 | parameter this [slowUploads] : Number |
| ThreadResourceAbuse.java:209:49:209:59 | uploadDelay : Number | ThreadResourceAbuse.java:209:30:209:87 | new UploadListener(...) [slowUploads] : Number |
| ThreadResourceAbuse.java:209:49:209:59 | uploadDelay : Number | UploadListener.java:15:24:15:44 | sleepMilliseconds : Number |
@@ -48,12 +42,8 @@ nodes
| ThreadResourceAbuse.java:141:27:141:43 | getValue(...) : String | semmle.label | getValue(...) : String |
| ThreadResourceAbuse.java:144:34:144:42 | delayTime | semmle.label | delayTime |
| ThreadResourceAbuse.java:172:19:172:50 | getHeader(...) : String | semmle.label | getHeader(...) : String |
-| ThreadResourceAbuse.java:173:20:173:43 | parseInt(...) : Number | semmle.label | parseInt(...) : Number |
-| ThreadResourceAbuse.java:173:37:173:42 | header : String | semmle.label | header : String |
| ThreadResourceAbuse.java:176:17:176:26 | retryAfter | semmle.label | retryAfter |
| ThreadResourceAbuse.java:206:28:206:56 | getParameter(...) : String | semmle.label | getParameter(...) : String |
-| ThreadResourceAbuse.java:207:22:207:53 | parseInt(...) : Number | semmle.label | parseInt(...) : Number |
-| ThreadResourceAbuse.java:207:39:207:52 | uploadDelayStr : String | semmle.label | uploadDelayStr : String |
| ThreadResourceAbuse.java:209:30:209:87 | new UploadListener(...) [slowUploads] : Number | semmle.label | new UploadListener(...) [slowUploads] : Number |
| ThreadResourceAbuse.java:209:49:209:59 | uploadDelay : Number | semmle.label | uploadDelay : Number |
| UploadListener.java:15:24:15:44 | sleepMilliseconds : Number | semmle.label | sleepMilliseconds : Number |
diff --git a/java/ql/test/experimental/query-tests/security/CWE-755/NFEAndroidDoS.expected b/java/ql/test/experimental/query-tests/security/CWE-755/NFEAndroidDoS.expected
index 29c1daf500c..73657a38158 100644
--- a/java/ql/test/experimental/query-tests/security/CWE-755/NFEAndroidDoS.expected
+++ b/java/ql/test/experimental/query-tests/security/CWE-755/NFEAndroidDoS.expected
@@ -3,12 +3,8 @@ edges
| NFEAndroidDoS.java:13:24:13:61 | getStringExtra(...) : Object | NFEAndroidDoS.java:14:21:14:51 | parseDouble(...) |
| NFEAndroidDoS.java:22:21:22:31 | getIntent(...) : Intent | NFEAndroidDoS.java:22:21:22:55 | getStringExtra(...) : Object |
| NFEAndroidDoS.java:22:21:22:55 | getStringExtra(...) : Object | NFEAndroidDoS.java:23:15:23:40 | parseInt(...) |
-| NFEAndroidDoS.java:22:21:22:55 | getStringExtra(...) : Object | NFEAndroidDoS.java:23:32:23:39 | widthStr : Object |
-| NFEAndroidDoS.java:23:32:23:39 | widthStr : Object | NFEAndroidDoS.java:23:15:23:40 | parseInt(...) |
| NFEAndroidDoS.java:25:22:25:32 | getIntent(...) : Intent | NFEAndroidDoS.java:25:22:25:57 | getStringExtra(...) : Object |
| NFEAndroidDoS.java:25:22:25:57 | getStringExtra(...) : Object | NFEAndroidDoS.java:26:16:26:42 | parseInt(...) |
-| NFEAndroidDoS.java:25:22:25:57 | getStringExtra(...) : Object | NFEAndroidDoS.java:26:33:26:41 | heightStr : Object |
-| NFEAndroidDoS.java:26:33:26:41 | heightStr : Object | NFEAndroidDoS.java:26:16:26:42 | parseInt(...) |
| NFEAndroidDoS.java:43:24:43:34 | getIntent(...) : Intent | NFEAndroidDoS.java:43:24:43:61 | getStringExtra(...) : Object |
| NFEAndroidDoS.java:43:24:43:61 | getStringExtra(...) : Object | NFEAndroidDoS.java:44:21:44:43 | new Double(...) |
| NFEAndroidDoS.java:43:24:43:61 | getStringExtra(...) : Object | NFEAndroidDoS.java:47:21:47:47 | valueOf(...) |
@@ -19,11 +15,9 @@ nodes
| NFEAndroidDoS.java:22:21:22:31 | getIntent(...) : Intent | semmle.label | getIntent(...) : Intent |
| NFEAndroidDoS.java:22:21:22:55 | getStringExtra(...) : Object | semmle.label | getStringExtra(...) : Object |
| NFEAndroidDoS.java:23:15:23:40 | parseInt(...) | semmle.label | parseInt(...) |
-| NFEAndroidDoS.java:23:32:23:39 | widthStr : Object | semmle.label | widthStr : Object |
| NFEAndroidDoS.java:25:22:25:32 | getIntent(...) : Intent | semmle.label | getIntent(...) : Intent |
| NFEAndroidDoS.java:25:22:25:57 | getStringExtra(...) : Object | semmle.label | getStringExtra(...) : Object |
| NFEAndroidDoS.java:26:16:26:42 | parseInt(...) | semmle.label | parseInt(...) |
-| NFEAndroidDoS.java:26:33:26:41 | heightStr : Object | semmle.label | heightStr : Object |
| NFEAndroidDoS.java:43:24:43:34 | getIntent(...) : Intent | semmle.label | getIntent(...) : Intent |
| NFEAndroidDoS.java:43:24:43:61 | getStringExtra(...) : Object | semmle.label | getStringExtra(...) : Object |
| NFEAndroidDoS.java:44:21:44:43 | new Double(...) | semmle.label | new Double(...) |
diff --git a/java/ql/test/query-tests/security/CWE-129/semmle/tests/ImproperValidationOfArrayConstructionLocal.expected b/java/ql/test/query-tests/security/CWE-129/semmle/tests/ImproperValidationOfArrayConstructionLocal.expected
index 466e2b10de4..abfb68f74a5 100644
--- a/java/ql/test/query-tests/security/CWE-129/semmle/tests/ImproperValidationOfArrayConstructionLocal.expected
+++ b/java/ql/test/query-tests/security/CWE-129/semmle/tests/ImproperValidationOfArrayConstructionLocal.expected
@@ -1,14 +1,10 @@
edges
| Test.java:76:27:76:60 | getProperty(...) : String | Test.java:78:37:78:48 | userProperty : String |
-| Test.java:78:20:78:56 | parseInt(...) : Number | Test.java:80:31:80:34 | size |
-| Test.java:78:20:78:56 | parseInt(...) : Number | Test.java:86:34:86:37 | size |
| Test.java:78:37:78:48 | userProperty : String | Test.java:78:37:78:55 | trim(...) : String |
-| Test.java:78:37:78:55 | trim(...) : String | Test.java:78:20:78:56 | parseInt(...) : Number |
| Test.java:78:37:78:55 | trim(...) : String | Test.java:80:31:80:34 | size |
| Test.java:78:37:78:55 | trim(...) : String | Test.java:86:34:86:37 | size |
nodes
| Test.java:76:27:76:60 | getProperty(...) : String | semmle.label | getProperty(...) : String |
-| Test.java:78:20:78:56 | parseInt(...) : Number | semmle.label | parseInt(...) : Number |
| Test.java:78:37:78:48 | userProperty : String | semmle.label | userProperty : String |
| Test.java:78:37:78:55 | trim(...) : String | semmle.label | trim(...) : String |
| Test.java:80:31:80:34 | size | semmle.label | size |
diff --git a/java/ql/test/query-tests/security/CWE-129/semmle/tests/ImproperValidationOfArrayIndexLocal.expected b/java/ql/test/query-tests/security/CWE-129/semmle/tests/ImproperValidationOfArrayIndexLocal.expected
index 6c932250e72..6e0738c8576 100644
--- a/java/ql/test/query-tests/security/CWE-129/semmle/tests/ImproperValidationOfArrayIndexLocal.expected
+++ b/java/ql/test/query-tests/security/CWE-129/semmle/tests/ImproperValidationOfArrayIndexLocal.expected
@@ -1,12 +1,9 @@
edges
| Test.java:14:27:14:60 | getProperty(...) : String | Test.java:16:38:16:49 | userProperty : String |
-| Test.java:16:21:16:57 | parseInt(...) : Number | Test.java:19:34:19:38 | index |
| Test.java:16:38:16:49 | userProperty : String | Test.java:16:38:16:56 | trim(...) : String |
-| Test.java:16:38:16:56 | trim(...) : String | Test.java:16:21:16:57 | parseInt(...) : Number |
| Test.java:16:38:16:56 | trim(...) : String | Test.java:19:34:19:38 | index |
nodes
| Test.java:14:27:14:60 | getProperty(...) : String | semmle.label | getProperty(...) : String |
-| Test.java:16:21:16:57 | parseInt(...) : Number | semmle.label | parseInt(...) : Number |
| Test.java:16:38:16:49 | userProperty : String | semmle.label | userProperty : String |
| Test.java:16:38:16:56 | trim(...) : String | semmle.label | trim(...) : String |
| Test.java:19:34:19:38 | index | semmle.label | index |
diff --git a/java/ql/test/query-tests/security/CWE-190/semmle/tests/ArithmeticTaintedLocal.expected b/java/ql/test/query-tests/security/CWE-190/semmle/tests/ArithmeticTaintedLocal.expected
index 188d0fafe6a..4d37fd48f49 100644
--- a/java/ql/test/query-tests/security/CWE-190/semmle/tests/ArithmeticTaintedLocal.expected
+++ b/java/ql/test/query-tests/security/CWE-190/semmle/tests/ArithmeticTaintedLocal.expected
@@ -11,19 +11,8 @@ edges
| ArithmeticTainted.java:19:26:19:39 | readerBuffered : BufferedReader | ArithmeticTainted.java:19:26:19:50 | readLine(...) : String |
| ArithmeticTainted.java:19:26:19:50 | readLine(...) : String | ArithmeticTainted.java:21:29:21:40 | stringNumber : String |
| ArithmeticTainted.java:19:26:19:50 | readLine(...) : String | ArithmeticTainted.java:21:29:21:40 | stringNumber : String |
-| ArithmeticTainted.java:21:12:21:48 | parseInt(...) : Number | ArithmeticTainted.java:32:17:32:20 | data |
-| ArithmeticTainted.java:21:12:21:48 | parseInt(...) : Number | ArithmeticTainted.java:40:17:40:20 | data |
-| ArithmeticTainted.java:21:12:21:48 | parseInt(...) : Number | ArithmeticTainted.java:50:17:50:20 | data |
-| ArithmeticTainted.java:21:12:21:48 | parseInt(...) : Number | ArithmeticTainted.java:64:20:64:23 | data : Number |
-| ArithmeticTainted.java:21:12:21:48 | parseInt(...) : Number | ArithmeticTainted.java:95:37:95:40 | data |
-| ArithmeticTainted.java:21:12:21:48 | parseInt(...) : Number | ArithmeticTainted.java:118:9:118:12 | data : Number |
-| ArithmeticTainted.java:21:12:21:48 | parseInt(...) : Number | ArithmeticTainted.java:119:10:119:13 | data : Number |
-| ArithmeticTainted.java:21:12:21:48 | parseInt(...) : Number | ArithmeticTainted.java:120:10:120:13 | data : Number |
-| ArithmeticTainted.java:21:12:21:48 | parseInt(...) : Number | ArithmeticTainted.java:121:10:121:13 | data : Number |
| ArithmeticTainted.java:21:29:21:40 | stringNumber : String | ArithmeticTainted.java:21:29:21:47 | trim(...) : String |
| ArithmeticTainted.java:21:29:21:40 | stringNumber : String | ArithmeticTainted.java:21:29:21:47 | trim(...) : String |
-| ArithmeticTainted.java:21:29:21:47 | trim(...) : String | ArithmeticTainted.java:21:12:21:48 | parseInt(...) : Number |
-| ArithmeticTainted.java:21:29:21:47 | trim(...) : String | ArithmeticTainted.java:21:12:21:48 | parseInt(...) : Number |
| ArithmeticTainted.java:21:29:21:47 | trim(...) : String | ArithmeticTainted.java:32:17:32:20 | data |
| ArithmeticTainted.java:21:29:21:47 | trim(...) : String | ArithmeticTainted.java:40:17:40:20 | data |
| ArithmeticTainted.java:21:29:21:47 | trim(...) : String | ArithmeticTainted.java:50:17:50:20 | data |
@@ -64,8 +53,6 @@ nodes
| ArithmeticTainted.java:19:26:19:39 | readerBuffered : BufferedReader | semmle.label | readerBuffered : BufferedReader |
| ArithmeticTainted.java:19:26:19:50 | readLine(...) : String | semmle.label | readLine(...) : String |
| ArithmeticTainted.java:19:26:19:50 | readLine(...) : String | semmle.label | readLine(...) : String |
-| ArithmeticTainted.java:21:12:21:48 | parseInt(...) : Number | semmle.label | parseInt(...) : Number |
-| ArithmeticTainted.java:21:12:21:48 | parseInt(...) : Number | semmle.label | parseInt(...) : Number |
| ArithmeticTainted.java:21:29:21:40 | stringNumber : String | semmle.label | stringNumber : String |
| ArithmeticTainted.java:21:29:21:40 | stringNumber : String | semmle.label | stringNumber : String |
| ArithmeticTainted.java:21:29:21:47 | trim(...) : String | semmle.label | trim(...) : String |
diff --git a/java/ql/test/query-tests/security/CWE-681/semmle/tests/NumericCastTaintedLocal.expected b/java/ql/test/query-tests/security/CWE-681/semmle/tests/NumericCastTaintedLocal.expected
index 7a9330e8220..6ab99919c33 100644
--- a/java/ql/test/query-tests/security/CWE-681/semmle/tests/NumericCastTaintedLocal.expected
+++ b/java/ql/test/query-tests/security/CWE-681/semmle/tests/NumericCastTaintedLocal.expected
@@ -4,9 +4,7 @@ edges
| Test.java:11:28:11:36 | System.in : InputStream | Test.java:11:6:11:46 | new InputStreamReader(...) : InputStreamReader |
| Test.java:12:26:12:39 | readerBuffered : BufferedReader | Test.java:12:26:12:50 | readLine(...) : String |
| Test.java:12:26:12:50 | readLine(...) : String | Test.java:14:27:14:38 | stringNumber : String |
-| Test.java:14:12:14:46 | parseLong(...) : Number | Test.java:21:22:21:25 | data |
| Test.java:14:27:14:38 | stringNumber : String | Test.java:14:27:14:45 | trim(...) : String |
-| Test.java:14:27:14:45 | trim(...) : String | Test.java:14:12:14:46 | parseLong(...) : Number |
| Test.java:14:27:14:45 | trim(...) : String | Test.java:21:22:21:25 | data |
nodes
| Test.java:10:36:11:47 | new BufferedReader(...) : BufferedReader | semmle.label | new BufferedReader(...) : BufferedReader |
@@ -14,7 +12,6 @@ nodes
| Test.java:11:28:11:36 | System.in : InputStream | semmle.label | System.in : InputStream |
| Test.java:12:26:12:39 | readerBuffered : BufferedReader | semmle.label | readerBuffered : BufferedReader |
| Test.java:12:26:12:50 | readLine(...) : String | semmle.label | readLine(...) : String |
-| Test.java:14:12:14:46 | parseLong(...) : Number | semmle.label | parseLong(...) : Number |
| Test.java:14:27:14:38 | stringNumber : String | semmle.label | stringNumber : String |
| Test.java:14:27:14:45 | trim(...) : String | semmle.label | trim(...) : String |
| Test.java:21:22:21:25 | data | semmle.label | data |
From 994ea704dae252ddc7937abc827ca30b56adfbea Mon Sep 17 00:00:00 2001
From: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
Date: Thu, 12 Jan 2023 09:31:48 +0000
Subject: [PATCH 201/381] Swift: Clean up the QL a little.
---
.../queries/Security/CWE-311/CleartextStorageDatabase.ql | 7 +++----
1 file changed, 3 insertions(+), 4 deletions(-)
diff --git a/swift/ql/src/queries/Security/CWE-311/CleartextStorageDatabase.ql b/swift/ql/src/queries/Security/CWE-311/CleartextStorageDatabase.ql
index 2eddbeeedaf..bd72c904745 100644
--- a/swift/ql/src/queries/Security/CWE-311/CleartextStorageDatabase.ql
+++ b/swift/ql/src/queries/Security/CWE-311/CleartextStorageDatabase.ql
@@ -93,10 +93,9 @@ class CleartextStorageConfig extends TaintTracking::Configuration {
// for example in `realmObj.data = sensitive`.
isSink(node) and
exists(ClassOrStructDecl cd, IterableDeclContext cx |
- (cx = cd or cx.(ExtensionDecl).getExtendedTypeDecl() = cd) and
- c.getAReadContent().(DataFlow::Content::FieldContent).getField() = cx.getAMember() and
- // TODO: add a `getAMember` version that accounts for extensions?
- cd.getABaseTypeDecl*().getName() = ["NSManagedObject", "RealmSwiftObject"]
+ cd.getABaseTypeDecl*().getName() = ["NSManagedObject", "RealmSwiftObject"] and
+ cx.getNominalTypeDecl() = cd and
+ c.getAReadContent().(DataFlow::Content::FieldContent).getField() = cx.getAMember()
)
or
// any default implicit reads
From 1ae52b6c7ede31138ac1bff8a516d7816fae24d4 Mon Sep 17 00:00:00 2001
From: Mathias Vorreiter Pedersen
Date: Thu, 12 Jan 2023 10:06:39 +0000
Subject: [PATCH 202/381] C++: Speedup 'MissingCheckScanf'.
---
cpp/ql/src/Critical/MissingCheckScanf.ql | 255 ++++++++++++++++-------
1 file changed, 179 insertions(+), 76 deletions(-)
diff --git a/cpp/ql/src/Critical/MissingCheckScanf.ql b/cpp/ql/src/Critical/MissingCheckScanf.ql
index 29f1c2b07ad..5d81a3f9e49 100644
--- a/cpp/ql/src/Critical/MissingCheckScanf.ql
+++ b/cpp/ql/src/Critical/MissingCheckScanf.ql
@@ -20,81 +20,187 @@ import semmle.code.cpp.dataflow.DataFlow
import semmle.code.cpp.ir.IR
import semmle.code.cpp.ir.ValueNumbering
-/** An expression appearing as an output argument to a `scanf`-like call */
-class ScanfOutput extends Expr {
- ScanfFunctionCall call;
- int varargIndex;
- Instruction instr;
- ValueNumber valNum;
+/**
+ * Holds if `call` is a `scanf`-like function that may write to `output` at index `index`.
+ *
+ * Furthermore, `instr` is the instruction that defines the address of the `index`'th argument
+ * of `call`, and `vn` is the value number of `instr.`
+ */
+predicate isSource(ScanfFunctionCall call, int index, Instruction instr, ValueNumber vn, Expr output) {
+ output = call.getOutputArgument(index).getFullyConverted() and
+ instr.getConvertedResultExpression() = output and
+ vn.getAnInstruction() = instr
+}
- ScanfOutput() {
- this = call.getOutputArgument(varargIndex).getFullyConverted() and
- instr.getConvertedResultExpression() = this and
- valueNumber(instr) = valNum
- }
+/**
+ * Holds if `instr` is control-flow reachable in 0 or more steps from an a call
+ * to a call to a `scanf`-like function.
+ */
+pragma[nomagic]
+predicate fwdFlow0(Instruction instr) {
+ isSource(_, _, instr, _, _)
+ or
+ exists(Instruction prev |
+ fwdFlow0(prev) and
+ prev.getASuccessor() = instr
+ )
+}
- ScanfFunctionCall getCall() { result = call }
+/**
+ * Holds if `instr` is part of the IR translation of `access` that
+ * is not an expression being deallocated, and `instr` has value
+ * number `vn`.
+ */
+predicate isSink(Instruction instr, Access access, ValueNumber vn) {
+ instr.getAst() = access and
+ not any(DeallocationExpr dealloc).getFreedExpr() = access and
+ vn.getAnInstruction() = instr
+}
- /**
- * Returns the smallest possible `scanf` return value that would indicate
- * success in writing this output argument.
- */
- int getMinimumGuardConstant() {
- result =
- varargIndex + 1 -
- count(ScanfFormatLiteral f, int n |
- // Special case: %n writes to an argument without reading any input.
- // It does not increase the count returned by `scanf`.
- n <= varargIndex and f.getUse() = call and f.getConversionChar(n) = "n"
- )
- }
-
- predicate hasGuardedAccess(Access e, boolean isGuarded) {
- e = this.getAnAccess() and
- if
- exists(int value, int minGuard | minGuard = this.getMinimumGuardConstant() |
- e.getBasicBlock() = blockGuardedBy(value, "==", call) and minGuard <= value
- or
- e.getBasicBlock() = blockGuardedBy(value, "<", call) and minGuard - 1 <= value
- or
- e.getBasicBlock() = blockGuardedBy(value, "<=", call) and minGuard <= value
- )
- then isGuarded = true
- else isGuarded = false
- }
-
- /**
- * Get a subsequent access of the same underlying storage,
- * but before it gets reset or reused in another `scanf` call.
- */
- Access getAnAccess() {
- exists(Instruction dst |
- this.bigStep() = dst and
- dst.getAst() = result and
- valueNumber(dst) = valNum
- )
- }
-
- private Instruction bigStep() {
- result = this.smallStep(instr)
+/**
+ * Holds if `instr` is part of a path from a call to a `scanf`-like function
+ * to a use of the written variable.
+ */
+pragma[nomagic]
+predicate revFlow0(Instruction instr) {
+ fwdFlow0(instr) and
+ (
+ isSink(instr, _, _)
or
- exists(Instruction i | i = this.bigStep() | result = this.smallStep(i))
- }
+ exists(Instruction succ | revFlow0(succ) | instr.getASuccessor() = succ)
+ )
+}
- private Instruction smallStep(Instruction i) {
- instr.getASuccessor*() = i and
- i.getASuccessor() = result and
- not this.isBarrier(result)
- }
-
- private predicate isBarrier(Instruction i) {
- valueNumber(i) = valNum and
- exists(Expr e | i.getAst() = e |
- i = any(StoreInstruction s).getDestinationAddress()
- or
- [e, e.getParent().(AddressOfExpr)] instanceof ScanfOutput
+/**
+ * Holds if `instr` is part of a path from a call `to a `scanf`-like function
+ * that writes to a variable with value number `vn`, without passing through
+ * redefinitions of the variable.
+ */
+pragma[nomagic]
+private predicate fwdFlow(Instruction instr, ValueNumber vn) {
+ revFlow0(instr) and
+ (
+ isSource(_, _, instr, vn, _)
+ or
+ exists(Instruction prev |
+ fwdFlow(prev, vn) and
+ prev.getASuccessor() = instr and
+ not isBarrier(instr, vn)
)
- }
+ )
+}
+
+/**
+ * Holds if `instr` is part of a path from a call `to a `scanf`-like function
+ * that writes to a variable with value number `vn`, without passing through
+ * redefinitions of the variable.
+ */
+pragma[nomagic]
+predicate revFlow(Instruction instr, ValueNumber vn) {
+ fwdFlow(instr, vn) and
+ (
+ isSink(instr, _, vn)
+ or
+ exists(Instruction succ | revFlow(succ, vn) |
+ instr.getASuccessor() = succ and
+ not isBarrier(succ, vn)
+ )
+ )
+}
+
+/**
+ * A type that bundles together a reachable instruction with the appropriate
+ * value number (i.e., the value number that's transferred from the source
+ * to the sink).
+ */
+newtype TNode = MkNode(Instruction instr, ValueNumber vn) { revFlow(instr, vn) }
+
+class Node extends MkNode {
+ ValueNumber vn;
+ Instruction instr;
+
+ Node() { this = MkNode(instr, vn) }
+
+ final string toString() { result = instr.toString() }
+
+ final Node getASuccessor() { result = MkNode(instr.getASuccessor(), vn) }
+
+ final Location getLocation() { result = instr.getLocation() }
+}
+
+/**
+ * Holds if `instr` is an instruction with value number `vn` that is
+ * used in a store operation, or is overwritten by another call to
+ * a `scanf`-like function.
+ */
+private predicate isBarrier(Instruction instr, ValueNumber vn) {
+ // We only need to compute barriers for instructions that we
+ // managed to hit during the initial flow stage.
+ revFlow0(pragma[only_bind_into](instr)) and
+ valueNumber(instr) = vn and
+ exists(Expr e | instr.getAst() = e |
+ instr = any(StoreInstruction s).getDestinationAddress()
+ or
+ isSource(_, _, _, _, [e, e.getParent().(AddressOfExpr)])
+ )
+}
+
+/** Holds if `n1` steps to `n2` in a single step. */
+predicate isSuccessor(Node n1, Node n2) { n1.getASuccessor() = n2 }
+
+predicate hasFlow(Node n1, Node n2) = fastTC(isSuccessor/2)(n1, n2)
+
+Node getNode(Instruction instr, ValueNumber vn) { result = MkNode(instr, vn) }
+
+/**
+ * Holds if `source` is the `index`'th argument to the `scanf`-like call `call`, and `sink` is
+ * an instruction that is part of the translation of `access` which is a transitive
+ * control-flow successor of `call`.
+ *
+ * Furthermore, `source` and `sink` have identical global value numbers.
+ */
+predicate hasFlow(
+ Instruction source, ScanfFunctionCall call, int index, Instruction sink, Access access
+) {
+ exists(ValueNumber vn |
+ isSource(call, index, source, vn, _) and
+ hasFlow(getNode(source, vn), getNode(sink, vn)) and
+ isSink(sink, access, vn)
+ )
+}
+
+/**
+ * Gets the smallest possible `scanf` return value of `call` that would indicate
+ * success in writing the output argument at index `index`.
+ */
+int getMinimumGuardConstant(ScanfFunctionCall call, int index) {
+ isSource(call, index, _, _, _) and
+ result =
+ index + 1 -
+ count(ScanfFormatLiteral f, int n |
+ // Special case: %n writes to an argument without reading any input.
+ // It does not increase the count returned by `scanf`.
+ n <= index and f.getUse() = call and f.getConversionChar(n) = "n"
+ )
+}
+
+/**
+ * Holds the access to `e` isn't guarded by a check that ensures that `call` returned
+ * at least `minGuard`.
+ */
+predicate hasNonGuardedAccess(ScanfFunctionCall call, Access e, int minGuard) {
+ exists(int index |
+ hasFlow(_, call, index, _, e) and
+ minGuard = getMinimumGuardConstant(call, index)
+ |
+ not exists(int value |
+ e.getBasicBlock() = blockGuardedBy(value, "==", call) and minGuard <= value
+ or
+ e.getBasicBlock() = blockGuardedBy(value, "<", call) and minGuard - 1 <= value
+ or
+ e.getBasicBlock() = blockGuardedBy(value, "<=", call) and minGuard <= value
+ )
+ )
}
/** Returns a block guarded by the assertion of `value op call` */
@@ -112,12 +218,9 @@ BasicBlock blockGuardedBy(int value, string op, ScanfFunctionCall call) {
)
}
-from ScanfOutput output, ScanfFunctionCall call, Access access
-where
- output.getCall() = call and
- output.hasGuardedAccess(access, false) and
- not exists(DeallocationExpr dealloc | dealloc.getFreedExpr() = access)
+from ScanfFunctionCall call, Access access, int minGuard
+where hasNonGuardedAccess(call, access, minGuard)
select access,
"This variable is read, but may not have been written. " +
- "It should be guarded by a check that the $@ returns at least " +
- output.getMinimumGuardConstant() + ".", call, call.toString()
+ "It should be guarded by a check that the $@ returns at least " + minGuard + ".", call,
+ call.toString()
From 0f993a0d267fe9d358afb7c482ace11767273bdb Mon Sep 17 00:00:00 2001
From: Michael Nebel
Date: Mon, 19 Dec 2022 13:48:04 +0100
Subject: [PATCH 203/381] Go: Prepare library for adding extensions.
---
go/ql/lib/qlpack.yml | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/go/ql/lib/qlpack.yml b/go/ql/lib/qlpack.yml
index a38974a0fd9..140062a39fe 100644
--- a/go/ql/lib/qlpack.yml
+++ b/go/ql/lib/qlpack.yml
@@ -7,4 +7,5 @@ library: true
upgrades: upgrades
dependencies:
codeql/tutorial: ${workspace}
-
+dataExtensions:
+ - ext/*.model.yml
From 5fd687d3df78b818415b4da908b02f943fcc3204 Mon Sep 17 00:00:00 2001
From: Michael Nebel
Date: Mon, 19 Dec 2022 13:48:44 +0100
Subject: [PATCH 204/381] Go: Add MaD related extensible predicates.
---
go/ql/lib/semmle/go/dataflow/ExternalFlow.qll | 1 +
.../go/dataflow/ExternalFlowExtensions.qll | 27 +++++++++++++++++++
2 files changed, 28 insertions(+)
create mode 100644 go/ql/lib/semmle/go/dataflow/ExternalFlowExtensions.qll
diff --git a/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll b/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll
index f3213e78627..1392f849201 100644
--- a/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll
+++ b/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll
@@ -61,6 +61,7 @@
*/
private import go
+private import ExternalFlowExtensions as Extensions
private import internal.DataFlowPrivate
private import internal.FlowSummaryImpl::Private::External
private import internal.FlowSummaryImplSpecific
diff --git a/go/ql/lib/semmle/go/dataflow/ExternalFlowExtensions.qll b/go/ql/lib/semmle/go/dataflow/ExternalFlowExtensions.qll
new file mode 100644
index 00000000000..24a8ddf4b8d
--- /dev/null
+++ b/go/ql/lib/semmle/go/dataflow/ExternalFlowExtensions.qll
@@ -0,0 +1,27 @@
+/**
+ * This module provides extensible predicates for defining MaD models.
+ */
+
+/**
+ * Holds if a source model exists for the given parameters.
+ */
+extensible predicate sourceModel(
+ string package, string type, boolean subtypes, string name, string signature, string ext,
+ string output, string kind, string provenance
+);
+
+/**
+ * Holds if a sink model exists for the given parameters.
+ */
+extensible predicate sinkModel(
+ string package, string type, boolean subtypes, string name, string signature, string ext,
+ string input, string kind, string provenance
+);
+
+/**
+ * Holds if a summary model exists for the given parameters.
+ */
+extensible predicate summaryModel(
+ string package, string type, boolean subtypes, string name, string signature, string ext,
+ string input, string output, string kind, string provenance
+);
From ebb3485a7343b2683559e2a88c7b481555a841ba Mon Sep 17 00:00:00 2001
From: Michael Nebel
Date: Mon, 19 Dec 2022 14:39:58 +0100
Subject: [PATCH 205/381] Go: Use the extensible predicates for model
definitions.
---
go/ql/lib/ext/builtin.model.yml | 7 ++
go/ql/lib/ext/dummy.model.yml | 14 ++++
go/ql/lib/semmle/go/dataflow/ExternalFlow.qll | 68 +------------------
3 files changed, 24 insertions(+), 65 deletions(-)
create mode 100644 go/ql/lib/ext/builtin.model.yml
create mode 100644 go/ql/lib/ext/dummy.model.yml
diff --git a/go/ql/lib/ext/builtin.model.yml b/go/ql/lib/ext/builtin.model.yml
new file mode 100644
index 00000000000..f4e7a4e5348
--- /dev/null
+++ b/go/ql/lib/ext/builtin.model.yml
@@ -0,0 +1,7 @@
+extensions:
+ - addsTo:
+ pack: codeql/go-all
+ extensible: summaryModel
+ data:
+ - ["", "", False, "append", "", "", "Argument[0].ArrayElement", "ReturnValue.ArrayElement", "value", "manual"]
+ - ["", "", False, "append", "", "", "Argument[1]", "ReturnValue.ArrayElement", "value", "manual"]
\ No newline at end of file
diff --git a/go/ql/lib/ext/dummy.model.yml b/go/ql/lib/ext/dummy.model.yml
new file mode 100644
index 00000000000..e04298be8ba
--- /dev/null
+++ b/go/ql/lib/ext/dummy.model.yml
@@ -0,0 +1,14 @@
+extensions:
+ # Make sure that the extensible model predicates are at least defined as empty.
+ - addsTo:
+ pack: codeql/go-all
+ extensible: sourceModel
+ data: []
+ - addsTo:
+ pack: codeql/go-all
+ extensible: sinkModel
+ data: []
+ - addsTo:
+ pack: codeql/go-all
+ extensible: summaryModel
+ data: []
diff --git a/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll b/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll
index 1392f849201..f4af6784f49 100644
--- a/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll
+++ b/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll
@@ -76,16 +76,6 @@ private module Frameworks {
private import semmle.go.frameworks.Stdlib
}
-private class BuiltinModel extends SummaryModelCsv {
- override predicate row(string row) {
- row =
- [
- ";;false;append;;;Argument[0].ArrayElement;ReturnValue.ArrayElement;value",
- ";;false;append;;;Argument[1];ReturnValue.ArrayElement;value"
- ]
- }
-}
-
/**
* A unit class for adding additional source model rows.
*
@@ -126,65 +116,13 @@ predicate sinkModel(string row) { any(SinkModelCsv s).row(row) }
predicate summaryModel(string row) { any(SummaryModelCsv s).row(row) }
/** Holds if a source model exists for the given parameters. */
-predicate sourceModel(
- string namespace, string type, boolean subtypes, string name, string signature, string ext,
- string output, string kind, string provenance
-) {
- exists(string row |
- sourceModel(row) and
- row.splitAt(";", 0) = namespace and
- row.splitAt(";", 1) = type and
- row.splitAt(";", 2) = subtypes.toString() and
- subtypes = [true, false] and
- row.splitAt(";", 3) = name and
- row.splitAt(";", 4) = signature and
- row.splitAt(";", 5) = ext and
- row.splitAt(";", 6) = output and
- row.splitAt(";", 7) = kind and
- provenance = "manual"
- )
-}
+predicate sourceModel = Extensions::sourceModel/9;
/** Holds if a sink model exists for the given parameters. */
-predicate sinkModel(
- string namespace, string type, boolean subtypes, string name, string signature, string ext,
- string input, string kind, string provenance
-) {
- exists(string row |
- sinkModel(row) and
- row.splitAt(";", 0) = namespace and
- row.splitAt(";", 1) = type and
- row.splitAt(";", 2) = subtypes.toString() and
- subtypes = [true, false] and
- row.splitAt(";", 3) = name and
- row.splitAt(";", 4) = signature and
- row.splitAt(";", 5) = ext and
- row.splitAt(";", 6) = input and
- row.splitAt(";", 7) = kind and
- provenance = "manual"
- )
-}
+predicate sinkModel = Extensions::sinkModel/9;
/** Holds if a summary model exists for the given parameters. */
-predicate summaryModel(
- string namespace, string type, boolean subtypes, string name, string signature, string ext,
- string input, string output, string kind, string provenance
-) {
- exists(string row |
- summaryModel(row) and
- row.splitAt(";", 0) = namespace and
- row.splitAt(";", 1) = type and
- row.splitAt(";", 2) = subtypes.toString() and
- subtypes = [true, false] and
- row.splitAt(";", 3) = name and
- row.splitAt(";", 4) = signature and
- row.splitAt(";", 5) = ext and
- row.splitAt(";", 6) = input and
- row.splitAt(";", 7) = output and
- row.splitAt(";", 8) = kind
- ) and
- provenance = "manual"
-}
+predicate summaryModel = Extensions::summaryModel/10;
/** Holds if `package` have CSV framework coverage. */
private predicate packageHasCsvCoverage(string package) {
From 218f553fef32af45d425a0708dfeb215673d8679 Mon Sep 17 00:00:00 2001
From: Michael Nebel
Date: Mon, 19 Dec 2022 14:42:38 +0100
Subject: [PATCH 206/381] Go: Convert remaining CSV production models to use
data extensions.
---
go/ql/lib/ext/archive_tar.model.yml | 6 ++++++
go/ql/lib/ext/net_http.model.yml | 13 +++++++++++++
.../semmle/go/frameworks/stdlib/ArchiveTar.qll | 7 -------
.../lib/semmle/go/frameworks/stdlib/NetHttp.qll | 17 -----------------
4 files changed, 19 insertions(+), 24 deletions(-)
create mode 100644 go/ql/lib/ext/archive_tar.model.yml
create mode 100644 go/ql/lib/ext/net_http.model.yml
diff --git a/go/ql/lib/ext/archive_tar.model.yml b/go/ql/lib/ext/archive_tar.model.yml
new file mode 100644
index 00000000000..9b8fd572bf3
--- /dev/null
+++ b/go/ql/lib/ext/archive_tar.model.yml
@@ -0,0 +1,6 @@
+extensions:
+ - addsTo:
+ pack: codeql/go-all
+ extensible: summaryModel
+ data:
+ - ["archive/tar", "", True, "FileInfoHeader", "", "", "Argument[0]", "ReturnValue[0]", "taint", "manual"]
\ No newline at end of file
diff --git a/go/ql/lib/ext/net_http.model.yml b/go/ql/lib/ext/net_http.model.yml
new file mode 100644
index 00000000000..0b686cfb432
--- /dev/null
+++ b/go/ql/lib/ext/net_http.model.yml
@@ -0,0 +1,13 @@
+extensions:
+ - addsTo:
+ pack: codeql/go-all
+ extensible: sourceModel
+ data:
+ - ["net/http", "Request", True, "Cookie", "", "", "ReturnValue[0]", "remote", "manual"]
+ - ["net/http", "Request", True, "Cookies", "", "", "ReturnValue.ArrayElement", "remote", "manual"]
+ - ["net/http", "Request", True, "FormFile", "", "", "ReturnValue[0..1]", "remote", "manual"]
+ - ["net/http", "Request", True, "FormValue", "", "", "ReturnValue", "remote", "manual"]
+ - ["net/http", "Request", True, "MultipartReader", "", "", "ReturnValue[0]", "remote", "manual"]
+ - ["net/http", "Request", True, "PostFormValue", "", "", "ReturnValue", "remote", "manual"]
+ - ["net/http", "Request", True, "Referer", "", "", "ReturnValue", "remote", "manual"]
+ - ["net/http", "Request", True, "UserAgent", "", "", "ReturnValue", "remote", "manual"]
diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/ArchiveTar.qll b/go/ql/lib/semmle/go/frameworks/stdlib/ArchiveTar.qll
index ef2d3b6446f..81bae84c052 100644
--- a/go/ql/lib/semmle/go/frameworks/stdlib/ArchiveTar.qll
+++ b/go/ql/lib/semmle/go/frameworks/stdlib/ArchiveTar.qll
@@ -3,13 +3,6 @@
*/
import go
-private import semmle.go.dataflow.ExternalFlow
-
-private class FlowSummaries extends SummaryModelCsv {
- override predicate row(string row) {
- row = ["archive/tar;;true;FileInfoHeader;;;Argument[0];ReturnValue[0];taint"]
- }
-}
/** Provides models of commonly used functions in the `archive/tar` package. */
module ArchiveTar {
diff --git a/go/ql/lib/semmle/go/frameworks/stdlib/NetHttp.qll b/go/ql/lib/semmle/go/frameworks/stdlib/NetHttp.qll
index e0518ecf465..12eee7079f7 100644
--- a/go/ql/lib/semmle/go/frameworks/stdlib/NetHttp.qll
+++ b/go/ql/lib/semmle/go/frameworks/stdlib/NetHttp.qll
@@ -3,23 +3,6 @@
*/
import go
-private import semmle.go.dataflow.ExternalFlow
-
-private class FlowSources extends SourceModelCsv {
- override predicate row(string row) {
- row =
- [
- "net/http;Request;true;Cookie;;;ReturnValue[0];remote",
- "net/http;Request;true;Cookies;;;ReturnValue.ArrayElement;remote",
- "net/http;Request;true;FormFile;;;ReturnValue[0..1];remote",
- "net/http;Request;true;FormValue;;;ReturnValue;remote",
- "net/http;Request;true;MultipartReader;;;ReturnValue[0];remote",
- "net/http;Request;true;PostFormValue;;;ReturnValue;remote",
- "net/http;Request;true;Referer;;;ReturnValue;remote",
- "net/http;Request;true;UserAgent;;;ReturnValue;remote"
- ]
- }
-}
/** Provides models of commonly used functions in the `net/http` package. */
module NetHttp {
From 3749a1bd4df15d3e715f4d839d0feddf009a88ac Mon Sep 17 00:00:00 2001
From: Michael Nebel
Date: Mon, 19 Dec 2022 15:11:27 +0100
Subject: [PATCH 207/381] Go: Migrate unit tests to use data extensions for
Models as Data.
---
.../ExternalFlow/completetest.ext.yml | 38 ++++++++++++++
.../go/dataflow/ExternalFlow/completetest.ql | 50 -------------------
.../go/dataflow/ExternalFlow/sinks.ext.yml | 8 +++
.../semmle/go/dataflow/ExternalFlow/sinks.ql | 12 -----
.../go/dataflow/ExternalFlow/srcs.ext.yml | 11 ++++
.../semmle/go/dataflow/ExternalFlow/srcs.ql | 15 ------
.../go/dataflow/ExternalFlow/steps.ext.yml | 14 ++++++
.../semmle/go/dataflow/ExternalFlow/steps.ql | 18 -------
.../ExternalFlowVarArgs/Flows.ext.yml | 10 ++++
.../go/dataflow/ExternalFlowVarArgs/Flows.ql | 14 ------
10 files changed, 81 insertions(+), 109 deletions(-)
create mode 100644 go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/completetest.ext.yml
create mode 100644 go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/sinks.ext.yml
create mode 100644 go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/srcs.ext.yml
create mode 100644 go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/steps.ext.yml
create mode 100644 go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowVarArgs/Flows.ext.yml
diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/completetest.ext.yml b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/completetest.ext.yml
new file mode 100644
index 00000000000..79ca023562c
--- /dev/null
+++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/completetest.ext.yml
@@ -0,0 +1,38 @@
+extensions:
+ - addsTo:
+ pack: codeql/go-all
+ extensible: summaryModel
+ data:
+ - ["github.com/nonexistent/test", "T", False, "StepArgRes", "", "", "Argument[0]", "ReturnValue", "taint", "manual"]
+ - ["github.com/nonexistent/test", "T", False, "StepArgRes1", "", "", "Argument[0]", "ReturnValue[1]", "taint", "manual"]
+ - ["github.com/nonexistent/test", "T", False, "StepArgArg", "", "", "Argument[0]", "Argument[1]", "taint", "manual"]
+ - ["github.com/nonexistent/test", "T", False, "StepArgQual", "", "", "Argument[0]", "Argument[-1]", "taint", "manual"]
+ - ["github.com/nonexistent/test", "T", False, "StepQualRes", "", "", "Argument[-1]", "ReturnValue", "taint", "manual"]
+ - ["github.com/nonexistent/test", "T", False, "StepQualArg", "", "", "Argument[-1]", "Argument[0]", "taint", "manual"]
+ - ["github.com/nonexistent/test", "", False, "StepArgResNoQual", "", "", "Argument[0]", "ReturnValue", "taint", "manual"]
+ - ["github.com/nonexistent/test", "", False, "StepArgResArrayContent", "", "", "Argument[0]", "ReturnValue.ArrayElement", "taint", "manual"]
+ - ["github.com/nonexistent/test", "", False, "StepArgArrayContentRes", "", "", "Argument[0].ArrayElement", "ReturnValue", "taint", "manual"]
+ - ["github.com/nonexistent/test", "", False, "StepArgResCollectionContent", "", "", "Argument[0]", "ReturnValue.Element", "taint", "manual"]
+ - ["github.com/nonexistent/test", "", False, "StepArgCollectionContentRes", "", "", "Argument[0].Element", "ReturnValue", "taint", "manual"]
+ - ["github.com/nonexistent/test", "", False, "StepArgResMapKeyContent", "", "", "Argument[0]", "ReturnValue.MapKey", "taint", "manual"]
+ - ["github.com/nonexistent/test", "", False, "StepArgMapKeyContentRes", "", "", "Argument[0].MapKey", "ReturnValue", "taint", "manual"]
+ - ["github.com/nonexistent/test", "", False, "StepArgResMapValueContent", "", "", "Argument[0]", "ReturnValue.MapValue", "taint", "manual"]
+ - ["github.com/nonexistent/test", "", False, "StepArgMapValueContentRes", "", "", "Argument[0].MapValue", "ReturnValue", "taint", "manual"]
+ - ["github.com/nonexistent/test", "", False, "GetElement", "", "", "Argument[0].Element", "ReturnValue", "value", "manual"]
+ - ["github.com/nonexistent/test", "", False, "GetMapKey", "", "", "Argument[0].MapKey", "ReturnValue", "value", "manual"]
+ - ["github.com/nonexistent/test", "", False, "SetElement", "", "", "Argument[0]", "ReturnValue.Element", "value", "manual"]
+ - ["github.com/nonexistent/test", "C", False, "Get", "", "", "Argument[-1].Field[github.com/nonexistent/test.C.F]", "ReturnValue", "value", "manual"]
+ - ["github.com/nonexistent/test", "C", False, "Set", "", "", "Argument[0]", "Argument[-1].Field[github.com/nonexistent/test.C.F]", "value", "manual"]
+
+ - addsTo:
+ pack: codeql/go-all
+ extensible: sourceModel
+ data:
+ - ["github.com/nonexistent/test", "A", False, "Src1", "", "", "ReturnValue", "qltest", "manual"]
+
+ - addsTo:
+ pack: codeql/go-all
+ extensible: sinkModel
+ data:
+ - ["github.com/nonexistent/test", "B", False, "Sink1", "", "", "Argument[0]", "qltest", "manual"]
+ - ["github.com/nonexistent/test", "B", False, "SinkManyArgs", "", "", "Argument[0..2]", "qltest", "manual"]
diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/completetest.ql b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/completetest.ql
index 6554f5c5ec0..45e67564e06 100644
--- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/completetest.ql
+++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/completetest.ql
@@ -8,56 +8,6 @@ import CsvValidation
import semmle.go.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
import TestUtilities.InlineFlowTest
-class SummaryModelTest extends SummaryModelCsv {
- override predicate row(string row) {
- row =
- [
- //`namespace; type; subtypes; name; signature; ext; input; output; kind`
- "github.com/nonexistent/test;T;false;StepArgRes;;;Argument[0];ReturnValue;taint",
- "github.com/nonexistent/test;T;false;StepArgRes1;;;Argument[0];ReturnValue[1];taint",
- "github.com/nonexistent/test;T;false;StepArgArg;;;Argument[0];Argument[1];taint",
- "github.com/nonexistent/test;T;false;StepArgQual;;;Argument[0];Argument[-1];taint",
- "github.com/nonexistent/test;T;false;StepQualRes;;;Argument[-1];ReturnValue;taint",
- "github.com/nonexistent/test;T;false;StepQualArg;;;Argument[-1];Argument[0];taint",
- "github.com/nonexistent/test;;false;StepArgResNoQual;;;Argument[0];ReturnValue;taint",
- "github.com/nonexistent/test;;false;StepArgResArrayContent;;;Argument[0];ReturnValue.ArrayElement;taint",
- "github.com/nonexistent/test;;false;StepArgArrayContentRes;;;Argument[0].ArrayElement;ReturnValue;taint",
- "github.com/nonexistent/test;;false;StepArgResCollectionContent;;;Argument[0];ReturnValue.Element;taint",
- "github.com/nonexistent/test;;false;StepArgCollectionContentRes;;;Argument[0].Element;ReturnValue;taint",
- "github.com/nonexistent/test;;false;StepArgResMapKeyContent;;;Argument[0];ReturnValue.MapKey;taint",
- "github.com/nonexistent/test;;false;StepArgMapKeyContentRes;;;Argument[0].MapKey;ReturnValue;taint",
- "github.com/nonexistent/test;;false;StepArgResMapValueContent;;;Argument[0];ReturnValue.MapValue;taint",
- "github.com/nonexistent/test;;false;StepArgMapValueContentRes;;;Argument[0].MapValue;ReturnValue;taint",
- "github.com/nonexistent/test;;false;GetElement;;;Argument[0].Element;ReturnValue;value",
- "github.com/nonexistent/test;;false;GetMapKey;;;Argument[0].MapKey;ReturnValue;value",
- "github.com/nonexistent/test;;false;SetElement;;;Argument[0];ReturnValue.Element;value",
- "github.com/nonexistent/test;C;false;Get;;;Argument[-1].Field[github.com/nonexistent/test.C.F];ReturnValue;value",
- "github.com/nonexistent/test;C;false;Set;;;Argument[0];Argument[-1].Field[github.com/nonexistent/test.C.F];value",
- ]
- }
-}
-
-class SourceModelTest extends SourceModelCsv {
- override predicate row(string row) {
- row =
- [
- //`namespace; type; subtypes; name; -; ext; output; kind`
- "github.com/nonexistent/test;A;false;Src1;;;ReturnValue;qltest"
- ]
- }
-}
-
-class SinkModelTest extends SinkModelCsv {
- override predicate row(string row) {
- row =
- [
- //`namespace; type; subtypes; name; -; ext; input; kind`
- "github.com/nonexistent/test;B;false;Sink1;;;Argument[0];qltest",
- "github.com/nonexistent/test;B;false;SinkManyArgs;;;Argument[0..2];qltest"
- ]
- }
-}
-
class Config extends TaintTracking::Configuration {
Config() { this = "external-flow-test" }
diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/sinks.ext.yml b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/sinks.ext.yml
new file mode 100644
index 00000000000..653f82bae61
--- /dev/null
+++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/sinks.ext.yml
@@ -0,0 +1,8 @@
+extensions:
+ - addsTo:
+ pack: codeql/go-all
+ extensible: sinkModel
+ data:
+ - ["github.com/nonexistent/test", "B", False, "Sink1", "", "", "Argument[0]", "qltest", "manual"]
+ - ["github.com/nonexistent/test", "B", False, "SinkMethod", "", "", "Argument[-1]", "qltest", "manual"]
+ - ["github.com/nonexistent/test", "B", False, "SinkManyArgs", "", "", "Argument[0..2]", "qltest", "manual"]
\ No newline at end of file
diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/sinks.ql b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/sinks.ql
index a95446246c9..48d75ce06e6 100644
--- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/sinks.ql
+++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/sinks.ql
@@ -2,18 +2,6 @@ import go
import semmle.go.dataflow.ExternalFlow
import CsvValidation
-class SinkModelTest extends SinkModelCsv {
- override predicate row(string row) {
- row =
- [
- //`namespace; type; subtypes; name; -; ext; input; kind`
- "github.com/nonexistent/test;B;false;Sink1;;;Argument[0];qltest",
- "github.com/nonexistent/test;B;false;SinkMethod;;;Argument[-1];qltest",
- "github.com/nonexistent/test;B;false;SinkManyArgs;;;Argument[0..2];qltest",
- ]
- }
-}
-
from DataFlow::Node node, string kind
where sinkNode(node, kind)
select node, kind
diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/srcs.ext.yml b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/srcs.ext.yml
new file mode 100644
index 00000000000..5493650132c
--- /dev/null
+++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/srcs.ext.yml
@@ -0,0 +1,11 @@
+extensions:
+ - addsTo:
+ pack: codeql/go-all
+ extensible: sourceModel
+ data:
+ - ["github.com/nonexistent/test", "A", False, "Src1", "", "", "ReturnValue", "qltest", "manual"]
+ - ["github.com/nonexistent/test", "A", False, "Src2", "", "", "ReturnValue", "qltest", "manual"]
+ - ["github.com/nonexistent/test", "A", True, "Src2", "", "", "ReturnValue", "qltest-w-subtypes", "manual"]
+ - ["github.com/nonexistent/test", "A", False, "SrcArg", "", "", "Argument[0]", "qltest-arg", "manual"]
+ - ["github.com/nonexistent/test", "A", False, "Src3", "", "", "ReturnValue[0]", "qltest", "manual"]
+ - ["github.com/nonexistent/test", "A", True, "Src3", "", "", "ReturnValue[1]", "qltest-w-subtypes", "manual"]
\ No newline at end of file
diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/srcs.ql b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/srcs.ql
index 79514cbdc23..cffb909c495 100644
--- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/srcs.ql
+++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/srcs.ql
@@ -2,21 +2,6 @@ import go
import semmle.go.dataflow.ExternalFlow
import CsvValidation
-class SourceModelTest extends SourceModelCsv {
- override predicate row(string row) {
- row =
- [
- //`namespace; type; subtypes; name; -; ext; output; kind`
- "github.com/nonexistent/test;A;false;Src1;;;ReturnValue;qltest",
- "github.com/nonexistent/test;A;false;Src2;;;ReturnValue;qltest",
- "github.com/nonexistent/test;A;true;Src2;;;ReturnValue;qltest-w-subtypes",
- "github.com/nonexistent/test;A;false;SrcArg;;;Argument[0];qltest-arg",
- "github.com/nonexistent/test;A;false;Src3;;;ReturnValue[0];qltest",
- "github.com/nonexistent/test;A;true;Src3;;;ReturnValue[1];qltest-w-subtypes"
- ]
- }
-}
-
from DataFlow::Node node, string kind
where sourceNode(node, kind)
select node, kind
diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/steps.ext.yml b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/steps.ext.yml
new file mode 100644
index 00000000000..f1c5a78ecbf
--- /dev/null
+++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/steps.ext.yml
@@ -0,0 +1,14 @@
+extensions:
+ - addsTo:
+ pack: codeql/go-all
+ extensible: summaryModel
+ data:
+ - ["github.com/nonexistent/test", "T", False, "StepArgRes", "", "", "Argument[0]", "ReturnValue", "taint", "manual"]
+ - ["github.com/nonexistent/test", "T", False, "StepArgRes1", "", "", "Argument[0]", "ReturnValue[1]", "taint", "manual"]
+ - ["github.com/nonexistent/test", "T", False, "StepArgArg", "", "", "Argument[0]", "Argument[1]", "taint", "manual"]
+ - ["github.com/nonexistent/test", "T", False, "StepArgQual", "", "", "Argument[0]", "Argument[-1]", "taint", "manual"]
+ - ["github.com/nonexistent/test", "T", False, "StepQualRes", "", "", "Argument[-1]", "ReturnValue", "taint", "manual"]
+ - ["github.com/nonexistent/test", "T", False, "StepQualArg", "", "", "Argument[-1]", "Argument[0]", "taint", "manual"]
+ - ["github.com/nonexistent/test", "", False, "StepArgResNoQual", "", "", "Argument[0]", "ReturnValue", "taint", "manual"]
+ - ["github.com/nonexistent/test", "", False, "StepArgResContent", "", "", "Argument[0]", "ReturnValue.ArrayElement", "taint", "manual"]
+ - ["github.com/nonexistent/test", "", False, "StepArgContentRes", "", "", "Argument[0].ArrayElement", "ReturnValue", "taint", "manual"]
diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/steps.ql b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/steps.ql
index c6603c5df93..8ae82d104d6 100644
--- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/steps.ql
+++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/steps.ql
@@ -3,24 +3,6 @@ import semmle.go.dataflow.ExternalFlow
import CsvValidation
import semmle.go.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
-class SummaryModelTest extends SummaryModelCsv {
- override predicate row(string row) {
- row =
- [
- //`namespace; type; subtypes; name; -; ext; input; output; kind`
- "github.com/nonexistent/test;T;false;StepArgRes;;;Argument[0];ReturnValue;taint",
- "github.com/nonexistent/test;T;false;StepArgRes1;;;Argument[0];ReturnValue[1];taint",
- "github.com/nonexistent/test;T;false;StepArgArg;;;Argument[0];Argument[1];taint",
- "github.com/nonexistent/test;T;false;StepArgQual;;;Argument[0];Argument[-1];taint",
- "github.com/nonexistent/test;T;false;StepQualRes;;;Argument[-1];ReturnValue;taint",
- "github.com/nonexistent/test;T;false;StepQualArg;;;Argument[-1];Argument[0];taint",
- "github.com/nonexistent/test;;false;StepArgResNoQual;;;Argument[0];ReturnValue;taint",
- "github.com/nonexistent/test;;false;StepArgResContent;;;Argument[0];ReturnValue.ArrayElement;taint",
- "github.com/nonexistent/test;;false;StepArgContentRes;;;Argument[0].ArrayElement;ReturnValue;taint"
- ]
- }
-}
-
from DataFlow::Node node1, DataFlow::Node node2
where FlowSummaryImpl::Private::Steps::summaryThroughStepTaint(node1, node2, _)
select node1, node2
diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowVarArgs/Flows.ext.yml b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowVarArgs/Flows.ext.yml
new file mode 100644
index 00000000000..c4c77087049
--- /dev/null
+++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowVarArgs/Flows.ext.yml
@@ -0,0 +1,10 @@
+extensions:
+ - addsTo:
+ pack: codeql/go-all
+ extensible: summaryModel
+ data:
+ - ["github.com/nonexistent/test", "", False, "FunctionWithParameter", "", "", "Argument[0]", "ReturnValue", "value", "manual"]
+ - ["github.com/nonexistent/test", "", False, "FunctionWithSliceParameter", "", "", "Argument[0].ArrayElement", "ReturnValue", "value", "manual"]
+ - ["github.com/nonexistent/test", "", False, "FunctionWithVarArgsParameter", "", "", "Argument[0].ArrayElement", "ReturnValue", "value", "manual"]
+ - ["github.com/nonexistent/test", "", False, "FunctionWithSliceOfStructsParameter", "", "", "Argument[0].ArrayElement.Field[github.com/nonexistent/test.A.Field]", "ReturnValue", "value", "manual"]
+ - ["github.com/nonexistent/test", "", False, "FunctionWithVarArgsOfStructsParameter", "", "", "Argument[0].ArrayElement.Field[github.com/nonexistent/test.A.Field]", "ReturnValue", "value", "manual"]
diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowVarArgs/Flows.ql b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowVarArgs/Flows.ql
index 278da456bf2..f7c77d944f2 100644
--- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowVarArgs/Flows.ql
+++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowVarArgs/Flows.ql
@@ -3,20 +3,6 @@ import semmle.go.dataflow.ExternalFlow
import CsvValidation
import TestUtilities.InlineExpectationsTest
-class SummaryModelTest extends SummaryModelCsv {
- override predicate row(string row) {
- row =
- [
- //`namespace; type; subtypes; name; signature; ext; input; output; kind`
- "github.com/nonexistent/test;;false;FunctionWithParameter;;;Argument[0];ReturnValue;value",
- "github.com/nonexistent/test;;false;FunctionWithSliceParameter;;;Argument[0].ArrayElement;ReturnValue;value",
- "github.com/nonexistent/test;;false;FunctionWithVarArgsParameter;;;Argument[0].ArrayElement;ReturnValue;value",
- "github.com/nonexistent/test;;false;FunctionWithSliceOfStructsParameter;;;Argument[0].ArrayElement.Field[github.com/nonexistent/test.A.Field];ReturnValue;value",
- "github.com/nonexistent/test;;false;FunctionWithVarArgsOfStructsParameter;;;Argument[0].ArrayElement.Field[github.com/nonexistent/test.A.Field];ReturnValue;value"
- ]
- }
-}
-
class DataConfiguration extends DataFlow::Configuration {
DataConfiguration() { this = "data-configuration" }
From 48d0eccbf6e249095cdfd5cf974e168360931e50 Mon Sep 17 00:00:00 2001
From: Michael Nebel
Date: Mon, 19 Dec 2022 15:43:49 +0100
Subject: [PATCH 208/381] Go: Cleanup and renaming.
---
go/ql/lib/semmle/go/dataflow/ExternalFlow.qll | 153 +++++-------------
.../internal/FlowSummaryImplSpecific.qll | 24 ++-
go/ql/lib/semmle/go/security/FlowSources.qll | 9 +-
.../go/dataflow/ExternalFlow/completetest.ql | 2 +-
.../semmle/go/dataflow/ExternalFlow/sinks.ql | 2 +-
.../semmle/go/dataflow/ExternalFlow/srcs.ql | 2 +-
.../semmle/go/dataflow/ExternalFlow/steps.ql | 2 +-
.../go/dataflow/ExternalFlowVarArgs/Flows.ql | 2 +-
.../VarArgsWithFunctionModels/Flows.ql | 2 +-
9 files changed, 65 insertions(+), 133 deletions(-)
diff --git a/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll b/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll
index f4af6784f49..7fde586838a 100644
--- a/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll
+++ b/go/ql/lib/semmle/go/dataflow/ExternalFlow.qll
@@ -1,19 +1,20 @@
/**
* INTERNAL use only. This is an experimental API subject to change without notice.
*
- * Provides classes and predicates for dealing with flow models specified in CSV format.
+ * Provides classes and predicates for dealing with MaD flow models specified
+ * in data extensions and CSV format.
*
* The CSV specification has the following columns:
* - Sources:
- * `namespace; type; subtypes; name; signature; ext; output; kind`
+ * `package; type; subtypes; name; signature; ext; output; kind; provenance`
* - Sinks:
- * `namespace; type; subtypes; name; signature; ext; input; kind`
+ * `package; type; subtypes; name; signature; ext; input; kind; provenance`
* - Summaries:
- * `namespace; type; subtypes; name; signature; ext; input; output; kind`
+ * `package; type; subtypes; name; signature; ext; input; output; kind; provenance`
*
* The interpretation of a row is similar to API-graphs with a left-to-right
* reading.
- * 1. The `namespace` column selects a package.
+ * 1. The `package` column selects a package.
* 2. The `type` column selects a type within that package.
* 3. The `subtypes` is a boolean that indicates whether to jump to an
* arbitrary subtype of that type.
@@ -76,45 +77,6 @@ private module Frameworks {
private import semmle.go.frameworks.Stdlib
}
-/**
- * A unit class for adding additional source model rows.
- *
- * Extend this class to add additional source definitions.
- */
-class SourceModelCsv extends Unit {
- /** Holds if `row` specifies a source definition. */
- abstract predicate row(string row);
-}
-
-/**
- * A unit class for adding additional sink model rows.
- *
- * Extend this class to add additional sink definitions.
- */
-class SinkModelCsv extends Unit {
- /** Holds if `row` specifies a sink definition. */
- abstract predicate row(string row);
-}
-
-/**
- * A unit class for adding additional summary model rows.
- *
- * Extend this class to add additional flow summary definitions.
- */
-class SummaryModelCsv extends Unit {
- /** Holds if `row` specifies a summary definition. */
- abstract predicate row(string row);
-}
-
-/** Holds if `row` is a source model. */
-predicate sourceModel(string row) { any(SourceModelCsv s).row(row) }
-
-/** Holds if `row` is a sink model. */
-predicate sinkModel(string row) { any(SinkModelCsv s).row(row) }
-
-/** Holds if `row` is a summary model. */
-predicate summaryModel(string row) { any(SummaryModelCsv s).row(row) }
-
/** Holds if a source model exists for the given parameters. */
predicate sourceModel = Extensions::sourceModel/9;
@@ -124,35 +86,35 @@ predicate sinkModel = Extensions::sinkModel/9;
/** Holds if a summary model exists for the given parameters. */
predicate summaryModel = Extensions::summaryModel/10;
-/** Holds if `package` have CSV framework coverage. */
-private predicate packageHasCsvCoverage(string package) {
+/** Holds if `package` have MaD framework coverage. */
+private predicate packageHasMaDCoverage(string package) {
sourceModel(package, _, _, _, _, _, _, _, _) or
sinkModel(package, _, _, _, _, _, _, _, _) or
summaryModel(package, _, _, _, _, _, _, _, _, _)
}
/**
- * Holds if `package` and `subpkg` have CSV framework coverage and `subpkg`
+ * Holds if `package` and `subpkg` have MaD framework coverage and `subpkg`
* is a subpackage of `package`.
*/
private predicate packageHasASubpackage(string package, string subpkg) {
- packageHasCsvCoverage(package) and
- packageHasCsvCoverage(subpkg) and
+ packageHasMaDCoverage(package) and
+ packageHasMaDCoverage(subpkg) and
subpkg.prefix(subpkg.indexOf(".")) = package
}
/**
- * Holds if `package` has CSV framework coverage and it is not a subpackage of
- * any other package with CSV framework coverage.
+ * Holds if `package` has MaD framework coverage and it is not a subpackage of
+ * any other package with MaD framework coverage.
*/
private predicate canonicalPackage(string package) {
- packageHasCsvCoverage(package) and not packageHasASubpackage(_, package)
+ packageHasMaDCoverage(package) and not packageHasASubpackage(_, package)
}
/**
- * Holds if `package` and `subpkg` have CSV framework coverage, `subpkg` is a
+ * Holds if `package` and `subpkg` have MaD framework coverage, `subpkg` is a
* subpackage of `package` (or they are the same), and `package` is not a
- * subpackage of any other package with CSV framework coverage.
+ * subpackage of any other package with MaD framework coverage.
*/
private predicate canonicalPackageHasASubpackage(string package, string subpkg) {
canonicalPackage(package) and
@@ -160,9 +122,9 @@ private predicate canonicalPackageHasASubpackage(string package, string subpkg)
}
/**
- * Holds if CSV framework coverage of `package` is `n` api endpoints of the
+ * Holds if MaD framework coverage of `package` is `n` api endpoints of the
* kind `(kind, part)`, and `pkgs` is the number of subpackages of `package`
- * which have CSV framework coverage (including `package` itself).
+ * which have MaD framework coverage (including `package` itself).
*/
predicate modelCoverage(string package, int pkgs, string kind, string part, int n) {
pkgs = strictcount(string subpkg | canonicalPackageHasASubpackage(package, subpkg)) and
@@ -193,8 +155,8 @@ predicate modelCoverage(string package, int pkgs, string kind, string part, int
)
}
-/** Provides a query predicate to check the CSV data for validation errors. */
-module CsvValidation {
+/** Provides a query predicate to check the MaD models for validation errors. */
+module ModelValidation {
private string getInvalidModelInput() {
exists(string pred, AccessPath input, string part |
sinkModel(_, _, _, _, _, _, input, _, _) and pred = "sink"
@@ -227,57 +189,25 @@ module CsvValidation {
}
private string getInvalidModelKind() {
- exists(string row, string kind | summaryModel(row) |
- kind = row.splitAt(";", 8) and
+ exists(string kind | summaryModel(_, _, _, _, _, _, _, _, kind, _) |
not kind = ["taint", "value"] and
result = "Invalid kind \"" + kind + "\" in summary model."
)
}
- private string getInvalidModelSubtype() {
- exists(string pred, string row |
- sourceModel(row) and pred = "source"
- or
- sinkModel(row) and pred = "sink"
- or
- summaryModel(row) and pred = "summary"
- |
- exists(string b |
- b = row.splitAt(";", 2) and
- not b = ["true", "false"] and
- result = "Invalid boolean \"" + b + "\" in " + pred + " model."
- )
- )
- }
-
- private string getInvalidModelColumnCount() {
- exists(string pred, string row, int expect |
- sourceModel(row) and expect = 8 and pred = "source"
- or
- sinkModel(row) and expect = 8 and pred = "sink"
- or
- summaryModel(row) and expect = 9 and pred = "summary"
- |
- exists(int cols |
- cols = 1 + max(int n | exists(row.splitAt(";", n))) and
- cols != expect and
- result =
- "Wrong number of columns in " + pred + " model row, expected " + expect + ", got " + cols +
- "."
- )
- )
- }
-
private string getInvalidModelSignature() {
- exists(string pred, string namespace, string type, string name, string signature, string ext |
- sourceModel(namespace, type, _, name, signature, ext, _, _, _) and pred = "source"
- or
- sinkModel(namespace, type, _, name, signature, ext, _, _, _) and pred = "sink"
- or
- summaryModel(namespace, type, _, name, signature, ext, _, _, _, _) and pred = "summary"
+ exists(
+ string pred, string package, string type, string name, string signature, string ext,
+ string provenance
|
- not namespace.regexpMatch("[a-zA-Z0-9_\\./]*") and
- result = "Dubious namespace \"" + namespace + "\" in " + pred + " model."
+ sourceModel(package, type, _, name, signature, ext, _, _, provenance) and pred = "source"
+ or
+ sinkModel(package, type, _, name, signature, ext, _, _, provenance) and pred = "sink"
+ or
+ summaryModel(package, type, _, name, signature, ext, _, _, _, provenance) and pred = "summary"
+ |
+ not package.regexpMatch("[a-zA-Z0-9_\\./]*") and
+ result = "Dubious package \"" + package + "\" in " + pred + " model."
or
not type.regexpMatch("[a-zA-Z0-9_\\$<>]*") and
result = "Dubious type \"" + type + "\" in " + pred + " model."
@@ -290,26 +220,29 @@ module CsvValidation {
or
not ext.regexpMatch("|Annotated") and
result = "Unrecognized extra API graph element \"" + ext + "\" in " + pred + " model."
+ or
+ not provenance = ["manual", "generated"] and
+ result = "Unrecognized provenance description \"" + provenance + "\" in " + pred + " model."
)
}
- /** Holds if some row in a CSV-based flow model appears to contain typos. */
+ /** Holds if some row in a MaD flow model appears to contain typos. */
query predicate invalidModelRow(string msg) {
msg =
[
getInvalidModelSignature(), getInvalidModelInput(), getInvalidModelOutput(),
- getInvalidModelSubtype(), getInvalidModelColumnCount(), getInvalidModelKind()
+ getInvalidModelKind()
]
}
}
pragma[nomagic]
private predicate elementSpec(
- string namespace, string type, boolean subtypes, string name, string signature, string ext
+ string package, string type, boolean subtypes, string name, string signature, string ext
) {
- sourceModel(namespace, type, subtypes, name, signature, ext, _, _, _) or
- sinkModel(namespace, type, subtypes, name, signature, ext, _, _, _) or
- summaryModel(namespace, type, subtypes, name, signature, ext, _, _, _, _)
+ sourceModel(package, type, subtypes, name, signature, ext, _, _, _) or
+ sinkModel(package, type, subtypes, name, signature, ext, _, _, _) or
+ summaryModel(package, type, subtypes, name, signature, ext, _, _, _, _)
}
private string paramsStringPart(Function f, int i) {
@@ -405,7 +338,7 @@ predicate parseContent(string component, DataFlow::Content content) {
cached
private module Cached {
/**
- * Holds if `node` is specified as a source with the given kind in a CSV flow
+ * Holds if `node` is specified as a source with the given kind in a MaD flow
* model.
*/
cached
@@ -414,7 +347,7 @@ private module Cached {
}
/**
- * Holds if `node` is specified as a sink with the given kind in a CSV flow
+ * Holds if `node` is specified as a sink with the given kind in a MaD flow
* model.
*/
cached
diff --git a/go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImplSpecific.qll b/go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImplSpecific.qll
index 5e3768d52f4..0bf368aee60 100644
--- a/go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImplSpecific.qll
+++ b/go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImplSpecific.qll
@@ -65,11 +65,9 @@ DataFlowType getSyntheticGlobalType(SummaryComponent::SyntheticGlobal sg) { any(
predicate summaryElement(
SummarizedCallableBase c, string input, string output, string kind, string provenance
) {
- exists(
- string namespace, string type, boolean subtypes, string name, string signature, string ext
- |
- summaryModel(namespace, type, subtypes, name, signature, ext, input, output, kind, provenance) and
- c.asFunction() = interpretElement(namespace, type, subtypes, name, signature, ext).asEntity()
+ exists(string package, string type, boolean subtypes, string name, string signature, string ext |
+ summaryModel(package, type, subtypes, name, signature, ext, input, output, kind, provenance) and
+ c.asFunction() = interpretElement(package, type, subtypes, name, signature, ext).asEntity()
)
}
@@ -154,11 +152,9 @@ class SourceOrSinkElement extends TSourceOrSinkElement {
* `output`, kind `kind`, and provenance `provenance`.
*/
predicate sourceElement(SourceOrSinkElement e, string output, string kind, string provenance) {
- exists(
- string namespace, string type, boolean subtypes, string name, string signature, string ext
- |
- sourceModel(namespace, type, subtypes, name, signature, ext, output, kind, provenance) and
- e = interpretElement(namespace, type, subtypes, name, signature, ext)
+ exists(string package, string type, boolean subtypes, string name, string signature, string ext |
+ sourceModel(package, type, subtypes, name, signature, ext, output, kind, provenance) and
+ e = interpretElement(package, type, subtypes, name, signature, ext)
)
}
@@ -167,11 +163,9 @@ predicate sourceElement(SourceOrSinkElement e, string output, string kind, strin
* `input`, kind `kind` and provenance `provenance`.
*/
predicate sinkElement(SourceOrSinkElement e, string input, string kind, string provenance) {
- exists(
- string namespace, string type, boolean subtypes, string name, string signature, string ext
- |
- sinkModel(namespace, type, subtypes, name, signature, ext, input, kind, provenance) and
- e = interpretElement(namespace, type, subtypes, name, signature, ext)
+ exists(string package, string type, boolean subtypes, string name, string signature, string ext |
+ sinkModel(package, type, subtypes, name, signature, ext, input, kind, provenance) and
+ e = interpretElement(package, type, subtypes, name, signature, ext)
)
}
diff --git a/go/ql/lib/semmle/go/security/FlowSources.qll b/go/ql/lib/semmle/go/security/FlowSources.qll
index de8fb5c3732..b4d4c4d3187 100644
--- a/go/ql/lib/semmle/go/security/FlowSources.qll
+++ b/go/ql/lib/semmle/go/security/FlowSources.qll
@@ -23,7 +23,12 @@ module UntrustedFlowSource {
*/
abstract class Range extends DataFlow::Node { }
- class CsvRemoteSource extends Range {
- CsvRemoteSource() { ExternalFlow::sourceNode(this, "remote") }
+ /**
+ * A source of data that is controlled by an untrusted user.
+ */
+ class MaDRemoteSource extends Range {
+ MaDRemoteSource() { ExternalFlow::sourceNode(this, "remote") }
}
+
+ deprecated class CsvRemoteSource = MaDRemoteSource;
}
diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/completetest.ql b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/completetest.ql
index 45e67564e06..9719a9d69a6 100644
--- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/completetest.ql
+++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/completetest.ql
@@ -4,7 +4,7 @@
import go
import semmle.go.dataflow.ExternalFlow
-import CsvValidation
+import ModelValidation
import semmle.go.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
import TestUtilities.InlineFlowTest
diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/sinks.ql b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/sinks.ql
index 48d75ce06e6..de84cf24e4d 100644
--- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/sinks.ql
+++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/sinks.ql
@@ -1,6 +1,6 @@
import go
import semmle.go.dataflow.ExternalFlow
-import CsvValidation
+import ModelValidation
from DataFlow::Node node, string kind
where sinkNode(node, kind)
diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/srcs.ql b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/srcs.ql
index cffb909c495..d1cd0fee89d 100644
--- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/srcs.ql
+++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/srcs.ql
@@ -1,6 +1,6 @@
import go
import semmle.go.dataflow.ExternalFlow
-import CsvValidation
+import ModelValidation
from DataFlow::Node node, string kind
where sourceNode(node, kind)
diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/steps.ql b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/steps.ql
index 8ae82d104d6..00067971b76 100644
--- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/steps.ql
+++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlow/steps.ql
@@ -1,6 +1,6 @@
import go
import semmle.go.dataflow.ExternalFlow
-import CsvValidation
+import ModelValidation
import semmle.go.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
from DataFlow::Node node1, DataFlow::Node node2
diff --git a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowVarArgs/Flows.ql b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowVarArgs/Flows.ql
index f7c77d944f2..1be00de1f13 100644
--- a/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowVarArgs/Flows.ql
+++ b/go/ql/test/library-tests/semmle/go/dataflow/ExternalFlowVarArgs/Flows.ql
@@ -1,6 +1,6 @@
import go
import semmle.go.dataflow.ExternalFlow
-import CsvValidation
+import ModelValidation
import TestUtilities.InlineExpectationsTest
class DataConfiguration extends DataFlow::Configuration {
diff --git a/go/ql/test/library-tests/semmle/go/dataflow/VarArgsWithFunctionModels/Flows.ql b/go/ql/test/library-tests/semmle/go/dataflow/VarArgsWithFunctionModels/Flows.ql
index e80681e243e..176396da6f7 100644
--- a/go/ql/test/library-tests/semmle/go/dataflow/VarArgsWithFunctionModels/Flows.ql
+++ b/go/ql/test/library-tests/semmle/go/dataflow/VarArgsWithFunctionModels/Flows.ql
@@ -1,6 +1,6 @@
import go
import semmle.go.dataflow.ExternalFlow
-import CsvValidation
+import ModelValidation
// import DataFlow::PartialPathGraph
import TestUtilities.InlineExpectationsTest
From 4e5483744f9124584dce02b346f847477c83a604 Mon Sep 17 00:00:00 2001
From: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
Date: Thu, 12 Jan 2023 10:50:28 +0000
Subject: [PATCH 209/381] Swift: Add a test case we're discussing.
---
.../dataflow/dataflow/DataFlow.expected | 17 +++++++---
.../dataflow/dataflow/FlowConfig.qll | 2 +-
.../dataflow/dataflow/LocalFlow.expected | 34 +++++++++++--------
.../dataflow/dataflow/test.swift | 7 ++++
4 files changed, 39 insertions(+), 21 deletions(-)
diff --git a/swift/ql/test/library-tests/dataflow/dataflow/DataFlow.expected b/swift/ql/test/library-tests/dataflow/dataflow/DataFlow.expected
index d95be652a64..c1a30e3b551 100644
--- a/swift/ql/test/library-tests/dataflow/dataflow/DataFlow.expected
+++ b/swift/ql/test/library-tests/dataflow/dataflow/DataFlow.expected
@@ -100,7 +100,7 @@ edges
| test.swift:225:14:225:21 | call to source() : | test.swift:235:13:235:15 | .source_value |
| test.swift:225:14:225:21 | call to source() : | test.swift:238:13:238:15 | .source_value |
| test.swift:259:12:259:19 | call to source() : | test.swift:263:13:263:28 | call to optionalSource() : |
-| test.swift:259:12:259:19 | call to source() : | test.swift:437:13:437:28 | call to optionalSource() : |
+| test.swift:259:12:259:19 | call to source() : | test.swift:439:13:439:28 | call to optionalSource() : |
| test.swift:263:13:263:28 | call to optionalSource() : | test.swift:265:15:265:15 | x |
| test.swift:263:13:263:28 | call to optionalSource() : | test.swift:267:15:267:16 | ...! |
| test.swift:263:13:263:28 | call to optionalSource() : | test.swift:271:15:271:16 | ...? : |
@@ -141,7 +141,9 @@ edges
| test.swift:357:15:357:15 | t1 [Tuple element at index 1] : | test.swift:357:15:357:18 | .1 |
| test.swift:360:15:360:15 | t2 [Tuple element at index 0] : | test.swift:360:15:360:18 | .0 |
| test.swift:361:15:361:15 | t2 [Tuple element at index 1] : | test.swift:361:15:361:18 | .1 |
-| test.swift:437:13:437:28 | call to optionalSource() : | test.swift:440:19:440:19 | a |
+| test.swift:439:13:439:28 | call to optionalSource() : | test.swift:442:19:442:19 | a |
+| test.swift:455:21:455:29 | call to source2() : | test.swift:456:19:456:19 | x |
+| test.swift:455:21:455:29 | call to source2() : | test.swift:457:19:457:19 | y |
nodes
| file://:0:0:0:0 | .a [x] : | semmle.label | .a [x] : |
| file://:0:0:0:0 | .x : | semmle.label | .x : |
@@ -298,8 +300,11 @@ nodes
| test.swift:360:15:360:18 | .0 | semmle.label | .0 |
| test.swift:361:15:361:15 | t2 [Tuple element at index 1] : | semmle.label | t2 [Tuple element at index 1] : |
| test.swift:361:15:361:18 | .1 | semmle.label | .1 |
-| test.swift:437:13:437:28 | call to optionalSource() : | semmle.label | call to optionalSource() : |
-| test.swift:440:19:440:19 | a | semmle.label | a |
+| test.swift:439:13:439:28 | call to optionalSource() : | semmle.label | call to optionalSource() : |
+| test.swift:442:19:442:19 | a | semmle.label | a |
+| test.swift:455:21:455:29 | call to source2() : | semmle.label | call to source2() : |
+| test.swift:456:19:456:19 | x | semmle.label | x |
+| test.swift:457:19:457:19 | y | semmle.label | y |
subpaths
| test.swift:75:21:75:22 | &... : | test.swift:65:16:65:28 | arg1 : | test.swift:65:1:70:1 | arg2[return] : | test.swift:75:31:75:32 | [post] &... : |
| test.swift:114:19:114:19 | arg : | test.swift:109:9:109:14 | arg : | test.swift:110:12:110:12 | arg : | test.swift:114:12:114:22 | call to ... : |
@@ -380,4 +385,6 @@ subpaths
| test.swift:357:15:357:18 | .1 | test.swift:351:31:351:38 | call to source() : | test.swift:357:15:357:18 | .1 | result |
| test.swift:360:15:360:18 | .0 | test.swift:351:18:351:25 | call to source() : | test.swift:360:15:360:18 | .0 | result |
| test.swift:361:15:361:18 | .1 | test.swift:351:31:351:38 | call to source() : | test.swift:361:15:361:18 | .1 | result |
-| test.swift:440:19:440:19 | a | test.swift:259:12:259:19 | call to source() : | test.swift:440:19:440:19 | a | result |
+| test.swift:442:19:442:19 | a | test.swift:259:12:259:19 | call to source() : | test.swift:442:19:442:19 | a | result |
+| test.swift:456:19:456:19 | x | test.swift:455:21:455:29 | call to source2() : | test.swift:456:19:456:19 | x | result |
+| test.swift:457:19:457:19 | y | test.swift:455:21:455:29 | call to source2() : | test.swift:457:19:457:19 | y | result |
diff --git a/swift/ql/test/library-tests/dataflow/dataflow/FlowConfig.qll b/swift/ql/test/library-tests/dataflow/dataflow/FlowConfig.qll
index 1be01c4a6c8..062814ddfd2 100644
--- a/swift/ql/test/library-tests/dataflow/dataflow/FlowConfig.qll
+++ b/swift/ql/test/library-tests/dataflow/dataflow/FlowConfig.qll
@@ -10,7 +10,7 @@ class TestConfiguration extends DataFlow::Configuration {
TestConfiguration() { this = "TestConfiguration" }
override predicate isSource(DataFlow::Node src) {
- src.asExpr().(CallExpr).getStaticTarget().getName() = "source()"
+ src.asExpr().(CallExpr).getStaticTarget().getName().matches("source%()")
}
override predicate isSink(DataFlow::Node sink) {
diff --git a/swift/ql/test/library-tests/dataflow/dataflow/LocalFlow.expected b/swift/ql/test/library-tests/dataflow/dataflow/LocalFlow.expected
index 88f69288dfb..da400552ce2 100644
--- a/swift/ql/test/library-tests/dataflow/dataflow/LocalFlow.expected
+++ b/swift/ql/test/library-tests/dataflow/dataflow/LocalFlow.expected
@@ -355,18 +355,22 @@
| test.swift:430:13:430:33 | SSA def(y) | test.swift:432:19:432:19 | y |
| test.swift:430:37:430:37 | a | test.swift:430:13:430:33 | SSA def(x) |
| test.swift:430:37:430:37 | a | test.swift:430:13:430:33 | SSA def(y) |
-| test.swift:436:21:436:27 | SSA def(y) | test.swift:439:27:439:27 | y |
-| test.swift:436:21:436:27 | SSA def(y) | test.swift:444:22:444:22 | y |
-| test.swift:436:21:436:27 | y | test.swift:436:21:436:27 | SSA def(y) |
-| test.swift:437:9:437:9 | SSA def(x) | test.swift:439:16:439:16 | x |
-| test.swift:437:13:437:28 | call to optionalSource() | test.swift:437:9:437:9 | SSA def(x) |
-| test.swift:439:8:439:12 | SSA def(a) | test.swift:440:19:440:19 | a |
-| test.swift:439:16:439:16 | x | test.swift:439:8:439:12 | SSA def(a) |
-| test.swift:439:16:439:16 | x | test.swift:444:19:444:19 | x |
-| test.swift:439:19:439:23 | SSA def(b) | test.swift:441:19:441:19 | b |
-| test.swift:439:27:439:27 | y | test.swift:439:19:439:23 | SSA def(b) |
-| test.swift:439:27:439:27 | y | test.swift:444:22:444:22 | y |
-| test.swift:444:9:444:9 | SSA def(tuple1) | test.swift:445:12:445:12 | tuple1 |
-| test.swift:444:18:444:23 | (...) | test.swift:444:9:444:9 | SSA def(tuple1) |
-| test.swift:446:10:446:37 | SSA def(a) | test.swift:447:19:447:19 | a |
-| test.swift:446:10:446:37 | SSA def(b) | test.swift:448:19:448:19 | b |
+| test.swift:438:21:438:27 | SSA def(y) | test.swift:441:27:441:27 | y |
+| test.swift:438:21:438:27 | SSA def(y) | test.swift:446:22:446:22 | y |
+| test.swift:438:21:438:27 | y | test.swift:438:21:438:27 | SSA def(y) |
+| test.swift:439:9:439:9 | SSA def(x) | test.swift:441:16:441:16 | x |
+| test.swift:439:13:439:28 | call to optionalSource() | test.swift:439:9:439:9 | SSA def(x) |
+| test.swift:441:8:441:12 | SSA def(a) | test.swift:442:19:442:19 | a |
+| test.swift:441:16:441:16 | x | test.swift:441:8:441:12 | SSA def(a) |
+| test.swift:441:16:441:16 | x | test.swift:446:19:446:19 | x |
+| test.swift:441:19:441:23 | SSA def(b) | test.swift:443:19:443:19 | b |
+| test.swift:441:27:441:27 | y | test.swift:441:19:441:23 | SSA def(b) |
+| test.swift:441:27:441:27 | y | test.swift:446:22:446:22 | y |
+| test.swift:446:9:446:9 | SSA def(tuple1) | test.swift:447:12:447:12 | tuple1 |
+| test.swift:446:18:446:23 | (...) | test.swift:446:9:446:9 | SSA def(tuple1) |
+| test.swift:448:10:448:37 | SSA def(a) | test.swift:449:19:449:19 | a |
+| test.swift:448:10:448:37 | SSA def(b) | test.swift:450:19:450:19 | b |
+| test.swift:455:8:455:17 | SSA def(x) | test.swift:456:19:456:19 | x |
+| test.swift:455:8:455:17 | SSA def(y) | test.swift:457:19:457:19 | y |
+| test.swift:455:21:455:29 | call to source2() | test.swift:455:8:455:17 | SSA def(x) |
+| test.swift:455:21:455:29 | call to source2() | test.swift:455:8:455:17 | SSA def(y) |
diff --git a/swift/ql/test/library-tests/dataflow/dataflow/test.swift b/swift/ql/test/library-tests/dataflow/dataflow/test.swift
index 7692dc05e68..400b3c05bf6 100644
--- a/swift/ql/test/library-tests/dataflow/dataflow/test.swift
+++ b/swift/ql/test/library-tests/dataflow/dataflow/test.swift
@@ -433,6 +433,8 @@ func testEnums() {
}
}
+func source2() -> (Int, Int)? { return nil }
+
func testOptionals2(y: Int?) {
let x = optionalSource()
@@ -449,4 +451,9 @@ func testOptionals2(y: Int?) {
default:
()
}
+
+ if let (x, y) = source2() {
+ sink(arg: x) // $ flow=455
+ sink(arg: y) // $ flow=455
+ }
}
From d0eb167d47b9b9ed6a21471ee3655434824f8523 Mon Sep 17 00:00:00 2001
From: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
Date: Thu, 12 Jan 2023 11:28:44 +0000
Subject: [PATCH 210/381] Swift: Merge FloatingPointType.qll into
NumericOrCharType.qll, because it is a numeric type and other stuff like
CharacterType is there.
---
.../codeql/swift/elements/type/FloatingPointType.qll | 12 ------------
.../codeql/swift/elements/type/NumericOrCharType.qll | 11 +++++++++++
swift/ql/lib/swift.qll | 1 -
3 files changed, 11 insertions(+), 13 deletions(-)
delete mode 100644 swift/ql/lib/codeql/swift/elements/type/FloatingPointType.qll
diff --git a/swift/ql/lib/codeql/swift/elements/type/FloatingPointType.qll b/swift/ql/lib/codeql/swift/elements/type/FloatingPointType.qll
deleted file mode 100644
index e5ae0ac3e7a..00000000000
--- a/swift/ql/lib/codeql/swift/elements/type/FloatingPointType.qll
+++ /dev/null
@@ -1,12 +0,0 @@
-private import swift
-
-/**
- * A floating-point type. This includes the `Float` type, the `Double`, and
- * builtin floating-point types.
- */
-class FloatingPointType extends Type {
- FloatingPointType() {
- this.getName() = ["Float", "Double"] or
- this instanceof BuiltinFloatType
- }
-}
diff --git a/swift/ql/lib/codeql/swift/elements/type/NumericOrCharType.qll b/swift/ql/lib/codeql/swift/elements/type/NumericOrCharType.qll
index 217690039ed..31a825bd6cd 100644
--- a/swift/ql/lib/codeql/swift/elements/type/NumericOrCharType.qll
+++ b/swift/ql/lib/codeql/swift/elements/type/NumericOrCharType.qll
@@ -1,5 +1,16 @@
private import swift
+/**
+ * A floating-point type. This includes the `Float` type, the `Double`, and
+ * builtin floating-point types.
+ */
+class FloatingPointType extends Type {
+ FloatingPointType() {
+ this.getName() = ["Float", "Double"] or
+ this instanceof BuiltinFloatType
+ }
+}
+
/** The `Character` type. */
class CharacterType extends StructType {
CharacterType() { this.getName() = "Character" }
diff --git a/swift/ql/lib/swift.qll b/swift/ql/lib/swift.qll
index 552f2c99828..4d79e4b73eb 100644
--- a/swift/ql/lib/swift.qll
+++ b/swift/ql/lib/swift.qll
@@ -10,6 +10,5 @@ import codeql.swift.elements.expr.InitializerCallExpr
import codeql.swift.elements.expr.SelfRefExpr
import codeql.swift.elements.decl.MethodDecl
import codeql.swift.elements.decl.ClassOrStructDecl
-import codeql.swift.elements.type.FloatingPointType
import codeql.swift.elements.type.NumericOrCharType
import codeql.swift.Unit
From 418d593a97d5666933146477b9e715f22c177e0c Mon Sep 17 00:00:00 2001
From: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
Date: Thu, 12 Jan 2023 11:39:33 +0000
Subject: [PATCH 211/381] Swift: Replace NumericOrCharType with a more basic
NumericType, and rename classes for consistency with other static languages.
---
.../swift/elements/type/NumericOrCharType.qll | 20 +++++++++----------
1 file changed, 9 insertions(+), 11 deletions(-)
diff --git a/swift/ql/lib/codeql/swift/elements/type/NumericOrCharType.qll b/swift/ql/lib/codeql/swift/elements/type/NumericOrCharType.qll
index 31a825bd6cd..1becac4493b 100644
--- a/swift/ql/lib/codeql/swift/elements/type/NumericOrCharType.qll
+++ b/swift/ql/lib/codeql/swift/elements/type/NumericOrCharType.qll
@@ -19,8 +19,8 @@ class CharacterType extends StructType {
/**
* An integer-like type. For example, `Int`, `Int16`, `Uint16`, etc.
*/
-class IntegerType extends Type {
- IntegerType() {
+class IntegralType extends Type {
+ IntegralType() {
this.getName() =
["Int", "Int8", "Int16", "Int32", "Int64", "UInt", "UInt8", "UInt16", "UInt32", "UInt64"]
or
@@ -29,18 +29,16 @@ class IntegerType extends Type {
}
/** The `Bool` type. */
-class BooleanType extends Type {
- BooleanType() { this.getName() = "Bool" }
+class BoolType extends Type {
+ BoolType() { this.getName() = "Bool" }
}
/**
- * A numeric-like type. This includes the types `Character`, `Bool`, and all
- * the integer-like types.
+ * A numeric type. This includes the integer and floating point types.
*/
-class NumericOrCharType extends Type {
- NumericOrCharType() {
- this instanceof CharacterType or
- this instanceof IntegerType or
- this instanceof BooleanType
+class NumericType extends Type {
+ NumericType() {
+ this instanceof IntegralType or
+ this instanceof FloatingPointType
}
}
From 3d1b2fdbda06c77dafcb4e056908547e28f588f6 Mon Sep 17 00:00:00 2001
From: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
Date: Thu, 12 Jan 2023 11:46:51 +0000
Subject: [PATCH 212/381] Swift: Rename NumericOrCharType.qll -> Numer>
NumericType.qll.
---
.../elements/type/{NumericOrCharType.qll => NumericType.qll} | 0
swift/ql/lib/swift.qll | 2 +-
2 files changed, 1 insertion(+), 1 deletion(-)
rename swift/ql/lib/codeql/swift/elements/type/{NumericOrCharType.qll => NumericType.qll} (100%)
diff --git a/swift/ql/lib/codeql/swift/elements/type/NumericOrCharType.qll b/swift/ql/lib/codeql/swift/elements/type/NumericType.qll
similarity index 100%
rename from swift/ql/lib/codeql/swift/elements/type/NumericOrCharType.qll
rename to swift/ql/lib/codeql/swift/elements/type/NumericType.qll
diff --git a/swift/ql/lib/swift.qll b/swift/ql/lib/swift.qll
index 4d79e4b73eb..897bbf9b2f7 100644
--- a/swift/ql/lib/swift.qll
+++ b/swift/ql/lib/swift.qll
@@ -10,5 +10,5 @@ import codeql.swift.elements.expr.InitializerCallExpr
import codeql.swift.elements.expr.SelfRefExpr
import codeql.swift.elements.decl.MethodDecl
import codeql.swift.elements.decl.ClassOrStructDecl
-import codeql.swift.elements.type.NumericOrCharType
+import codeql.swift.elements.type.NumericType
import codeql.swift.Unit
From 7ae27bcc34af2c263eaf43c5f26f623b6af52059 Mon Sep 17 00:00:00 2001
From: erik-krogh
Date: Thu, 12 Jan 2023 15:37:52 +0100
Subject: [PATCH 213/381] fix errors in JS printAst
---
.../ql/lib/semmle/javascript/PrintAst.qll | 13 +-
.../AST/Decorators/printAst.expected | 138 ++++++++++++++++++
.../library-tests/AST/Decorators/printAst.ql | 2 +
.../AST/Decorators/tsconfig.json | 7 +
.../test/library-tests/AST/Decorators/tst.ts | 14 ++
.../TypeAnnotations/printAst.expected | 112 +++++++-------
.../TypeScript/Types/printAst.expected | 128 ++++++++--------
7 files changed, 291 insertions(+), 123 deletions(-)
create mode 100644 javascript/ql/test/library-tests/AST/Decorators/printAst.expected
create mode 100644 javascript/ql/test/library-tests/AST/Decorators/printAst.ql
create mode 100644 javascript/ql/test/library-tests/AST/Decorators/tsconfig.json
create mode 100644 javascript/ql/test/library-tests/AST/Decorators/tst.ts
diff --git a/javascript/ql/lib/semmle/javascript/PrintAst.qll b/javascript/ql/lib/semmle/javascript/PrintAst.qll
index a4d71362818..6339d81a01c 100644
--- a/javascript/ql/lib/semmle/javascript/PrintAst.qll
+++ b/javascript/ql/lib/semmle/javascript/PrintAst.qll
@@ -30,12 +30,17 @@ private predicate shouldPrint(Locatable e, Location l) {
exists(PrintAstConfiguration config | config.shouldPrint(e, l))
}
-/** Holds if the given element does not need to be rendered in the AST, due to being the `TopLevel` for a file. */
+/**
+ * Holds if the given element does not need to be rendered in the AST.
+ * Either due to being the `TopLevel` for a file, or an internal node representing a decorator list.
+ */
private predicate isNotNeeded(Locatable el) {
el instanceof TopLevel and
el.getLocation().getStartLine() = 0 and
el.getLocation().getStartColumn() = 0
or
+ el instanceof @decorator_list // there is no public API for this.
+ or
// relaxing aggressive type inference.
none()
}
@@ -500,9 +505,11 @@ private module PrintJavaScript {
override Parameter element;
override AstNode getChildNode(int childIndex) {
- childIndex = 0 and result = element.getTypeAnnotation()
+ result = super.getChildNode(childIndex) // in case the parameter is a destructuring pattern
or
- childIndex = 1 and result = element.getDefault()
+ childIndex = -2 and result = element.getTypeAnnotation()
+ or
+ childIndex = -1 and result = element.getDefault()
}
}
diff --git a/javascript/ql/test/library-tests/AST/Decorators/printAst.expected b/javascript/ql/test/library-tests/AST/Decorators/printAst.expected
new file mode 100644
index 00000000000..5cbec5ec883
--- /dev/null
+++ b/javascript/ql/test/library-tests/AST/Decorators/printAst.expected
@@ -0,0 +1,138 @@
+nodes
+| file://:0:0:0:0 | (Arguments) | semmle.label | (Arguments) |
+| file://:0:0:0:0 | (Parameters) | semmle.label | (Parameters) |
+| tst.ts:1:1:1:22 | [DeclStmt] const Dec = ... | semmle.label | [DeclStmt] const Dec = ... |
+| tst.ts:1:1:1:22 | [DeclStmt] const Dec = ... | semmle.order | 1 |
+| tst.ts:1:7:1:9 | [VarDecl] Dec | semmle.label | [VarDecl] Dec |
+| tst.ts:1:7:1:21 | [VariableDeclarator] Dec: any = null | semmle.label | [VariableDeclarator] Dec: any = null |
+| tst.ts:1:12:1:14 | [KeywordTypeExpr] any | semmle.label | [KeywordTypeExpr] any |
+| tst.ts:1:18:1:21 | [Literal] null | semmle.label | [Literal] null |
+| tst.ts:3:1:3:6 | [Decorator] @Dec() | semmle.label | [Decorator] @Dec() |
+| tst.ts:3:2:3:4 | [VarRef] Dec | semmle.label | [VarRef] Dec |
+| tst.ts:3:2:3:6 | [CallExpr] Dec() | semmle.label | [CallExpr] Dec() |
+| tst.ts:4:1:8:1 | [ExportDeclaration] export ... id {} } | semmle.label | [ExportDeclaration] export ... id {} } |
+| tst.ts:4:1:8:1 | [ExportDeclaration] export ... id {} } | semmle.order | 2 |
+| tst.ts:4:8:8:1 | [ClassDefinition,TypeDefinition] class O ... id {} } | semmle.label | [ClassDefinition,TypeDefinition] class O ... id {} } |
+| tst.ts:4:14:4:30 | [VarDecl] OperatorResolvers | semmle.label | [VarDecl] OperatorResolvers |
+| tst.ts:4:32:4:31 | [BlockStmt] {} | semmle.label | [BlockStmt] {} |
+| tst.ts:4:32:4:31 | [ClassInitializedMember,ConstructorDefinition] constructor() {} | semmle.label | [ClassInitializedMember,ConstructorDefinition] constructor() {} |
+| tst.ts:4:32:4:31 | [FunctionExpr] () {} | semmle.label | [FunctionExpr] () {} |
+| tst.ts:4:32:4:31 | [Label] constructor | semmle.label | [Label] constructor |
+| tst.ts:5:3:5:8 | [Decorator] @Dec() | semmle.label | [Decorator] @Dec() |
+| tst.ts:5:4:5:6 | [VarRef] Dec | semmle.label | [VarRef] Dec |
+| tst.ts:5:4:5:8 | [CallExpr] Dec() | semmle.label | [CallExpr] Dec() |
+| tst.ts:6:3:6:8 | [Decorator] @Dec() | semmle.label | [Decorator] @Dec() |
+| tst.ts:6:4:6:6 | [VarRef] Dec | semmle.label | [VarRef] Dec |
+| tst.ts:6:4:6:8 | [CallExpr] Dec() | semmle.label | [CallExpr] Dec() |
+| tst.ts:7:3:7:11 | [Label] operators | semmle.label | [Label] operators |
+| tst.ts:7:3:7:22 | [ClassInitializedMember,MethodDefinition] operators(): void {} | semmle.label | [ClassInitializedMember,MethodDefinition] operators(): void {} |
+| tst.ts:7:3:7:22 | [FunctionExpr] operators(): void {} | semmle.label | [FunctionExpr] operators(): void {} |
+| tst.ts:7:16:7:19 | [KeywordTypeExpr] void | semmle.label | [KeywordTypeExpr] void |
+| tst.ts:7:21:7:22 | [BlockStmt] {} | semmle.label | [BlockStmt] {} |
+| tst.ts:10:1:10:41 | [DeclStmt] const createMethodDecorator = ... | semmle.label | [DeclStmt] const createMethodDecorator = ... |
+| tst.ts:10:1:10:41 | [DeclStmt] const createMethodDecorator = ... | semmle.order | 3 |
+| tst.ts:10:7:10:27 | [VarDecl] createMethodDecorator | semmle.label | [VarDecl] createMethodDecorator |
+| tst.ts:10:7:10:40 | [VariableDeclarator] createM ... = null | semmle.label | [VariableDeclarator] createM ... = null |
+| tst.ts:10:31:10:33 | [KeywordTypeExpr] any | semmle.label | [KeywordTypeExpr] any |
+| tst.ts:10:37:10:40 | [Literal] null | semmle.label | [Literal] null |
+| tst.ts:12:1:12:21 | [VarRef] createMethodDecorator | semmle.label | [VarRef] createMethodDecorator |
+| tst.ts:12:1:14:2 | [CallExpr] createM ... { }) | semmle.label | [CallExpr] createM ... { }) |
+| tst.ts:12:1:14:3 | [ExprStmt] createM ... }); | semmle.label | [ExprStmt] createM ... }); |
+| tst.ts:12:1:14:3 | [ExprStmt] createM ... }); | semmle.order | 4 |
+| tst.ts:12:23:14:1 | [ArrowFunctionExpr] ({ args ... { } | semmle.label | [ArrowFunctionExpr] ({ args ... { } |
+| tst.ts:12:24:12:40 | [ObjectPattern,Parameter] { args, context } | semmle.label | [ObjectPattern,Parameter] { args, context } |
+| tst.ts:12:26:12:29 | [Label] args | semmle.label | [Label] args |
+| tst.ts:12:26:12:29 | [PropertyPattern] args | semmle.label | [PropertyPattern] args |
+| tst.ts:12:26:12:29 | [VarDecl] args | semmle.label | [VarDecl] args |
+| tst.ts:12:32:12:38 | [Label] context | semmle.label | [Label] context |
+| tst.ts:12:32:12:38 | [PropertyPattern] context | semmle.label | [PropertyPattern] context |
+| tst.ts:12:32:12:38 | [VarDecl] context | semmle.label | [VarDecl] context |
+| tst.ts:12:43:12:46 | [SimpleParameter] next | semmle.label | [SimpleParameter] next |
+| tst.ts:12:52:14:1 | [BlockStmt] { } | semmle.label | [BlockStmt] { } |
+edges
+| file://:0:0:0:0 | (Arguments) | tst.ts:12:23:14:1 | [ArrowFunctionExpr] ({ args ... { } | semmle.label | 0 |
+| file://:0:0:0:0 | (Arguments) | tst.ts:12:23:14:1 | [ArrowFunctionExpr] ({ args ... { } | semmle.order | 0 |
+| file://:0:0:0:0 | (Parameters) | tst.ts:12:24:12:40 | [ObjectPattern,Parameter] { args, context } | semmle.label | 0 |
+| file://:0:0:0:0 | (Parameters) | tst.ts:12:24:12:40 | [ObjectPattern,Parameter] { args, context } | semmle.order | 0 |
+| file://:0:0:0:0 | (Parameters) | tst.ts:12:43:12:46 | [SimpleParameter] next | semmle.label | 1 |
+| file://:0:0:0:0 | (Parameters) | tst.ts:12:43:12:46 | [SimpleParameter] next | semmle.order | 1 |
+| tst.ts:1:1:1:22 | [DeclStmt] const Dec = ... | tst.ts:1:7:1:21 | [VariableDeclarator] Dec: any = null | semmle.label | 1 |
+| tst.ts:1:1:1:22 | [DeclStmt] const Dec = ... | tst.ts:1:7:1:21 | [VariableDeclarator] Dec: any = null | semmle.order | 1 |
+| tst.ts:1:7:1:21 | [VariableDeclarator] Dec: any = null | tst.ts:1:7:1:9 | [VarDecl] Dec | semmle.label | 1 |
+| tst.ts:1:7:1:21 | [VariableDeclarator] Dec: any = null | tst.ts:1:7:1:9 | [VarDecl] Dec | semmle.order | 1 |
+| tst.ts:1:7:1:21 | [VariableDeclarator] Dec: any = null | tst.ts:1:12:1:14 | [KeywordTypeExpr] any | semmle.label | 2 |
+| tst.ts:1:7:1:21 | [VariableDeclarator] Dec: any = null | tst.ts:1:12:1:14 | [KeywordTypeExpr] any | semmle.order | 2 |
+| tst.ts:1:7:1:21 | [VariableDeclarator] Dec: any = null | tst.ts:1:18:1:21 | [Literal] null | semmle.label | 3 |
+| tst.ts:1:7:1:21 | [VariableDeclarator] Dec: any = null | tst.ts:1:18:1:21 | [Literal] null | semmle.order | 3 |
+| tst.ts:3:1:3:6 | [Decorator] @Dec() | tst.ts:3:2:3:6 | [CallExpr] Dec() | semmle.label | 1 |
+| tst.ts:3:1:3:6 | [Decorator] @Dec() | tst.ts:3:2:3:6 | [CallExpr] Dec() | semmle.order | 1 |
+| tst.ts:3:2:3:6 | [CallExpr] Dec() | tst.ts:3:2:3:4 | [VarRef] Dec | semmle.label | 0 |
+| tst.ts:3:2:3:6 | [CallExpr] Dec() | tst.ts:3:2:3:4 | [VarRef] Dec | semmle.order | 0 |
+| tst.ts:4:1:8:1 | [ExportDeclaration] export ... id {} } | tst.ts:4:8:8:1 | [ClassDefinition,TypeDefinition] class O ... id {} } | semmle.label | 1 |
+| tst.ts:4:1:8:1 | [ExportDeclaration] export ... id {} } | tst.ts:4:8:8:1 | [ClassDefinition,TypeDefinition] class O ... id {} } | semmle.order | 1 |
+| tst.ts:4:8:8:1 | [ClassDefinition,TypeDefinition] class O ... id {} } | tst.ts:3:1:3:6 | [Decorator] @Dec() | semmle.label | 1 |
+| tst.ts:4:8:8:1 | [ClassDefinition,TypeDefinition] class O ... id {} } | tst.ts:3:1:3:6 | [Decorator] @Dec() | semmle.order | 1 |
+| tst.ts:4:8:8:1 | [ClassDefinition,TypeDefinition] class O ... id {} } | tst.ts:4:14:4:30 | [VarDecl] OperatorResolvers | semmle.label | 2 |
+| tst.ts:4:8:8:1 | [ClassDefinition,TypeDefinition] class O ... id {} } | tst.ts:4:14:4:30 | [VarDecl] OperatorResolvers | semmle.order | 2 |
+| tst.ts:4:8:8:1 | [ClassDefinition,TypeDefinition] class O ... id {} } | tst.ts:4:32:4:31 | [ClassInitializedMember,ConstructorDefinition] constructor() {} | semmle.label | 3 |
+| tst.ts:4:8:8:1 | [ClassDefinition,TypeDefinition] class O ... id {} } | tst.ts:4:32:4:31 | [ClassInitializedMember,ConstructorDefinition] constructor() {} | semmle.order | 3 |
+| tst.ts:4:8:8:1 | [ClassDefinition,TypeDefinition] class O ... id {} } | tst.ts:7:3:7:22 | [ClassInitializedMember,MethodDefinition] operators(): void {} | semmle.label | 4 |
+| tst.ts:4:8:8:1 | [ClassDefinition,TypeDefinition] class O ... id {} } | tst.ts:7:3:7:22 | [ClassInitializedMember,MethodDefinition] operators(): void {} | semmle.order | 4 |
+| tst.ts:4:32:4:31 | [ClassInitializedMember,ConstructorDefinition] constructor() {} | tst.ts:4:32:4:31 | [FunctionExpr] () {} | semmle.label | 2 |
+| tst.ts:4:32:4:31 | [ClassInitializedMember,ConstructorDefinition] constructor() {} | tst.ts:4:32:4:31 | [FunctionExpr] () {} | semmle.order | 2 |
+| tst.ts:4:32:4:31 | [ClassInitializedMember,ConstructorDefinition] constructor() {} | tst.ts:4:32:4:31 | [Label] constructor | semmle.label | 1 |
+| tst.ts:4:32:4:31 | [ClassInitializedMember,ConstructorDefinition] constructor() {} | tst.ts:4:32:4:31 | [Label] constructor | semmle.order | 1 |
+| tst.ts:4:32:4:31 | [FunctionExpr] () {} | tst.ts:4:32:4:31 | [BlockStmt] {} | semmle.label | 5 |
+| tst.ts:4:32:4:31 | [FunctionExpr] () {} | tst.ts:4:32:4:31 | [BlockStmt] {} | semmle.order | 5 |
+| tst.ts:5:3:5:8 | [Decorator] @Dec() | tst.ts:5:4:5:8 | [CallExpr] Dec() | semmle.label | 1 |
+| tst.ts:5:3:5:8 | [Decorator] @Dec() | tst.ts:5:4:5:8 | [CallExpr] Dec() | semmle.order | 1 |
+| tst.ts:5:4:5:8 | [CallExpr] Dec() | tst.ts:5:4:5:6 | [VarRef] Dec | semmle.label | 0 |
+| tst.ts:5:4:5:8 | [CallExpr] Dec() | tst.ts:5:4:5:6 | [VarRef] Dec | semmle.order | 0 |
+| tst.ts:6:3:6:8 | [Decorator] @Dec() | tst.ts:6:4:6:8 | [CallExpr] Dec() | semmle.label | 1 |
+| tst.ts:6:3:6:8 | [Decorator] @Dec() | tst.ts:6:4:6:8 | [CallExpr] Dec() | semmle.order | 1 |
+| tst.ts:6:4:6:8 | [CallExpr] Dec() | tst.ts:6:4:6:6 | [VarRef] Dec | semmle.label | 0 |
+| tst.ts:6:4:6:8 | [CallExpr] Dec() | tst.ts:6:4:6:6 | [VarRef] Dec | semmle.order | 0 |
+| tst.ts:7:3:7:22 | [ClassInitializedMember,MethodDefinition] operators(): void {} | tst.ts:5:3:5:8 | [Decorator] @Dec() | semmle.label | 1 |
+| tst.ts:7:3:7:22 | [ClassInitializedMember,MethodDefinition] operators(): void {} | tst.ts:5:3:5:8 | [Decorator] @Dec() | semmle.order | 1 |
+| tst.ts:7:3:7:22 | [ClassInitializedMember,MethodDefinition] operators(): void {} | tst.ts:6:3:6:8 | [Decorator] @Dec() | semmle.label | 2 |
+| tst.ts:7:3:7:22 | [ClassInitializedMember,MethodDefinition] operators(): void {} | tst.ts:6:3:6:8 | [Decorator] @Dec() | semmle.order | 2 |
+| tst.ts:7:3:7:22 | [ClassInitializedMember,MethodDefinition] operators(): void {} | tst.ts:7:3:7:11 | [Label] operators | semmle.label | 3 |
+| tst.ts:7:3:7:22 | [ClassInitializedMember,MethodDefinition] operators(): void {} | tst.ts:7:3:7:11 | [Label] operators | semmle.order | 3 |
+| tst.ts:7:3:7:22 | [ClassInitializedMember,MethodDefinition] operators(): void {} | tst.ts:7:3:7:22 | [FunctionExpr] operators(): void {} | semmle.label | 4 |
+| tst.ts:7:3:7:22 | [ClassInitializedMember,MethodDefinition] operators(): void {} | tst.ts:7:3:7:22 | [FunctionExpr] operators(): void {} | semmle.order | 4 |
+| tst.ts:7:3:7:22 | [FunctionExpr] operators(): void {} | tst.ts:7:16:7:19 | [KeywordTypeExpr] void | semmle.label | 4 |
+| tst.ts:7:3:7:22 | [FunctionExpr] operators(): void {} | tst.ts:7:16:7:19 | [KeywordTypeExpr] void | semmle.order | 4 |
+| tst.ts:7:3:7:22 | [FunctionExpr] operators(): void {} | tst.ts:7:21:7:22 | [BlockStmt] {} | semmle.label | 5 |
+| tst.ts:7:3:7:22 | [FunctionExpr] operators(): void {} | tst.ts:7:21:7:22 | [BlockStmt] {} | semmle.order | 5 |
+| tst.ts:10:1:10:41 | [DeclStmt] const createMethodDecorator = ... | tst.ts:10:7:10:40 | [VariableDeclarator] createM ... = null | semmle.label | 1 |
+| tst.ts:10:1:10:41 | [DeclStmt] const createMethodDecorator = ... | tst.ts:10:7:10:40 | [VariableDeclarator] createM ... = null | semmle.order | 1 |
+| tst.ts:10:7:10:40 | [VariableDeclarator] createM ... = null | tst.ts:10:7:10:27 | [VarDecl] createMethodDecorator | semmle.label | 1 |
+| tst.ts:10:7:10:40 | [VariableDeclarator] createM ... = null | tst.ts:10:7:10:27 | [VarDecl] createMethodDecorator | semmle.order | 1 |
+| tst.ts:10:7:10:40 | [VariableDeclarator] createM ... = null | tst.ts:10:31:10:33 | [KeywordTypeExpr] any | semmle.label | 2 |
+| tst.ts:10:7:10:40 | [VariableDeclarator] createM ... = null | tst.ts:10:31:10:33 | [KeywordTypeExpr] any | semmle.order | 2 |
+| tst.ts:10:7:10:40 | [VariableDeclarator] createM ... = null | tst.ts:10:37:10:40 | [Literal] null | semmle.label | 3 |
+| tst.ts:10:7:10:40 | [VariableDeclarator] createM ... = null | tst.ts:10:37:10:40 | [Literal] null | semmle.order | 3 |
+| tst.ts:12:1:14:2 | [CallExpr] createM ... { }) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 |
+| tst.ts:12:1:14:2 | [CallExpr] createM ... { }) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 |
+| tst.ts:12:1:14:2 | [CallExpr] createM ... { }) | tst.ts:12:1:12:21 | [VarRef] createMethodDecorator | semmle.label | 0 |
+| tst.ts:12:1:14:2 | [CallExpr] createM ... { }) | tst.ts:12:1:12:21 | [VarRef] createMethodDecorator | semmle.order | 0 |
+| tst.ts:12:1:14:3 | [ExprStmt] createM ... }); | tst.ts:12:1:14:2 | [CallExpr] createM ... { }) | semmle.label | 1 |
+| tst.ts:12:1:14:3 | [ExprStmt] createM ... }); | tst.ts:12:1:14:2 | [CallExpr] createM ... { }) | semmle.order | 1 |
+| tst.ts:12:23:14:1 | [ArrowFunctionExpr] ({ args ... { } | file://:0:0:0:0 | (Parameters) | semmle.label | 1 |
+| tst.ts:12:23:14:1 | [ArrowFunctionExpr] ({ args ... { } | file://:0:0:0:0 | (Parameters) | semmle.order | 1 |
+| tst.ts:12:23:14:1 | [ArrowFunctionExpr] ({ args ... { } | tst.ts:12:52:14:1 | [BlockStmt] { } | semmle.label | 5 |
+| tst.ts:12:23:14:1 | [ArrowFunctionExpr] ({ args ... { } | tst.ts:12:52:14:1 | [BlockStmt] { } | semmle.order | 5 |
+| tst.ts:12:24:12:40 | [ObjectPattern,Parameter] { args, context } | tst.ts:12:26:12:29 | [PropertyPattern] args | semmle.label | 1 |
+| tst.ts:12:24:12:40 | [ObjectPattern,Parameter] { args, context } | tst.ts:12:26:12:29 | [PropertyPattern] args | semmle.order | 1 |
+| tst.ts:12:24:12:40 | [ObjectPattern,Parameter] { args, context } | tst.ts:12:32:12:38 | [PropertyPattern] context | semmle.label | 2 |
+| tst.ts:12:24:12:40 | [ObjectPattern,Parameter] { args, context } | tst.ts:12:32:12:38 | [PropertyPattern] context | semmle.order | 2 |
+| tst.ts:12:26:12:29 | [PropertyPattern] args | tst.ts:12:26:12:29 | [Label] args | semmle.label | 1 |
+| tst.ts:12:26:12:29 | [PropertyPattern] args | tst.ts:12:26:12:29 | [Label] args | semmle.order | 1 |
+| tst.ts:12:26:12:29 | [PropertyPattern] args | tst.ts:12:26:12:29 | [VarDecl] args | semmle.label | 2 |
+| tst.ts:12:26:12:29 | [PropertyPattern] args | tst.ts:12:26:12:29 | [VarDecl] args | semmle.order | 2 |
+| tst.ts:12:32:12:38 | [PropertyPattern] context | tst.ts:12:32:12:38 | [Label] context | semmle.label | 1 |
+| tst.ts:12:32:12:38 | [PropertyPattern] context | tst.ts:12:32:12:38 | [Label] context | semmle.order | 1 |
+| tst.ts:12:32:12:38 | [PropertyPattern] context | tst.ts:12:32:12:38 | [VarDecl] context | semmle.label | 2 |
+| tst.ts:12:32:12:38 | [PropertyPattern] context | tst.ts:12:32:12:38 | [VarDecl] context | semmle.order | 2 |
+graphProperties
+| semmle.graphKind | tree |
diff --git a/javascript/ql/test/library-tests/AST/Decorators/printAst.ql b/javascript/ql/test/library-tests/AST/Decorators/printAst.ql
new file mode 100644
index 00000000000..248ea7ad396
--- /dev/null
+++ b/javascript/ql/test/library-tests/AST/Decorators/printAst.ql
@@ -0,0 +1,2 @@
+import javascript
+import semmle.javascript.PrintAst
diff --git a/javascript/ql/test/library-tests/AST/Decorators/tsconfig.json b/javascript/ql/test/library-tests/AST/Decorators/tsconfig.json
new file mode 100644
index 00000000000..fe851ed6b77
--- /dev/null
+++ b/javascript/ql/test/library-tests/AST/Decorators/tsconfig.json
@@ -0,0 +1,7 @@
+{
+ "compilerOptions": {
+ "experimentalDecorators": true
+ },
+ "include": ["**/*.ts"],
+ "lib": ["es2015", "dom"]
+}
\ No newline at end of file
diff --git a/javascript/ql/test/library-tests/AST/Decorators/tst.ts b/javascript/ql/test/library-tests/AST/Decorators/tst.ts
new file mode 100644
index 00000000000..f56ff5ed52d
--- /dev/null
+++ b/javascript/ql/test/library-tests/AST/Decorators/tst.ts
@@ -0,0 +1,14 @@
+const Dec: any = null;
+
+@Dec()
+export class OperatorResolvers {
+ @Dec()
+ @Dec()
+ operators(): void {}
+}
+
+const createMethodDecorator : any = null;
+
+createMethodDecorator(({ args, context }, next) => {
+
+});
\ No newline at end of file
diff --git a/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/printAst.expected b/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/printAst.expected
index 5a429553e69..32f8fa2bf31 100644
--- a/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/printAst.expected
+++ b/javascript/ql/test/library-tests/TypeScript/TypeAnnotations/printAst.expected
@@ -1292,16 +1292,16 @@ edges
| tst.ts:24:3:24:46 | [MethodSignature] takeNum ... umber); | tst.ts:24:3:24:18 | [Label] takeNumberMethod | semmle.order | 1 |
| tst.ts:24:3:24:46 | [MethodSignature] takeNum ... umber); | tst.ts:24:3:24:46 | [FunctionExpr] takeNum ... umber); | semmle.label | 2 |
| tst.ts:24:3:24:46 | [MethodSignature] takeNum ... umber); | tst.ts:24:3:24:46 | [FunctionExpr] takeNum ... umber); | semmle.order | 2 |
-| tst.ts:24:20:24:36 | [SimpleParameter] numberMethodParam | tst.ts:24:39:24:44 | [KeywordTypeExpr] number | semmle.label | 0 |
-| tst.ts:24:20:24:36 | [SimpleParameter] numberMethodParam | tst.ts:24:39:24:44 | [KeywordTypeExpr] number | semmle.order | 0 |
+| tst.ts:24:20:24:36 | [SimpleParameter] numberMethodParam | tst.ts:24:39:24:44 | [KeywordTypeExpr] number | semmle.label | -2 |
+| tst.ts:24:20:24:36 | [SimpleParameter] numberMethodParam | tst.ts:24:39:24:44 | [KeywordTypeExpr] number | semmle.order | -2 |
| tst.ts:25:3:25:55 | [FunctionExpr] takeInt ... rface); | file://:0:0:0:0 | (Parameters) | semmle.label | 1 |
| tst.ts:25:3:25:55 | [FunctionExpr] takeInt ... rface); | file://:0:0:0:0 | (Parameters) | semmle.order | 1 |
| tst.ts:25:3:25:55 | [MethodSignature] takeInt ... rface); | tst.ts:25:3:25:21 | [Label] takeInterfaceMethod | semmle.label | 1 |
| tst.ts:25:3:25:55 | [MethodSignature] takeInt ... rface); | tst.ts:25:3:25:21 | [Label] takeInterfaceMethod | semmle.order | 1 |
| tst.ts:25:3:25:55 | [MethodSignature] takeInt ... rface); | tst.ts:25:3:25:55 | [FunctionExpr] takeInt ... rface); | semmle.label | 2 |
| tst.ts:25:3:25:55 | [MethodSignature] takeInt ... rface); | tst.ts:25:3:25:55 | [FunctionExpr] takeInt ... rface); | semmle.order | 2 |
-| tst.ts:25:23:25:42 | [SimpleParameter] interfaceMethodParam | tst.ts:25:45:25:53 | [LocalTypeAccess] Interface | semmle.label | 0 |
-| tst.ts:25:23:25:42 | [SimpleParameter] interfaceMethodParam | tst.ts:25:45:25:53 | [LocalTypeAccess] Interface | semmle.order | 0 |
+| tst.ts:25:23:25:42 | [SimpleParameter] interfaceMethodParam | tst.ts:25:45:25:53 | [LocalTypeAccess] Interface | semmle.label | -2 |
+| tst.ts:25:23:25:42 | [SimpleParameter] interfaceMethodParam | tst.ts:25:45:25:53 | [LocalTypeAccess] Interface | semmle.order | -2 |
| tst.ts:28:1:28:28 | [DeclStmt] var interfaceVar = ... | tst.ts:28:5:28:27 | [VariableDeclarator] interfa ... terface | semmle.label | 1 |
| tst.ts:28:1:28:28 | [DeclStmt] var interfaceVar = ... | tst.ts:28:5:28:27 | [VariableDeclarator] interfa ... terface | semmle.order | 1 |
| tst.ts:28:5:28:27 | [VariableDeclarator] interfa ... terface | tst.ts:28:5:28:16 | [VarDecl] interfaceVar | semmle.label | 1 |
@@ -1344,30 +1344,30 @@ edges
| tst.ts:33:1:33:59 | [FunctionDeclStmt] functio ... ber) {} | tst.ts:33:10:33:27 | [VarDecl] takeNumberFunction | semmle.order | 0 |
| tst.ts:33:1:33:59 | [FunctionDeclStmt] functio ... ber) {} | tst.ts:33:58:33:59 | [BlockStmt] {} | semmle.label | 5 |
| tst.ts:33:1:33:59 | [FunctionDeclStmt] functio ... ber) {} | tst.ts:33:58:33:59 | [BlockStmt] {} | semmle.order | 5 |
-| tst.ts:33:29:33:47 | [SimpleParameter] numberFunctionParam | tst.ts:33:50:33:55 | [KeywordTypeExpr] number | semmle.label | 0 |
-| tst.ts:33:29:33:47 | [SimpleParameter] numberFunctionParam | tst.ts:33:50:33:55 | [KeywordTypeExpr] number | semmle.order | 0 |
+| tst.ts:33:29:33:47 | [SimpleParameter] numberFunctionParam | tst.ts:33:50:33:55 | [KeywordTypeExpr] number | semmle.label | -2 |
+| tst.ts:33:29:33:47 | [SimpleParameter] numberFunctionParam | tst.ts:33:50:33:55 | [KeywordTypeExpr] number | semmle.order | -2 |
| tst.ts:34:1:34:67 | [FunctionDeclStmt] functio ... ace) {} | file://:0:0:0:0 | (Parameters) | semmle.label | 1 |
| tst.ts:34:1:34:67 | [FunctionDeclStmt] functio ... ace) {} | file://:0:0:0:0 | (Parameters) | semmle.order | 1 |
| tst.ts:34:1:34:67 | [FunctionDeclStmt] functio ... ace) {} | tst.ts:34:10:34:30 | [VarDecl] takeInterfaceFunction | semmle.label | 0 |
| tst.ts:34:1:34:67 | [FunctionDeclStmt] functio ... ace) {} | tst.ts:34:10:34:30 | [VarDecl] takeInterfaceFunction | semmle.order | 0 |
| tst.ts:34:1:34:67 | [FunctionDeclStmt] functio ... ace) {} | tst.ts:34:66:34:67 | [BlockStmt] {} | semmle.label | 5 |
| tst.ts:34:1:34:67 | [FunctionDeclStmt] functio ... ace) {} | tst.ts:34:66:34:67 | [BlockStmt] {} | semmle.order | 5 |
-| tst.ts:34:32:34:52 | [SimpleParameter] interaceFunctionParam | tst.ts:34:55:34:63 | [LocalTypeAccess] Interface | semmle.label | 0 |
-| tst.ts:34:32:34:52 | [SimpleParameter] interaceFunctionParam | tst.ts:34:55:34:63 | [LocalTypeAccess] Interface | semmle.order | 0 |
+| tst.ts:34:32:34:52 | [SimpleParameter] interaceFunctionParam | tst.ts:34:55:34:63 | [LocalTypeAccess] Interface | semmle.label | -2 |
+| tst.ts:34:32:34:52 | [SimpleParameter] interaceFunctionParam | tst.ts:34:55:34:63 | [LocalTypeAccess] Interface | semmle.order | -2 |
| tst.ts:36:1:36:70 | [FunctionDeclStmt] functio ... '2') {} | file://:0:0:0:0 | (Parameters) | semmle.label | 1 |
| tst.ts:36:1:36:70 | [FunctionDeclStmt] functio ... '2') {} | file://:0:0:0:0 | (Parameters) | semmle.order | 1 |
| tst.ts:36:1:36:70 | [FunctionDeclStmt] functio ... '2') {} | tst.ts:36:10:36:25 | [VarDecl] typesAndDefaults | semmle.label | 0 |
| tst.ts:36:1:36:70 | [FunctionDeclStmt] functio ... '2') {} | tst.ts:36:10:36:25 | [VarDecl] typesAndDefaults | semmle.order | 0 |
| tst.ts:36:1:36:70 | [FunctionDeclStmt] functio ... '2') {} | tst.ts:36:69:36:70 | [BlockStmt] {} | semmle.label | 5 |
| tst.ts:36:1:36:70 | [FunctionDeclStmt] functio ... '2') {} | tst.ts:36:69:36:70 | [BlockStmt] {} | semmle.order | 5 |
-| tst.ts:36:27:36:32 | [SimpleParameter] param1 | tst.ts:36:35:36:40 | [KeywordTypeExpr] number | semmle.label | 0 |
-| tst.ts:36:27:36:32 | [SimpleParameter] param1 | tst.ts:36:35:36:40 | [KeywordTypeExpr] number | semmle.order | 0 |
-| tst.ts:36:27:36:32 | [SimpleParameter] param1 | tst.ts:36:44:36:44 | [Literal] 1 | semmle.label | 1 |
-| tst.ts:36:27:36:32 | [SimpleParameter] param1 | tst.ts:36:44:36:44 | [Literal] 1 | semmle.order | 1 |
-| tst.ts:36:47:36:52 | [SimpleParameter] param2 | tst.ts:36:55:36:60 | [KeywordTypeExpr] string | semmle.label | 0 |
-| tst.ts:36:47:36:52 | [SimpleParameter] param2 | tst.ts:36:55:36:60 | [KeywordTypeExpr] string | semmle.order | 0 |
-| tst.ts:36:47:36:52 | [SimpleParameter] param2 | tst.ts:36:64:36:66 | [Literal] '2' | semmle.label | 1 |
-| tst.ts:36:47:36:52 | [SimpleParameter] param2 | tst.ts:36:64:36:66 | [Literal] '2' | semmle.order | 1 |
+| tst.ts:36:27:36:32 | [SimpleParameter] param1 | tst.ts:36:35:36:40 | [KeywordTypeExpr] number | semmle.label | -2 |
+| tst.ts:36:27:36:32 | [SimpleParameter] param1 | tst.ts:36:35:36:40 | [KeywordTypeExpr] number | semmle.order | -2 |
+| tst.ts:36:27:36:32 | [SimpleParameter] param1 | tst.ts:36:44:36:44 | [Literal] 1 | semmle.label | -1 |
+| tst.ts:36:27:36:32 | [SimpleParameter] param1 | tst.ts:36:44:36:44 | [Literal] 1 | semmle.order | -1 |
+| tst.ts:36:47:36:52 | [SimpleParameter] param2 | tst.ts:36:55:36:60 | [KeywordTypeExpr] string | semmle.label | -2 |
+| tst.ts:36:47:36:52 | [SimpleParameter] param2 | tst.ts:36:55:36:60 | [KeywordTypeExpr] string | semmle.order | -2 |
+| tst.ts:36:47:36:52 | [SimpleParameter] param2 | tst.ts:36:64:36:66 | [Literal] '2' | semmle.label | -1 |
+| tst.ts:36:47:36:52 | [SimpleParameter] param2 | tst.ts:36:64:36:66 | [Literal] '2' | semmle.order | -1 |
| tst.ts:38:1:38:23 | [DeclStmt] var arrayType = ... | tst.ts:38:5:38:23 | [VariableDeclarator] arrayType: string[] | semmle.label | 1 |
| tst.ts:38:1:38:23 | [DeclStmt] var arrayType = ... | tst.ts:38:5:38:23 | [VariableDeclarator] arrayType: string[] | semmle.order | 1 |
| tst.ts:38:5:38:23 | [VariableDeclarator] arrayType: string[] | tst.ts:38:5:38:13 | [VarDecl] arrayType | semmle.label | 1 |
@@ -1734,8 +1734,8 @@ edges
| tst.ts:80:1:80:73 | [FunctionDeclStmt] functio ... alse; } | tst.ts:80:36:80:55 | [IsTypeExpr] x is Generic | semmle.order | 4 |
| tst.ts:80:1:80:73 | [FunctionDeclStmt] functio ... alse; } | tst.ts:80:57:80:73 | [BlockStmt] { return false; } | semmle.label | 5 |
| tst.ts:80:1:80:73 | [FunctionDeclStmt] functio ... alse; } | tst.ts:80:57:80:73 | [BlockStmt] { return false; } | semmle.order | 5 |
-| tst.ts:80:24:80:24 | [SimpleParameter] x | tst.ts:80:27:80:32 | [KeywordTypeExpr] number | semmle.label | 0 |
-| tst.ts:80:24:80:24 | [SimpleParameter] x | tst.ts:80:27:80:32 | [KeywordTypeExpr] number | semmle.order | 0 |
+| tst.ts:80:24:80:24 | [SimpleParameter] x | tst.ts:80:27:80:32 | [KeywordTypeExpr] number | semmle.label | -2 |
+| tst.ts:80:24:80:24 | [SimpleParameter] x | tst.ts:80:27:80:32 | [KeywordTypeExpr] number | semmle.order | -2 |
| tst.ts:80:36:80:55 | [IsTypeExpr] x is Generic | tst.ts:80:36:80:36 | [LocalVarTypeAccess] x | semmle.label | 1 |
| tst.ts:80:36:80:55 | [IsTypeExpr] x is Generic | tst.ts:80:36:80:36 | [LocalVarTypeAccess] x | semmle.order | 1 |
| tst.ts:80:36:80:55 | [IsTypeExpr] x is Generic | tst.ts:80:41:80:55 | [GenericTypeExpr] Generic | semmle.label | 2 |
@@ -1758,8 +1758,8 @@ edges
| tst.ts:81:1:81:66 | [FunctionDeclStmt] functio ... true } | tst.ts:81:38:81:50 | [IsTypeExpr] x is typeof x | semmle.order | 4 |
| tst.ts:81:1:81:66 | [FunctionDeclStmt] functio ... true } | tst.ts:81:52:81:66 | [BlockStmt] { return true } | semmle.label | 5 |
| tst.ts:81:1:81:66 | [FunctionDeclStmt] functio ... true } | tst.ts:81:52:81:66 | [BlockStmt] { return true } | semmle.order | 5 |
-| tst.ts:81:24:81:24 | [SimpleParameter] x | tst.ts:81:27:81:34 | [ArrayTypeExpr] string[] | semmle.label | 0 |
-| tst.ts:81:24:81:24 | [SimpleParameter] x | tst.ts:81:27:81:34 | [ArrayTypeExpr] string[] | semmle.order | 0 |
+| tst.ts:81:24:81:24 | [SimpleParameter] x | tst.ts:81:27:81:34 | [ArrayTypeExpr] string[] | semmle.label | -2 |
+| tst.ts:81:24:81:24 | [SimpleParameter] x | tst.ts:81:27:81:34 | [ArrayTypeExpr] string[] | semmle.order | -2 |
| tst.ts:81:27:81:34 | [ArrayTypeExpr] string[] | tst.ts:81:27:81:32 | [KeywordTypeExpr] string | semmle.label | 1 |
| tst.ts:81:27:81:34 | [ArrayTypeExpr] string[] | tst.ts:81:27:81:32 | [KeywordTypeExpr] string | semmle.order | 1 |
| tst.ts:81:38:81:50 | [IsTypeExpr] x is typeof x | tst.ts:81:38:81:38 | [LocalVarTypeAccess] x | semmle.label | 1 |
@@ -1832,8 +1832,8 @@ edges
| tst.ts:88:20:88:44 | [FunctionExpr] (param: ... number | tst.ts:88:39:88:44 | [KeywordTypeExpr] number | semmle.order | 4 |
| tst.ts:88:20:88:44 | [FunctionTypeExpr] (param: ... number | tst.ts:88:20:88:44 | [FunctionExpr] (param: ... number | semmle.label | 1 |
| tst.ts:88:20:88:44 | [FunctionTypeExpr] (param: ... number | tst.ts:88:20:88:44 | [FunctionExpr] (param: ... number | semmle.order | 1 |
-| tst.ts:88:21:88:25 | [SimpleParameter] param | tst.ts:88:28:88:33 | [KeywordTypeExpr] string | semmle.label | 0 |
-| tst.ts:88:21:88:25 | [SimpleParameter] param | tst.ts:88:28:88:33 | [KeywordTypeExpr] string | semmle.order | 0 |
+| tst.ts:88:21:88:25 | [SimpleParameter] param | tst.ts:88:28:88:33 | [KeywordTypeExpr] string | semmle.label | -2 |
+| tst.ts:88:21:88:25 | [SimpleParameter] param | tst.ts:88:28:88:33 | [KeywordTypeExpr] string | semmle.order | -2 |
| tst.ts:89:1:89:38 | [DeclStmt] var functionType3 = ... | tst.ts:89:5:89:37 | [VariableDeclarator] functio ... T) => T | semmle.label | 1 |
| tst.ts:89:1:89:38 | [DeclStmt] var functionType3 = ... | tst.ts:89:5:89:37 | [VariableDeclarator] functio ... T) => T | semmle.order | 1 |
| tst.ts:89:5:89:37 | [VariableDeclarator] functio ... T) => T | tst.ts:89:5:89:17 | [VarDecl] functionType3 | semmle.label | 1 |
@@ -1850,8 +1850,8 @@ edges
| tst.ts:89:20:89:37 | [FunctionTypeExpr] (param: T) => T | tst.ts:89:20:89:37 | [FunctionExpr] (param: T) => T | semmle.order | 1 |
| tst.ts:89:21:89:21 | [TypeParameter] T | tst.ts:89:21:89:21 | [Identifier] T | semmle.label | 1 |
| tst.ts:89:21:89:21 | [TypeParameter] T | tst.ts:89:21:89:21 | [Identifier] T | semmle.order | 1 |
-| tst.ts:89:24:89:28 | [SimpleParameter] param | tst.ts:89:31:89:31 | [LocalTypeAccess] T | semmle.label | 0 |
-| tst.ts:89:24:89:28 | [SimpleParameter] param | tst.ts:89:31:89:31 | [LocalTypeAccess] T | semmle.order | 0 |
+| tst.ts:89:24:89:28 | [SimpleParameter] param | tst.ts:89:31:89:31 | [LocalTypeAccess] T | semmle.label | -2 |
+| tst.ts:89:24:89:28 | [SimpleParameter] param | tst.ts:89:31:89:31 | [LocalTypeAccess] T | semmle.order | -2 |
| tst.ts:90:1:90:39 | [DeclStmt] var constructorType1 = ... | tst.ts:90:5:90:38 | [VariableDeclarator] constru ... Object | semmle.label | 1 |
| tst.ts:90:1:90:39 | [DeclStmt] var constructorType1 = ... | tst.ts:90:5:90:38 | [VariableDeclarator] constru ... Object | semmle.order | 1 |
| tst.ts:90:5:90:38 | [VariableDeclarator] constru ... Object | tst.ts:90:5:90:20 | [VarDecl] constructorType1 | semmle.label | 1 |
@@ -1874,8 +1874,8 @@ edges
| tst.ts:91:23:91:51 | [FunctionExpr] new (pa ... Object | tst.ts:91:46:91:51 | [LocalTypeAccess] Object | semmle.order | 4 |
| tst.ts:91:23:91:51 | [FunctionTypeExpr] new (pa ... Object | tst.ts:91:23:91:51 | [FunctionExpr] new (pa ... Object | semmle.label | 1 |
| tst.ts:91:23:91:51 | [FunctionTypeExpr] new (pa ... Object | tst.ts:91:23:91:51 | [FunctionExpr] new (pa ... Object | semmle.order | 1 |
-| tst.ts:91:28:91:32 | [SimpleParameter] param | tst.ts:91:35:91:40 | [KeywordTypeExpr] string | semmle.label | 0 |
-| tst.ts:91:28:91:32 | [SimpleParameter] param | tst.ts:91:35:91:40 | [KeywordTypeExpr] string | semmle.order | 0 |
+| tst.ts:91:28:91:32 | [SimpleParameter] param | tst.ts:91:35:91:40 | [KeywordTypeExpr] string | semmle.label | -2 |
+| tst.ts:91:28:91:32 | [SimpleParameter] param | tst.ts:91:35:91:40 | [KeywordTypeExpr] string | semmle.order | -2 |
| tst.ts:92:1:92:50 | [DeclStmt] var constructorType3 = ... | tst.ts:92:5:92:49 | [VariableDeclarator] constru ... Object | semmle.label | 1 |
| tst.ts:92:1:92:50 | [DeclStmt] var constructorType3 = ... | tst.ts:92:5:92:49 | [VariableDeclarator] constru ... Object | semmle.order | 1 |
| tst.ts:92:5:92:49 | [VariableDeclarator] constru ... Object | tst.ts:92:5:92:20 | [VarDecl] constructorType3 | semmle.label | 1 |
@@ -1892,8 +1892,8 @@ edges
| tst.ts:92:23:92:49 | [FunctionTypeExpr] new ... Object | tst.ts:92:23:92:49 | [FunctionExpr] new ... Object | semmle.order | 1 |
| tst.ts:92:28:92:28 | [TypeParameter] T | tst.ts:92:28:92:28 | [Identifier] T | semmle.label | 1 |
| tst.ts:92:28:92:28 | [TypeParameter] T | tst.ts:92:28:92:28 | [Identifier] T | semmle.order | 1 |
-| tst.ts:92:31:92:35 | [SimpleParameter] param | tst.ts:92:38:92:38 | [LocalTypeAccess] T | semmle.label | 0 |
-| tst.ts:92:31:92:35 | [SimpleParameter] param | tst.ts:92:38:92:38 | [LocalTypeAccess] T | semmle.order | 0 |
+| tst.ts:92:31:92:35 | [SimpleParameter] param | tst.ts:92:38:92:38 | [LocalTypeAccess] T | semmle.label | -2 |
+| tst.ts:92:31:92:35 | [SimpleParameter] param | tst.ts:92:38:92:38 | [LocalTypeAccess] T | semmle.order | -2 |
| tst.ts:94:1:94:37 | [FunctionDeclStmt] functio ... rn x; } | file://:0:0:0:0 | (Parameters) | semmle.label | 1 |
| tst.ts:94:1:94:37 | [FunctionDeclStmt] functio ... rn x; } | file://:0:0:0:0 | (Parameters) | semmle.order | 1 |
| tst.ts:94:1:94:37 | [FunctionDeclStmt] functio ... rn x; } | file://:0:0:0:0 | (TypeParameters) | semmle.label | 2 |
@@ -1906,8 +1906,8 @@ edges
| tst.ts:94:1:94:37 | [FunctionDeclStmt] functio ... rn x; } | tst.ts:94:25:94:37 | [BlockStmt] { return x; } | semmle.order | 5 |
| tst.ts:94:13:94:13 | [TypeParameter] S | tst.ts:94:13:94:13 | [Identifier] S | semmle.label | 1 |
| tst.ts:94:13:94:13 | [TypeParameter] S | tst.ts:94:13:94:13 | [Identifier] S | semmle.order | 1 |
-| tst.ts:94:16:94:16 | [SimpleParameter] x | tst.ts:94:19:94:19 | [LocalTypeAccess] S | semmle.label | 0 |
-| tst.ts:94:16:94:16 | [SimpleParameter] x | tst.ts:94:19:94:19 | [LocalTypeAccess] S | semmle.order | 0 |
+| tst.ts:94:16:94:16 | [SimpleParameter] x | tst.ts:94:19:94:19 | [LocalTypeAccess] S | semmle.label | -2 |
+| tst.ts:94:16:94:16 | [SimpleParameter] x | tst.ts:94:19:94:19 | [LocalTypeAccess] S | semmle.order | -2 |
| tst.ts:94:25:94:37 | [BlockStmt] { return x; } | tst.ts:94:27:94:35 | [ReturnStmt] return x; | semmle.label | 1 |
| tst.ts:94:25:94:37 | [BlockStmt] { return x; } | tst.ts:94:27:94:35 | [ReturnStmt] return x; | semmle.order | 1 |
| tst.ts:94:27:94:35 | [ReturnStmt] return x; | tst.ts:94:34:94:34 | [VarRef] x | semmle.label | 1 |
@@ -1926,10 +1926,10 @@ edges
| tst.ts:95:13:95:13 | [TypeParameter] S | tst.ts:95:13:95:13 | [Identifier] S | semmle.order | 1 |
| tst.ts:95:15:95:15 | [TypeParameter] T | tst.ts:95:15:95:15 | [Identifier] T | semmle.label | 1 |
| tst.ts:95:15:95:15 | [TypeParameter] T | tst.ts:95:15:95:15 | [Identifier] T | semmle.order | 1 |
-| tst.ts:95:18:95:18 | [SimpleParameter] x | tst.ts:95:21:95:21 | [LocalTypeAccess] S | semmle.label | 0 |
-| tst.ts:95:18:95:18 | [SimpleParameter] x | tst.ts:95:21:95:21 | [LocalTypeAccess] S | semmle.order | 0 |
-| tst.ts:95:24:95:24 | [SimpleParameter] y | tst.ts:95:27:95:27 | [LocalTypeAccess] T | semmle.label | 0 |
-| tst.ts:95:24:95:24 | [SimpleParameter] y | tst.ts:95:27:95:27 | [LocalTypeAccess] T | semmle.order | 0 |
+| tst.ts:95:18:95:18 | [SimpleParameter] x | tst.ts:95:21:95:21 | [LocalTypeAccess] S | semmle.label | -2 |
+| tst.ts:95:18:95:18 | [SimpleParameter] x | tst.ts:95:21:95:21 | [LocalTypeAccess] S | semmle.order | -2 |
+| tst.ts:95:24:95:24 | [SimpleParameter] y | tst.ts:95:27:95:27 | [LocalTypeAccess] T | semmle.label | -2 |
+| tst.ts:95:24:95:24 | [SimpleParameter] y | tst.ts:95:27:95:27 | [LocalTypeAccess] T | semmle.order | -2 |
| tst.ts:95:31:95:35 | [TupleTypeExpr] [S,T] | tst.ts:95:32:95:32 | [LocalTypeAccess] S | semmle.label | 1 |
| tst.ts:95:31:95:35 | [TupleTypeExpr] [S,T] | tst.ts:95:32:95:32 | [LocalTypeAccess] S | semmle.order | 1 |
| tst.ts:95:31:95:35 | [TupleTypeExpr] [S,T] | tst.ts:95:34:95:34 | [LocalTypeAccess] T | semmle.label | 2 |
@@ -1956,8 +1956,8 @@ edges
| tst.ts:96:13:96:28 | [TypeParameter] S extends number | tst.ts:96:13:96:13 | [Identifier] S | semmle.order | 1 |
| tst.ts:96:13:96:28 | [TypeParameter] S extends number | tst.ts:96:23:96:28 | [KeywordTypeExpr] number | semmle.label | 2 |
| tst.ts:96:13:96:28 | [TypeParameter] S extends number | tst.ts:96:23:96:28 | [KeywordTypeExpr] number | semmle.order | 2 |
-| tst.ts:96:31:96:31 | [SimpleParameter] x | tst.ts:96:34:96:34 | [LocalTypeAccess] S | semmle.label | 0 |
-| tst.ts:96:31:96:31 | [SimpleParameter] x | tst.ts:96:34:96:34 | [LocalTypeAccess] S | semmle.order | 0 |
+| tst.ts:96:31:96:31 | [SimpleParameter] x | tst.ts:96:34:96:34 | [LocalTypeAccess] S | semmle.label | -2 |
+| tst.ts:96:31:96:31 | [SimpleParameter] x | tst.ts:96:34:96:34 | [LocalTypeAccess] S | semmle.order | -2 |
| tst.ts:96:40:96:52 | [BlockStmt] { return x; } | tst.ts:96:42:96:50 | [ReturnStmt] return x; | semmle.label | 1 |
| tst.ts:96:40:96:52 | [BlockStmt] { return x; } | tst.ts:96:42:96:50 | [ReturnStmt] return x; | semmle.order | 1 |
| tst.ts:96:42:96:50 | [ReturnStmt] return x; | tst.ts:96:49:96:49 | [VarRef] x | semmle.label | 1 |
@@ -2132,10 +2132,10 @@ edges
| tst.ts:116:1:116:58 | [FunctionDeclStmt] functio ... ing) {} | tst.ts:116:29:116:32 | [KeywordTypeExpr] void | semmle.order | 3 |
| tst.ts:116:1:116:58 | [FunctionDeclStmt] functio ... ing) {} | tst.ts:116:57:116:58 | [BlockStmt] {} | semmle.label | 5 |
| tst.ts:116:1:116:58 | [FunctionDeclStmt] functio ... ing) {} | tst.ts:116:57:116:58 | [BlockStmt] {} | semmle.order | 5 |
-| tst.ts:116:35:116:35 | [SimpleParameter] x | tst.ts:116:38:116:43 | [KeywordTypeExpr] number | semmle.label | 0 |
-| tst.ts:116:35:116:35 | [SimpleParameter] x | tst.ts:116:38:116:43 | [KeywordTypeExpr] number | semmle.order | 0 |
-| tst.ts:116:46:116:46 | [SimpleParameter] y | tst.ts:116:49:116:54 | [KeywordTypeExpr] string | semmle.label | 0 |
-| tst.ts:116:46:116:46 | [SimpleParameter] y | tst.ts:116:49:116:54 | [KeywordTypeExpr] string | semmle.order | 0 |
+| tst.ts:116:35:116:35 | [SimpleParameter] x | tst.ts:116:38:116:43 | [KeywordTypeExpr] number | semmle.label | -2 |
+| tst.ts:116:35:116:35 | [SimpleParameter] x | tst.ts:116:38:116:43 | [KeywordTypeExpr] number | semmle.order | -2 |
+| tst.ts:116:46:116:46 | [SimpleParameter] y | tst.ts:116:49:116:54 | [KeywordTypeExpr] string | semmle.label | -2 |
+| tst.ts:116:46:116:46 | [SimpleParameter] y | tst.ts:116:49:116:54 | [KeywordTypeExpr] string | semmle.order | -2 |
| tst.ts:118:1:120:1 | [InterfaceDeclaration,TypeDefinition] interfa ... ram); } | tst.ts:118:11:118:32 | [Identifier] InterfaceWithThisParam | semmle.label | 1 |
| tst.ts:118:1:120:1 | [InterfaceDeclaration,TypeDefinition] interfa ... ram); } | tst.ts:118:11:118:32 | [Identifier] InterfaceWithThisParam | semmle.order | 1 |
| tst.ts:118:1:120:1 | [InterfaceDeclaration,TypeDefinition] interfa ... ram); } | tst.ts:119:3:119:45 | [MethodSignature] hasThis ... Param); | semmle.label | 2 |
@@ -2326,10 +2326,10 @@ edges
| tst.ts:142:1:146:1 | [FunctionDeclStmt] functio ... ) } } | tst.ts:142:48:142:64 | [PredicateTypeExpr] asserts condition | semmle.order | 4 |
| tst.ts:142:1:146:1 | [FunctionDeclStmt] functio ... ) } } | tst.ts:142:66:146:1 | [BlockStmt] { if ... ) } } | semmle.label | 5 |
| tst.ts:142:1:146:1 | [FunctionDeclStmt] functio ... ) } } | tst.ts:142:66:146:1 | [BlockStmt] { if ... ) } } | semmle.order | 5 |
-| tst.ts:142:17:142:25 | [SimpleParameter] condition | tst.ts:142:28:142:30 | [KeywordTypeExpr] any | semmle.label | 0 |
-| tst.ts:142:17:142:25 | [SimpleParameter] condition | tst.ts:142:28:142:30 | [KeywordTypeExpr] any | semmle.order | 0 |
-| tst.ts:142:33:142:35 | [SimpleParameter] msg | tst.ts:142:39:142:44 | [KeywordTypeExpr] string | semmle.label | 0 |
-| tst.ts:142:33:142:35 | [SimpleParameter] msg | tst.ts:142:39:142:44 | [KeywordTypeExpr] string | semmle.order | 0 |
+| tst.ts:142:17:142:25 | [SimpleParameter] condition | tst.ts:142:28:142:30 | [KeywordTypeExpr] any | semmle.label | -2 |
+| tst.ts:142:17:142:25 | [SimpleParameter] condition | tst.ts:142:28:142:30 | [KeywordTypeExpr] any | semmle.order | -2 |
+| tst.ts:142:33:142:35 | [SimpleParameter] msg | tst.ts:142:39:142:44 | [KeywordTypeExpr] string | semmle.label | -2 |
+| tst.ts:142:33:142:35 | [SimpleParameter] msg | tst.ts:142:39:142:44 | [KeywordTypeExpr] string | semmle.order | -2 |
| tst.ts:142:48:142:64 | [PredicateTypeExpr] asserts condition | tst.ts:142:56:142:64 | [LocalVarTypeAccess] condition | semmle.label | 1 |
| tst.ts:142:48:142:64 | [PredicateTypeExpr] asserts condition | tst.ts:142:56:142:64 | [LocalVarTypeAccess] condition | semmle.order | 1 |
| tst.ts:142:66:146:1 | [BlockStmt] { if ... ) } } | tst.ts:143:3:145:3 | [IfStmt] if (!co ... sg) } | semmle.label | 1 |
@@ -2356,8 +2356,8 @@ edges
| tst.ts:148:1:152:1 | [FunctionDeclStmt] functio ... ; } } | tst.ts:148:36:148:56 | [IsTypeExpr] asserts ... string | semmle.order | 4 |
| tst.ts:148:1:152:1 | [FunctionDeclStmt] functio ... ; } } | tst.ts:148:58:152:1 | [BlockStmt] { if ... ; } } | semmle.label | 5 |
| tst.ts:148:1:152:1 | [FunctionDeclStmt] functio ... ; } } | tst.ts:148:58:152:1 | [BlockStmt] { if ... ; } } | semmle.order | 5 |
-| tst.ts:148:25:148:27 | [SimpleParameter] val | tst.ts:148:30:148:32 | [KeywordTypeExpr] any | semmle.label | 0 |
-| tst.ts:148:25:148:27 | [SimpleParameter] val | tst.ts:148:30:148:32 | [KeywordTypeExpr] any | semmle.order | 0 |
+| tst.ts:148:25:148:27 | [SimpleParameter] val | tst.ts:148:30:148:32 | [KeywordTypeExpr] any | semmle.label | -2 |
+| tst.ts:148:25:148:27 | [SimpleParameter] val | tst.ts:148:30:148:32 | [KeywordTypeExpr] any | semmle.order | -2 |
| tst.ts:148:36:148:56 | [IsTypeExpr] asserts ... string | tst.ts:148:44:148:46 | [LocalVarTypeAccess] val | semmle.label | 1 |
| tst.ts:148:36:148:56 | [IsTypeExpr] asserts ... string | tst.ts:148:44:148:46 | [LocalVarTypeAccess] val | semmle.order | 1 |
| tst.ts:148:36:148:56 | [IsTypeExpr] asserts ... string | tst.ts:148:51:148:56 | [KeywordTypeExpr] string | semmle.label | 2 |
@@ -2396,8 +2396,8 @@ edges
| tst.ts:157:15:157:29 | [TypeParameter] T extends any[] | tst.ts:157:25:157:29 | [ArrayTypeExpr] any[] | semmle.order | 2 |
| tst.ts:157:25:157:29 | [ArrayTypeExpr] any[] | tst.ts:157:25:157:27 | [KeywordTypeExpr] any | semmle.label | 1 |
| tst.ts:157:25:157:29 | [ArrayTypeExpr] any[] | tst.ts:157:25:157:27 | [KeywordTypeExpr] any | semmle.order | 1 |
-| tst.ts:157:32:157:34 | [SimpleParameter] arr | tst.ts:157:37:157:56 | [ReadonlyTypeExpr] readonly [any, ...T] | semmle.label | 0 |
-| tst.ts:157:32:157:34 | [SimpleParameter] arr | tst.ts:157:37:157:56 | [ReadonlyTypeExpr] readonly [any, ...T] | semmle.order | 0 |
+| tst.ts:157:32:157:34 | [SimpleParameter] arr | tst.ts:157:37:157:56 | [ReadonlyTypeExpr] readonly [any, ...T] | semmle.label | -2 |
+| tst.ts:157:32:157:34 | [SimpleParameter] arr | tst.ts:157:37:157:56 | [ReadonlyTypeExpr] readonly [any, ...T] | semmle.order | -2 |
| tst.ts:157:37:157:56 | [ReadonlyTypeExpr] readonly [any, ...T] | tst.ts:157:46:157:56 | [TupleTypeExpr] [any, ...T] | semmle.label | 1 |
| tst.ts:157:37:157:56 | [ReadonlyTypeExpr] readonly [any, ...T] | tst.ts:157:46:157:56 | [TupleTypeExpr] [any, ...T] | semmle.order | 1 |
| tst.ts:157:46:157:56 | [TupleTypeExpr] [any, ...T] | tst.ts:157:47:157:49 | [KeywordTypeExpr] any | semmle.label | 1 |
@@ -2448,10 +2448,10 @@ edges
| tst.ts:164:32:164:44 | [TypeParameter] U extends Arr | tst.ts:164:32:164:32 | [Identifier] U | semmle.order | 1 |
| tst.ts:164:32:164:44 | [TypeParameter] U extends Arr | tst.ts:164:42:164:44 | [LocalTypeAccess] Arr | semmle.label | 2 |
| tst.ts:164:32:164:44 | [TypeParameter] U extends Arr | tst.ts:164:42:164:44 | [LocalTypeAccess] Arr | semmle.order | 2 |
-| tst.ts:164:47:164:50 | [SimpleParameter] arr1 | tst.ts:164:53:164:53 | [LocalTypeAccess] T | semmle.label | 0 |
-| tst.ts:164:47:164:50 | [SimpleParameter] arr1 | tst.ts:164:53:164:53 | [LocalTypeAccess] T | semmle.order | 0 |
-| tst.ts:164:56:164:59 | [SimpleParameter] arr2 | tst.ts:164:62:164:62 | [LocalTypeAccess] U | semmle.label | 0 |
-| tst.ts:164:56:164:59 | [SimpleParameter] arr2 | tst.ts:164:62:164:62 | [LocalTypeAccess] U | semmle.order | 0 |
+| tst.ts:164:47:164:50 | [SimpleParameter] arr1 | tst.ts:164:53:164:53 | [LocalTypeAccess] T | semmle.label | -2 |
+| tst.ts:164:47:164:50 | [SimpleParameter] arr1 | tst.ts:164:53:164:53 | [LocalTypeAccess] T | semmle.order | -2 |
+| tst.ts:164:56:164:59 | [SimpleParameter] arr2 | tst.ts:164:62:164:62 | [LocalTypeAccess] U | semmle.label | -2 |
+| tst.ts:164:56:164:59 | [SimpleParameter] arr2 | tst.ts:164:62:164:62 | [LocalTypeAccess] U | semmle.order | -2 |
| tst.ts:164:66:164:77 | [TupleTypeExpr] [...T, ...U] | tst.ts:164:67:164:70 | [RestTypeExpr] ...T | semmle.label | 1 |
| tst.ts:164:66:164:77 | [TupleTypeExpr] [...T, ...U] | tst.ts:164:67:164:70 | [RestTypeExpr] ...T | semmle.order | 1 |
| tst.ts:164:66:164:77 | [TupleTypeExpr] [...T, ...U] | tst.ts:164:73:164:76 | [RestTypeExpr] ...U | semmle.label | 2 |
@@ -2480,8 +2480,8 @@ edges
| tst.ts:169:1:172:1 | [FunctionDeclStmt] functio ... + b; } | tst.ts:169:68:169:73 | [KeywordTypeExpr] number | semmle.order | 4 |
| tst.ts:169:1:172:1 | [FunctionDeclStmt] functio ... + b; } | tst.ts:169:75:172:1 | [BlockStmt] { let ... + b; } | semmle.label | 5 |
| tst.ts:169:1:172:1 | [FunctionDeclStmt] functio ... + b; } | tst.ts:169:75:172:1 | [BlockStmt] { let ... + b; } | semmle.order | 5 |
-| tst.ts:169:31:169:31 | [SimpleParameter] x | tst.ts:169:34:169:64 | [TupleTypeExpr] [first: ... number] | semmle.label | 0 |
-| tst.ts:169:31:169:31 | [SimpleParameter] x | tst.ts:169:34:169:64 | [TupleTypeExpr] [first: ... number] | semmle.order | 0 |
+| tst.ts:169:31:169:31 | [SimpleParameter] x | tst.ts:169:34:169:64 | [TupleTypeExpr] [first: ... number] | semmle.label | -2 |
+| tst.ts:169:31:169:31 | [SimpleParameter] x | tst.ts:169:34:169:64 | [TupleTypeExpr] [first: ... number] | semmle.order | -2 |
| tst.ts:169:34:169:64 | [TupleTypeExpr] [first: ... number] | tst.ts:169:35:169:39 | [Identifier] first | semmle.label | 1 |
| tst.ts:169:34:169:64 | [TupleTypeExpr] [first: ... number] | tst.ts:169:35:169:39 | [Identifier] first | semmle.order | 1 |
| tst.ts:169:34:169:64 | [TupleTypeExpr] [first: ... number] | tst.ts:169:42:169:47 | [KeywordTypeExpr] number | semmle.label | 2 |
@@ -2622,8 +2622,8 @@ edges
| tst.ts:192:1:194:1 | [FunctionDeclStmt] functio ... rn x; } | tst.ts:192:47:192:70 | [TupleTypeExpr] [number ... number] | semmle.order | 4 |
| tst.ts:192:1:194:1 | [FunctionDeclStmt] functio ... rn x; } | tst.ts:192:72:194:1 | [BlockStmt] { return x; } | semmle.label | 5 |
| tst.ts:192:1:194:1 | [FunctionDeclStmt] functio ... rn x; } | tst.ts:192:72:194:1 | [BlockStmt] { return x; } | semmle.order | 5 |
-| tst.ts:192:18:192:18 | [SimpleParameter] x | tst.ts:192:21:192:43 | [TupleTypeExpr] [first: ... number] | semmle.label | 0 |
-| tst.ts:192:18:192:18 | [SimpleParameter] x | tst.ts:192:21:192:43 | [TupleTypeExpr] [first: ... number] | semmle.order | 0 |
+| tst.ts:192:18:192:18 | [SimpleParameter] x | tst.ts:192:21:192:43 | [TupleTypeExpr] [first: ... number] | semmle.label | -2 |
+| tst.ts:192:18:192:18 | [SimpleParameter] x | tst.ts:192:21:192:43 | [TupleTypeExpr] [first: ... number] | semmle.order | -2 |
| tst.ts:192:21:192:43 | [TupleTypeExpr] [first: ... number] | tst.ts:192:22:192:26 | [Identifier] first | semmle.label | 1 |
| tst.ts:192:21:192:43 | [TupleTypeExpr] [first: ... number] | tst.ts:192:22:192:26 | [Identifier] first | semmle.order | 1 |
| tst.ts:192:21:192:43 | [TupleTypeExpr] [first: ... number] | tst.ts:192:29:192:34 | [KeywordTypeExpr] number | semmle.label | 2 |
diff --git a/javascript/ql/test/library-tests/TypeScript/Types/printAst.expected b/javascript/ql/test/library-tests/TypeScript/Types/printAst.expected
index 2d553ec5df3..e650e55fccf 100644
--- a/javascript/ql/test/library-tests/TypeScript/Types/printAst.expected
+++ b/javascript/ql/test/library-tests/TypeScript/Types/printAst.expected
@@ -2155,10 +2155,10 @@ edges
| tst.ts:14:1:14:63 | [FunctionDeclStmt] functio ... + y; } | tst.ts:14:40:14:45 | [KeywordTypeExpr] string | semmle.order | 4 |
| tst.ts:14:1:14:63 | [FunctionDeclStmt] functio ... + y; } | tst.ts:14:47:14:63 | [BlockStmt] { return x + y; } | semmle.label | 5 |
| tst.ts:14:1:14:63 | [FunctionDeclStmt] functio ... + y; } | tst.ts:14:47:14:63 | [BlockStmt] { return x + y; } | semmle.order | 5 |
-| tst.ts:14:17:14:17 | [SimpleParameter] x | tst.ts:14:20:14:25 | [KeywordTypeExpr] string | semmle.label | 0 |
-| tst.ts:14:17:14:17 | [SimpleParameter] x | tst.ts:14:20:14:25 | [KeywordTypeExpr] string | semmle.order | 0 |
-| tst.ts:14:28:14:28 | [SimpleParameter] y | tst.ts:14:31:14:36 | [KeywordTypeExpr] string | semmle.label | 0 |
-| tst.ts:14:28:14:28 | [SimpleParameter] y | tst.ts:14:31:14:36 | [KeywordTypeExpr] string | semmle.order | 0 |
+| tst.ts:14:17:14:17 | [SimpleParameter] x | tst.ts:14:20:14:25 | [KeywordTypeExpr] string | semmle.label | -2 |
+| tst.ts:14:17:14:17 | [SimpleParameter] x | tst.ts:14:20:14:25 | [KeywordTypeExpr] string | semmle.order | -2 |
+| tst.ts:14:28:14:28 | [SimpleParameter] y | tst.ts:14:31:14:36 | [KeywordTypeExpr] string | semmle.label | -2 |
+| tst.ts:14:28:14:28 | [SimpleParameter] y | tst.ts:14:31:14:36 | [KeywordTypeExpr] string | semmle.order | -2 |
| tst.ts:14:47:14:63 | [BlockStmt] { return x + y; } | tst.ts:14:49:14:61 | [ReturnStmt] return x + y; | semmle.label | 1 |
| tst.ts:14:47:14:63 | [BlockStmt] { return x + y; } | tst.ts:14:49:14:61 | [ReturnStmt] return x + y; | semmle.order | 1 |
| tst.ts:14:49:14:61 | [ReturnStmt] return x + y; | tst.ts:14:56:14:60 | [BinaryExpr] x + y | semmle.label | 1 |
@@ -2175,10 +2175,10 @@ edges
| tst.ts:16:1:16:60 | [FunctionDeclStmt] functio ... + y; } | tst.ts:16:37:16:42 | [KeywordTypeExpr] number | semmle.order | 4 |
| tst.ts:16:1:16:60 | [FunctionDeclStmt] functio ... + y; } | tst.ts:16:44:16:60 | [BlockStmt] { return x + y; } | semmle.label | 5 |
| tst.ts:16:1:16:60 | [FunctionDeclStmt] functio ... + y; } | tst.ts:16:44:16:60 | [BlockStmt] { return x + y; } | semmle.order | 5 |
-| tst.ts:16:14:16:14 | [SimpleParameter] x | tst.ts:16:17:16:22 | [KeywordTypeExpr] number | semmle.label | 0 |
-| tst.ts:16:14:16:14 | [SimpleParameter] x | tst.ts:16:17:16:22 | [KeywordTypeExpr] number | semmle.order | 0 |
-| tst.ts:16:25:16:25 | [SimpleParameter] y | tst.ts:16:28:16:33 | [KeywordTypeExpr] number | semmle.label | 0 |
-| tst.ts:16:25:16:25 | [SimpleParameter] y | tst.ts:16:28:16:33 | [KeywordTypeExpr] number | semmle.order | 0 |
+| tst.ts:16:14:16:14 | [SimpleParameter] x | tst.ts:16:17:16:22 | [KeywordTypeExpr] number | semmle.label | -2 |
+| tst.ts:16:14:16:14 | [SimpleParameter] x | tst.ts:16:17:16:22 | [KeywordTypeExpr] number | semmle.order | -2 |
+| tst.ts:16:25:16:25 | [SimpleParameter] y | tst.ts:16:28:16:33 | [KeywordTypeExpr] number | semmle.label | -2 |
+| tst.ts:16:25:16:25 | [SimpleParameter] y | tst.ts:16:28:16:33 | [KeywordTypeExpr] number | semmle.order | -2 |
| tst.ts:16:44:16:60 | [BlockStmt] { return x + y; } | tst.ts:16:46:16:58 | [ReturnStmt] return x + y; | semmle.label | 1 |
| tst.ts:16:44:16:60 | [BlockStmt] { return x + y; } | tst.ts:16:46:16:58 | [ReturnStmt] return x + y; | semmle.order | 1 |
| tst.ts:16:46:16:58 | [ReturnStmt] return x + y; | tst.ts:16:53:16:57 | [BinaryExpr] x + y | semmle.label | 1 |
@@ -2207,8 +2207,8 @@ edges
| tst.ts:20:1:20:53 | [FunctionDeclStmt] functio ... + y; } | tst.ts:20:10:20:21 | [VarDecl] partialTyped | semmle.order | 0 |
| tst.ts:20:1:20:53 | [FunctionDeclStmt] functio ... + y; } | tst.ts:20:37:20:53 | [BlockStmt] { return x + y; } | semmle.label | 5 |
| tst.ts:20:1:20:53 | [FunctionDeclStmt] functio ... + y; } | tst.ts:20:37:20:53 | [BlockStmt] { return x + y; } | semmle.order | 5 |
-| tst.ts:20:26:20:26 | [SimpleParameter] y | tst.ts:20:29:20:34 | [KeywordTypeExpr] string | semmle.label | 0 |
-| tst.ts:20:26:20:26 | [SimpleParameter] y | tst.ts:20:29:20:34 | [KeywordTypeExpr] string | semmle.order | 0 |
+| tst.ts:20:26:20:26 | [SimpleParameter] y | tst.ts:20:29:20:34 | [KeywordTypeExpr] string | semmle.label | -2 |
+| tst.ts:20:26:20:26 | [SimpleParameter] y | tst.ts:20:29:20:34 | [KeywordTypeExpr] string | semmle.order | -2 |
| tst.ts:20:37:20:53 | [BlockStmt] { return x + y; } | tst.ts:20:39:20:51 | [ReturnStmt] return x + y; | semmle.label | 1 |
| tst.ts:20:37:20:53 | [BlockStmt] { return x + y; } | tst.ts:20:39:20:51 | [ReturnStmt] return x + y; | semmle.order | 1 |
| tst.ts:20:39:20:51 | [ReturnStmt] return x + y; | tst.ts:20:46:20:50 | [BinaryExpr] x + y | semmle.label | 1 |
@@ -2573,8 +2573,8 @@ edges
| tst.ts:75:5:75:47 | [SetterMethodSignature] set siz ... olean); | tst.ts:75:5:75:47 | [FunctionExpr] set siz ... olean); | semmle.order | 1 |
| tst.ts:75:5:75:47 | [SetterMethodSignature] set siz ... olean); | tst.ts:75:9:75:12 | [Label] size | semmle.label | 2 |
| tst.ts:75:5:75:47 | [SetterMethodSignature] set siz ... olean); | tst.ts:75:9:75:12 | [Label] size | semmle.order | 2 |
-| tst.ts:75:14:75:18 | [SimpleParameter] value | tst.ts:75:21:75:45 | [UnionTypeExpr] number ... boolean | semmle.label | 0 |
-| tst.ts:75:14:75:18 | [SimpleParameter] value | tst.ts:75:21:75:45 | [UnionTypeExpr] number ... boolean | semmle.order | 0 |
+| tst.ts:75:14:75:18 | [SimpleParameter] value | tst.ts:75:21:75:45 | [UnionTypeExpr] number ... boolean | semmle.label | -2 |
+| tst.ts:75:14:75:18 | [SimpleParameter] value | tst.ts:75:21:75:45 | [UnionTypeExpr] number ... boolean | semmle.order | -2 |
| tst.ts:75:21:75:45 | [UnionTypeExpr] number ... boolean | tst.ts:75:21:75:26 | [KeywordTypeExpr] number | semmle.label | 1 |
| tst.ts:75:21:75:45 | [UnionTypeExpr] number ... boolean | tst.ts:75:21:75:26 | [KeywordTypeExpr] number | semmle.order | 1 |
| tst.ts:75:21:75:45 | [UnionTypeExpr] number ... boolean | tst.ts:75:30:75:35 | [KeywordTypeExpr] string | semmle.label | 2 |
@@ -2629,8 +2629,8 @@ edges
| tst.ts:85:5:87:5 | [FunctionExpr] set siz ... ; } | file://:0:0:0:0 | (Parameters) | semmle.order | 1 |
| tst.ts:85:5:87:5 | [FunctionExpr] set siz ... ; } | tst.ts:85:48:87:5 | [BlockStmt] { ... ; } | semmle.label | 5 |
| tst.ts:85:5:87:5 | [FunctionExpr] set siz ... ; } | tst.ts:85:48:87:5 | [BlockStmt] { ... ; } | semmle.order | 5 |
-| tst.ts:85:14:85:18 | [SimpleParameter] value | tst.ts:85:21:85:45 | [UnionTypeExpr] string ... boolean | semmle.label | 0 |
-| tst.ts:85:14:85:18 | [SimpleParameter] value | tst.ts:85:21:85:45 | [UnionTypeExpr] string ... boolean | semmle.order | 0 |
+| tst.ts:85:14:85:18 | [SimpleParameter] value | tst.ts:85:21:85:45 | [UnionTypeExpr] string ... boolean | semmle.label | -2 |
+| tst.ts:85:14:85:18 | [SimpleParameter] value | tst.ts:85:21:85:45 | [UnionTypeExpr] string ... boolean | semmle.order | -2 |
| tst.ts:85:21:85:45 | [UnionTypeExpr] string ... boolean | tst.ts:85:21:85:26 | [KeywordTypeExpr] string | semmle.label | 1 |
| tst.ts:85:21:85:45 | [UnionTypeExpr] string ... boolean | tst.ts:85:21:85:26 | [KeywordTypeExpr] string | semmle.order | 1 |
| tst.ts:85:21:85:45 | [UnionTypeExpr] string ... boolean | tst.ts:85:30:85:35 | [KeywordTypeExpr] number | semmle.label | 2 |
@@ -2733,8 +2733,8 @@ edges
| tst.ts:104:3:107:3 | [FunctionDeclStmt] functio ... }`; } | tst.ts:104:28:104:44 | [TemplateLiteralTypeExpr] `hello ${string}` | semmle.order | 4 |
| tst.ts:104:3:107:3 | [FunctionDeclStmt] functio ... }`; } | tst.ts:104:46:107:3 | [BlockStmt] { / ... }`; } | semmle.label | 5 |
| tst.ts:104:3:107:3 | [FunctionDeclStmt] functio ... }`; } | tst.ts:104:46:107:3 | [BlockStmt] { / ... }`; } | semmle.order | 5 |
-| tst.ts:104:16:104:16 | [SimpleParameter] s | tst.ts:104:19:104:24 | [KeywordTypeExpr] string | semmle.label | 0 |
-| tst.ts:104:16:104:16 | [SimpleParameter] s | tst.ts:104:19:104:24 | [KeywordTypeExpr] string | semmle.order | 0 |
+| tst.ts:104:16:104:16 | [SimpleParameter] s | tst.ts:104:19:104:24 | [KeywordTypeExpr] string | semmle.label | -2 |
+| tst.ts:104:16:104:16 | [SimpleParameter] s | tst.ts:104:19:104:24 | [KeywordTypeExpr] string | semmle.order | -2 |
| tst.ts:104:28:104:44 | [TemplateLiteralTypeExpr] `hello ${string}` | tst.ts:104:29:104:34 | [LiteralTypeExpr] hello | semmle.label | 1 |
| tst.ts:104:28:104:44 | [TemplateLiteralTypeExpr] `hello ${string}` | tst.ts:104:29:104:34 | [LiteralTypeExpr] hello | semmle.order | 1 |
| tst.ts:104:28:104:44 | [TemplateLiteralTypeExpr] `hello ${string}` | tst.ts:104:37:104:42 | [KeywordTypeExpr] string | semmle.label | 2 |
@@ -2877,8 +2877,8 @@ edges
| tst.ts:133:3:138:3 | [FunctionDeclStmt] functio ... } } | tst.ts:133:12:133:14 | [VarDecl] foo | semmle.order | 0 |
| tst.ts:133:3:138:3 | [FunctionDeclStmt] functio ... } } | tst.ts:133:30:138:3 | [BlockStmt] { c ... } } | semmle.label | 5 |
| tst.ts:133:3:138:3 | [FunctionDeclStmt] functio ... } } | tst.ts:133:30:138:3 | [BlockStmt] { c ... } } | semmle.order | 5 |
-| tst.ts:133:16:133:18 | [SimpleParameter] arg | tst.ts:133:21:133:27 | [KeywordTypeExpr] unknown | semmle.label | 0 |
-| tst.ts:133:16:133:18 | [SimpleParameter] arg | tst.ts:133:21:133:27 | [KeywordTypeExpr] unknown | semmle.order | 0 |
+| tst.ts:133:16:133:18 | [SimpleParameter] arg | tst.ts:133:21:133:27 | [KeywordTypeExpr] unknown | semmle.label | -2 |
+| tst.ts:133:16:133:18 | [SimpleParameter] arg | tst.ts:133:21:133:27 | [KeywordTypeExpr] unknown | semmle.order | -2 |
| tst.ts:133:30:138:3 | [BlockStmt] { c ... } } | tst.ts:134:5:134:48 | [DeclStmt] const argIsString = ... | semmle.label | 1 |
| tst.ts:133:30:138:3 | [BlockStmt] { c ... } } | tst.ts:134:5:134:48 | [DeclStmt] const argIsString = ... | semmle.order | 1 |
| tst.ts:133:30:138:3 | [BlockStmt] { c ... } } | tst.ts:135:5:137:5 | [IfStmt] if (arg ... ; } | semmle.label | 2 |
@@ -2953,8 +2953,8 @@ edges
| tst.ts:144:3:149:3 | [FunctionDeclStmt] functio ... ; } } | tst.ts:144:32:144:37 | [KeywordTypeExpr] number | semmle.order | 4 |
| tst.ts:144:3:149:3 | [FunctionDeclStmt] functio ... ; } } | tst.ts:144:39:149:3 | [BlockStmt] { ... ; } } | semmle.label | 5 |
| tst.ts:144:3:149:3 | [FunctionDeclStmt] functio ... ; } } | tst.ts:144:39:149:3 | [BlockStmt] { ... ; } } | semmle.order | 5 |
-| tst.ts:144:17:144:21 | [SimpleParameter] shape | tst.ts:144:24:144:28 | [LocalTypeAccess] Shape | semmle.label | 0 |
-| tst.ts:144:17:144:21 | [SimpleParameter] shape | tst.ts:144:24:144:28 | [LocalTypeAccess] Shape | semmle.order | 0 |
+| tst.ts:144:17:144:21 | [SimpleParameter] shape | tst.ts:144:24:144:28 | [LocalTypeAccess] Shape | semmle.label | -2 |
+| tst.ts:144:17:144:21 | [SimpleParameter] shape | tst.ts:144:24:144:28 | [LocalTypeAccess] Shape | semmle.order | -2 |
| tst.ts:144:39:149:3 | [BlockStmt] { ... ; } } | tst.ts:145:7:145:29 | [DeclStmt] const { ... shape; | semmle.label | 1 |
| tst.ts:144:39:149:3 | [BlockStmt] { ... ; } } | tst.ts:145:7:145:29 | [DeclStmt] const { ... shape; | semmle.order | 1 |
| tst.ts:144:39:149:3 | [BlockStmt] { ... ; } } | tst.ts:147:7:148:39 | [IfStmt] if (kin ... ngth; } | semmle.label | 2 |
@@ -3025,24 +3025,24 @@ edges
| tst.ts:153:7:153:28 | [FunctionExpr] [sym: s ... number; | tst.ts:153:22:153:27 | [KeywordTypeExpr] number | semmle.order | 4 |
| tst.ts:153:7:153:28 | [IndexSignature] [sym: s ... number; | tst.ts:153:7:153:28 | [FunctionExpr] [sym: s ... number; | semmle.label | 1 |
| tst.ts:153:7:153:28 | [IndexSignature] [sym: s ... number; | tst.ts:153:7:153:28 | [FunctionExpr] [sym: s ... number; | semmle.order | 1 |
-| tst.ts:153:8:153:10 | [SimpleParameter] sym | tst.ts:153:13:153:18 | [KeywordTypeExpr] symbol | semmle.label | 0 |
-| tst.ts:153:8:153:10 | [SimpleParameter] sym | tst.ts:153:13:153:18 | [KeywordTypeExpr] symbol | semmle.order | 0 |
+| tst.ts:153:8:153:10 | [SimpleParameter] sym | tst.ts:153:13:153:18 | [KeywordTypeExpr] symbol | semmle.label | -2 |
+| tst.ts:153:8:153:10 | [SimpleParameter] sym | tst.ts:153:13:153:18 | [KeywordTypeExpr] symbol | semmle.order | -2 |
| tst.ts:154:7:154:28 | [FunctionExpr] [key: s ... string; | file://:0:0:0:0 | (Parameters) | semmle.label | 1 |
| tst.ts:154:7:154:28 | [FunctionExpr] [key: s ... string; | file://:0:0:0:0 | (Parameters) | semmle.order | 1 |
| tst.ts:154:7:154:28 | [FunctionExpr] [key: s ... string; | tst.ts:154:22:154:27 | [KeywordTypeExpr] string | semmle.label | 4 |
| tst.ts:154:7:154:28 | [FunctionExpr] [key: s ... string; | tst.ts:154:22:154:27 | [KeywordTypeExpr] string | semmle.order | 4 |
| tst.ts:154:7:154:28 | [IndexSignature] [key: s ... string; | tst.ts:154:7:154:28 | [FunctionExpr] [key: s ... string; | semmle.label | 1 |
| tst.ts:154:7:154:28 | [IndexSignature] [key: s ... string; | tst.ts:154:7:154:28 | [FunctionExpr] [key: s ... string; | semmle.order | 1 |
-| tst.ts:154:8:154:10 | [SimpleParameter] key | tst.ts:154:13:154:18 | [KeywordTypeExpr] string | semmle.label | 0 |
-| tst.ts:154:8:154:10 | [SimpleParameter] key | tst.ts:154:13:154:18 | [KeywordTypeExpr] string | semmle.order | 0 |
+| tst.ts:154:8:154:10 | [SimpleParameter] key | tst.ts:154:13:154:18 | [KeywordTypeExpr] string | semmle.label | -2 |
+| tst.ts:154:8:154:10 | [SimpleParameter] key | tst.ts:154:13:154:18 | [KeywordTypeExpr] string | semmle.order | -2 |
| tst.ts:155:7:155:29 | [FunctionExpr] [num: n ... oolean; | file://:0:0:0:0 | (Parameters) | semmle.label | 1 |
| tst.ts:155:7:155:29 | [FunctionExpr] [num: n ... oolean; | file://:0:0:0:0 | (Parameters) | semmle.order | 1 |
| tst.ts:155:7:155:29 | [FunctionExpr] [num: n ... oolean; | tst.ts:155:22:155:28 | [KeywordTypeExpr] boolean | semmle.label | 4 |
| tst.ts:155:7:155:29 | [FunctionExpr] [num: n ... oolean; | tst.ts:155:22:155:28 | [KeywordTypeExpr] boolean | semmle.order | 4 |
| tst.ts:155:7:155:29 | [IndexSignature] [num: n ... oolean; | tst.ts:155:7:155:29 | [FunctionExpr] [num: n ... oolean; | semmle.label | 1 |
| tst.ts:155:7:155:29 | [IndexSignature] [num: n ... oolean; | tst.ts:155:7:155:29 | [FunctionExpr] [num: n ... oolean; | semmle.order | 1 |
-| tst.ts:155:8:155:10 | [SimpleParameter] num | tst.ts:155:13:155:18 | [KeywordTypeExpr] number | semmle.label | 0 |
-| tst.ts:155:8:155:10 | [SimpleParameter] num | tst.ts:155:13:155:18 | [KeywordTypeExpr] number | semmle.order | 0 |
+| tst.ts:155:8:155:10 | [SimpleParameter] num | tst.ts:155:13:155:18 | [KeywordTypeExpr] number | semmle.label | -2 |
+| tst.ts:155:8:155:10 | [SimpleParameter] num | tst.ts:155:13:155:18 | [KeywordTypeExpr] number | semmle.order | -2 |
| tst.ts:158:5:158:28 | [DeclStmt] let colors = ... | tst.ts:158:9:158:27 | [VariableDeclarator] colors: Colors = {} | semmle.label | 1 |
| tst.ts:158:5:158:28 | [DeclStmt] let colors = ... | tst.ts:158:9:158:27 | [VariableDeclarator] colors: Colors = {} | semmle.order | 1 |
| tst.ts:158:9:158:27 | [VariableDeclarator] colors: Colors = {} | tst.ts:158:9:158:14 | [VarDecl] colors | semmle.label | 1 |
@@ -3111,8 +3111,8 @@ edges
| tst.ts:166:7:166:37 | [FunctionExpr] [key: ` ... number; | tst.ts:166:31:166:36 | [KeywordTypeExpr] number | semmle.order | 4 |
| tst.ts:166:7:166:37 | [IndexSignature] [key: ` ... number; | tst.ts:166:7:166:37 | [FunctionExpr] [key: ` ... number; | semmle.label | 1 |
| tst.ts:166:7:166:37 | [IndexSignature] [key: ` ... number; | tst.ts:166:7:166:37 | [FunctionExpr] [key: ` ... number; | semmle.order | 1 |
-| tst.ts:166:8:166:10 | [SimpleParameter] key | tst.ts:166:13:166:27 | [TemplateLiteralTypeExpr] `foo-${number}` | semmle.label | 0 |
-| tst.ts:166:8:166:10 | [SimpleParameter] key | tst.ts:166:13:166:27 | [TemplateLiteralTypeExpr] `foo-${number}` | semmle.order | 0 |
+| tst.ts:166:8:166:10 | [SimpleParameter] key | tst.ts:166:13:166:27 | [TemplateLiteralTypeExpr] `foo-${number}` | semmle.label | -2 |
+| tst.ts:166:8:166:10 | [SimpleParameter] key | tst.ts:166:13:166:27 | [TemplateLiteralTypeExpr] `foo-${number}` | semmle.order | -2 |
| tst.ts:166:13:166:27 | [TemplateLiteralTypeExpr] `foo-${number}` | tst.ts:166:14:166:17 | [LiteralTypeExpr] foo- | semmle.label | 1 |
| tst.ts:166:13:166:27 | [TemplateLiteralTypeExpr] `foo-${number}` | tst.ts:166:14:166:17 | [LiteralTypeExpr] foo- | semmle.order | 1 |
| tst.ts:166:13:166:27 | [TemplateLiteralTypeExpr] `foo-${number}` | tst.ts:166:20:166:25 | [KeywordTypeExpr] number | semmle.label | 2 |
@@ -3147,8 +3147,8 @@ edges
| tst.ts:172:7:172:42 | [FunctionExpr] [optNam ... oolean; | tst.ts:172:35:172:41 | [KeywordTypeExpr] boolean | semmle.order | 4 |
| tst.ts:172:7:172:42 | [IndexSignature] [optNam ... oolean; | tst.ts:172:7:172:42 | [FunctionExpr] [optNam ... oolean; | semmle.label | 1 |
| tst.ts:172:7:172:42 | [IndexSignature] [optNam ... oolean; | tst.ts:172:7:172:42 | [FunctionExpr] [optNam ... oolean; | semmle.order | 1 |
-| tst.ts:172:8:172:14 | [SimpleParameter] optName | tst.ts:172:17:172:31 | [UnionTypeExpr] string \| symbol | semmle.label | 0 |
-| tst.ts:172:8:172:14 | [SimpleParameter] optName | tst.ts:172:17:172:31 | [UnionTypeExpr] string \| symbol | semmle.order | 0 |
+| tst.ts:172:8:172:14 | [SimpleParameter] optName | tst.ts:172:17:172:31 | [UnionTypeExpr] string \| symbol | semmle.label | -2 |
+| tst.ts:172:8:172:14 | [SimpleParameter] optName | tst.ts:172:17:172:31 | [UnionTypeExpr] string \| symbol | semmle.order | -2 |
| tst.ts:172:17:172:31 | [UnionTypeExpr] string \| symbol | tst.ts:172:17:172:22 | [KeywordTypeExpr] string | semmle.label | 1 |
| tst.ts:172:17:172:31 | [UnionTypeExpr] string \| symbol | tst.ts:172:17:172:22 | [KeywordTypeExpr] string | semmle.order | 1 |
| tst.ts:172:17:172:31 | [UnionTypeExpr] string \| symbol | tst.ts:172:26:172:31 | [KeywordTypeExpr] symbol | semmle.label | 2 |
@@ -3343,8 +3343,8 @@ edges
| tst.ts:215:10:220:3 | [FunctionDeclStmt] functio ... } } | tst.ts:215:19:215:25 | [VarDecl] handler | semmle.order | 0 |
| tst.ts:215:10:220:3 | [FunctionDeclStmt] functio ... } } | tst.ts:215:47:220:3 | [BlockStmt] { ... } } | semmle.label | 5 |
| tst.ts:215:10:220:3 | [FunctionDeclStmt] functio ... } } | tst.ts:215:47:220:3 | [BlockStmt] { ... } } | semmle.order | 5 |
-| tst.ts:215:27:215:27 | [SimpleParameter] r | tst.ts:215:30:215:44 | [UnionTypeExpr] Success \| Error | semmle.label | 0 |
-| tst.ts:215:27:215:27 | [SimpleParameter] r | tst.ts:215:30:215:44 | [UnionTypeExpr] Success \| Error | semmle.order | 0 |
+| tst.ts:215:27:215:27 | [SimpleParameter] r | tst.ts:215:30:215:44 | [UnionTypeExpr] Success \| Error | semmle.label | -2 |
+| tst.ts:215:27:215:27 | [SimpleParameter] r | tst.ts:215:30:215:44 | [UnionTypeExpr] Success \| Error | semmle.order | -2 |
| tst.ts:215:30:215:44 | [UnionTypeExpr] Success \| Error | tst.ts:215:30:215:36 | [LocalTypeAccess] Success | semmle.label | 1 |
| tst.ts:215:30:215:44 | [UnionTypeExpr] Success \| Error | tst.ts:215:30:215:36 | [LocalTypeAccess] Success | semmle.order | 1 |
| tst.ts:215:30:215:44 | [UnionTypeExpr] Success \| Error | tst.ts:215:40:215:44 | [LocalTypeAccess] Error | semmle.label | 2 |
@@ -3395,8 +3395,8 @@ edges
| tst.ts:224:5:226:5 | [FunctionExpr] constru ... ; } | file://:0:0:0:0 | (Parameters) | semmle.order | 1 |
| tst.ts:224:5:226:5 | [FunctionExpr] constru ... ; } | tst.ts:224:31:226:5 | [BlockStmt] { ... ; } | semmle.label | 5 |
| tst.ts:224:5:226:5 | [FunctionExpr] constru ... ; } | tst.ts:224:31:226:5 | [BlockStmt] { ... ; } | semmle.order | 5 |
-| tst.ts:224:17:224:20 | [SimpleParameter] name | tst.ts:224:23:224:28 | [KeywordTypeExpr] string | semmle.label | 0 |
-| tst.ts:224:17:224:20 | [SimpleParameter] name | tst.ts:224:23:224:28 | [KeywordTypeExpr] string | semmle.order | 0 |
+| tst.ts:224:17:224:20 | [SimpleParameter] name | tst.ts:224:23:224:28 | [KeywordTypeExpr] string | semmle.label | -2 |
+| tst.ts:224:17:224:20 | [SimpleParameter] name | tst.ts:224:23:224:28 | [KeywordTypeExpr] string | semmle.order | -2 |
| tst.ts:224:31:226:5 | [BlockStmt] { ... ; } | tst.ts:225:9:225:26 | [ExprStmt] this.#name = name; | semmle.label | 1 |
| tst.ts:224:31:226:5 | [BlockStmt] { ... ; } | tst.ts:225:9:225:26 | [ExprStmt] this.#name = name; | semmle.order | 1 |
| tst.ts:225:9:225:18 | [DotExpr] this.#name | tst.ts:225:9:225:12 | [ThisExpr] this | semmle.label | 1 |
@@ -3417,8 +3417,8 @@ edges
| tst.ts:228:5:233:5 | [FunctionExpr] equals( ... . } | file://:0:0:0:0 | (Parameters) | semmle.order | 1 |
| tst.ts:228:5:233:5 | [FunctionExpr] equals( ... . } | tst.ts:228:28:233:5 | [BlockStmt] { ... . } | semmle.label | 5 |
| tst.ts:228:5:233:5 | [FunctionExpr] equals( ... . } | tst.ts:228:28:233:5 | [BlockStmt] { ... . } | semmle.order | 5 |
-| tst.ts:228:12:228:16 | [SimpleParameter] other | tst.ts:228:19:228:25 | [KeywordTypeExpr] unknown | semmle.label | 0 |
-| tst.ts:228:12:228:16 | [SimpleParameter] other | tst.ts:228:19:228:25 | [KeywordTypeExpr] unknown | semmle.order | 0 |
+| tst.ts:228:12:228:16 | [SimpleParameter] other | tst.ts:228:19:228:25 | [KeywordTypeExpr] unknown | semmle.label | -2 |
+| tst.ts:228:12:228:16 | [SimpleParameter] other | tst.ts:228:19:228:25 | [KeywordTypeExpr] unknown | semmle.order | -2 |
| tst.ts:228:28:233:5 | [BlockStmt] { ... . } | tst.ts:229:9:232:39 | [ReturnStmt] return ... .#name; | semmle.label | 1 |
| tst.ts:228:28:233:5 | [BlockStmt] { ... . } | tst.ts:229:9:232:39 | [ReturnStmt] return ... .#name; | semmle.order | 1 |
| tst.ts:229:9:232:39 | [ReturnStmt] return ... .#name; | tst.ts:229:16:232:38 | [BinaryExpr] other & ... r.#name | semmle.label | 1 |
@@ -3579,8 +3579,8 @@ edges
| tst.ts:256:3:263:3 | [FunctionDeclStmt] functio ... } } | tst.ts:256:12:256:24 | [VarDecl] processAction | semmle.order | 0 |
| tst.ts:256:3:263:3 | [FunctionDeclStmt] functio ... } } | tst.ts:256:42:263:3 | [BlockStmt] { c ... } } | semmle.label | 5 |
| tst.ts:256:3:263:3 | [FunctionDeclStmt] functio ... } } | tst.ts:256:42:263:3 | [BlockStmt] { c ... } } | semmle.order | 5 |
-| tst.ts:256:26:256:31 | [SimpleParameter] action | tst.ts:256:34:256:39 | [LocalTypeAccess] Action | semmle.label | 0 |
-| tst.ts:256:26:256:31 | [SimpleParameter] action | tst.ts:256:34:256:39 | [LocalTypeAccess] Action | semmle.order | 0 |
+| tst.ts:256:26:256:31 | [SimpleParameter] action | tst.ts:256:34:256:39 | [LocalTypeAccess] Action | semmle.label | -2 |
+| tst.ts:256:26:256:31 | [SimpleParameter] action | tst.ts:256:34:256:39 | [LocalTypeAccess] Action | semmle.order | -2 |
| tst.ts:256:42:263:3 | [BlockStmt] { c ... } } | tst.ts:257:5:257:37 | [DeclStmt] const { ... action; | semmle.label | 1 |
| tst.ts:256:42:263:3 | [BlockStmt] { c ... } } | tst.ts:257:5:257:37 | [DeclStmt] const { ... action; | semmle.order | 1 |
| tst.ts:256:42:263:3 | [BlockStmt] { c ... } } | tst.ts:258:5:262:5 | [IfStmt] if (kin ... g } | semmle.label | 2 |
@@ -3719,8 +3719,8 @@ edges
| tst.ts:274:10:274:32 | [FunctionExpr] (p: Typ ... => void | tst.ts:274:29:274:32 | [KeywordTypeExpr] void | semmle.order | 4 |
| tst.ts:274:10:274:32 | [FunctionTypeExpr] (p: Typ ... => void | tst.ts:274:10:274:32 | [FunctionExpr] (p: Typ ... => void | semmle.label | 1 |
| tst.ts:274:10:274:32 | [FunctionTypeExpr] (p: Typ ... => void | tst.ts:274:10:274:32 | [FunctionExpr] (p: Typ ... => void | semmle.order | 1 |
-| tst.ts:274:11:274:11 | [SimpleParameter] p | tst.ts:274:14:274:23 | [IndexedAccessTypeExpr] TypeMap[K] | semmle.label | 0 |
-| tst.ts:274:11:274:11 | [SimpleParameter] p | tst.ts:274:14:274:23 | [IndexedAccessTypeExpr] TypeMap[K] | semmle.order | 0 |
+| tst.ts:274:11:274:11 | [SimpleParameter] p | tst.ts:274:14:274:23 | [IndexedAccessTypeExpr] TypeMap[K] | semmle.label | -2 |
+| tst.ts:274:11:274:11 | [SimpleParameter] p | tst.ts:274:14:274:23 | [IndexedAccessTypeExpr] TypeMap[K] | semmle.order | -2 |
| tst.ts:274:14:274:23 | [IndexedAccessTypeExpr] TypeMap[K] | tst.ts:274:14:274:20 | [LocalTypeAccess] TypeMap | semmle.label | 1 |
| tst.ts:274:14:274:23 | [IndexedAccessTypeExpr] TypeMap[K] | tst.ts:274:14:274:20 | [LocalTypeAccess] TypeMap | semmle.order | 1 |
| tst.ts:274:14:274:23 | [IndexedAccessTypeExpr] TypeMap[K] | tst.ts:274:22:274:22 | [LocalTypeAccess] K | semmle.label | 2 |
@@ -3739,8 +3739,8 @@ edges
| tst.ts:278:26:278:48 | [TypeParameter] K exten ... TypeMap | tst.ts:278:36:278:48 | [KeyofTypeExpr] keyof TypeMap | semmle.order | 2 |
| tst.ts:278:36:278:48 | [KeyofTypeExpr] keyof TypeMap | tst.ts:278:42:278:48 | [LocalTypeAccess] TypeMap | semmle.label | 1 |
| tst.ts:278:36:278:48 | [KeyofTypeExpr] keyof TypeMap | tst.ts:278:42:278:48 | [LocalTypeAccess] TypeMap | semmle.order | 1 |
-| tst.ts:278:51:278:56 | [SimpleParameter] record | tst.ts:278:59:278:72 | [GenericTypeExpr] UnionRecord | semmle.label | 0 |
-| tst.ts:278:51:278:56 | [SimpleParameter] record | tst.ts:278:59:278:72 | [GenericTypeExpr] UnionRecord | semmle.order | 0 |
+| tst.ts:278:51:278:56 | [SimpleParameter] record | tst.ts:278:59:278:72 | [GenericTypeExpr] UnionRecord | semmle.label | -2 |
+| tst.ts:278:51:278:56 | [SimpleParameter] record | tst.ts:278:59:278:72 | [GenericTypeExpr] UnionRecord | semmle.order | -2 |
| tst.ts:278:59:278:72 | [GenericTypeExpr] UnionRecord | tst.ts:278:59:278:69 | [LocalTypeAccess] UnionRecord | semmle.label | 1 |
| tst.ts:278:59:278:72 | [GenericTypeExpr] UnionRecord | tst.ts:278:59:278:69 | [LocalTypeAccess] UnionRecord | semmle.order | 1 |
| tst.ts:278:59:278:72 | [GenericTypeExpr] UnionRecord | tst.ts:278:71:278:71 | [LocalTypeAccess] K | semmle.label | 2 |
@@ -3811,8 +3811,8 @@ edges
| tst.ts:289:15:289:62 | [FunctionExpr] (...arg ... => void | tst.ts:289:59:289:62 | [KeywordTypeExpr] void | semmle.order | 4 |
| tst.ts:289:15:289:62 | [FunctionTypeExpr] (...arg ... => void | tst.ts:289:15:289:62 | [FunctionExpr] (...arg ... => void | semmle.label | 1 |
| tst.ts:289:15:289:62 | [FunctionTypeExpr] (...arg ... => void | tst.ts:289:15:289:62 | [FunctionExpr] (...arg ... => void | semmle.order | 1 |
-| tst.ts:289:19:289:22 | [SimpleParameter] args | tst.ts:289:25:289:53 | [UnionTypeExpr] ["a", n ... string] | semmle.label | 0 |
-| tst.ts:289:19:289:22 | [SimpleParameter] args | tst.ts:289:25:289:53 | [UnionTypeExpr] ["a", n ... string] | semmle.order | 0 |
+| tst.ts:289:19:289:22 | [SimpleParameter] args | tst.ts:289:25:289:53 | [UnionTypeExpr] ["a", n ... string] | semmle.label | -2 |
+| tst.ts:289:19:289:22 | [SimpleParameter] args | tst.ts:289:25:289:53 | [UnionTypeExpr] ["a", n ... string] | semmle.order | -2 |
| tst.ts:289:25:289:37 | [TupleTypeExpr] ["a", number] | tst.ts:289:26:289:28 | [LiteralTypeExpr] "a" | semmle.label | 1 |
| tst.ts:289:25:289:37 | [TupleTypeExpr] ["a", number] | tst.ts:289:26:289:28 | [LiteralTypeExpr] "a" | semmle.order | 1 |
| tst.ts:289:25:289:37 | [TupleTypeExpr] ["a", number] | tst.ts:289:31:289:36 | [KeywordTypeExpr] number | semmle.label | 2 |
@@ -3947,8 +3947,8 @@ edges
| tst.ts:313:1:316:10 | [FunctionDeclStmt] functio ... void {} | tst.ts:316:9:316:10 | [BlockStmt] {} | semmle.order | 5 |
| tst.ts:313:12:313:12 | [TypeParameter] T | tst.ts:313:12:313:12 | [Identifier] T | semmle.label | 1 |
| tst.ts:313:12:313:12 | [TypeParameter] T | tst.ts:313:12:313:12 | [Identifier] T | semmle.order | 1 |
-| tst.ts:313:15:313:17 | [SimpleParameter] arg | tst.ts:313:20:315:27 | [InterfaceTypeExpr] { pro ... void } | semmle.label | 0 |
-| tst.ts:313:15:313:17 | [SimpleParameter] arg | tst.ts:313:20:315:27 | [InterfaceTypeExpr] { pro ... void } | semmle.order | 0 |
+| tst.ts:313:15:313:17 | [SimpleParameter] arg | tst.ts:313:20:315:27 | [InterfaceTypeExpr] { pro ... void } | semmle.label | -2 |
+| tst.ts:313:15:313:17 | [SimpleParameter] arg | tst.ts:313:20:315:27 | [InterfaceTypeExpr] { pro ... void } | semmle.order | -2 |
| tst.ts:313:20:315:27 | [InterfaceTypeExpr] { pro ... void } | tst.ts:314:3:314:28 | [FieldDeclaration] produce ... ) => T, | semmle.label | 1 |
| tst.ts:313:20:315:27 | [InterfaceTypeExpr] { pro ... void } | tst.ts:314:3:314:28 | [FieldDeclaration] produce ... ) => T, | semmle.order | 1 |
| tst.ts:313:20:315:27 | [InterfaceTypeExpr] { pro ... void } | tst.ts:315:3:315:25 | [FieldDeclaration] consume ... => void | semmle.label | 2 |
@@ -3963,8 +3963,8 @@ edges
| tst.ts:314:12:314:27 | [FunctionExpr] (n: string) => T | tst.ts:314:27:314:27 | [LocalTypeAccess] T | semmle.order | 4 |
| tst.ts:314:12:314:27 | [FunctionTypeExpr] (n: string) => T | tst.ts:314:12:314:27 | [FunctionExpr] (n: string) => T | semmle.label | 1 |
| tst.ts:314:12:314:27 | [FunctionTypeExpr] (n: string) => T | tst.ts:314:12:314:27 | [FunctionExpr] (n: string) => T | semmle.order | 1 |
-| tst.ts:314:13:314:13 | [SimpleParameter] n | tst.ts:314:16:314:21 | [KeywordTypeExpr] string | semmle.label | 0 |
-| tst.ts:314:13:314:13 | [SimpleParameter] n | tst.ts:314:16:314:21 | [KeywordTypeExpr] string | semmle.order | 0 |
+| tst.ts:314:13:314:13 | [SimpleParameter] n | tst.ts:314:16:314:21 | [KeywordTypeExpr] string | semmle.label | -2 |
+| tst.ts:314:13:314:13 | [SimpleParameter] n | tst.ts:314:16:314:21 | [KeywordTypeExpr] string | semmle.order | -2 |
| tst.ts:315:3:315:25 | [FieldDeclaration] consume ... => void | tst.ts:315:3:315:9 | [Label] consume | semmle.label | 1 |
| tst.ts:315:3:315:25 | [FieldDeclaration] consume ... => void | tst.ts:315:3:315:9 | [Label] consume | semmle.order | 1 |
| tst.ts:315:3:315:25 | [FieldDeclaration] consume ... => void | tst.ts:315:12:315:25 | [FunctionTypeExpr] (x: T) => void | semmle.label | 2 |
@@ -3975,8 +3975,8 @@ edges
| tst.ts:315:12:315:25 | [FunctionExpr] (x: T) => void | tst.ts:315:22:315:25 | [KeywordTypeExpr] void | semmle.order | 4 |
| tst.ts:315:12:315:25 | [FunctionTypeExpr] (x: T) => void | tst.ts:315:12:315:25 | [FunctionExpr] (x: T) => void | semmle.label | 1 |
| tst.ts:315:12:315:25 | [FunctionTypeExpr] (x: T) => void | tst.ts:315:12:315:25 | [FunctionExpr] (x: T) => void | semmle.order | 1 |
-| tst.ts:315:13:315:13 | [SimpleParameter] x | tst.ts:315:16:315:16 | [LocalTypeAccess] T | semmle.label | 0 |
-| tst.ts:315:13:315:13 | [SimpleParameter] x | tst.ts:315:16:315:16 | [LocalTypeAccess] T | semmle.order | 0 |
+| tst.ts:315:13:315:13 | [SimpleParameter] x | tst.ts:315:16:315:16 | [LocalTypeAccess] T | semmle.label | -2 |
+| tst.ts:315:13:315:13 | [SimpleParameter] x | tst.ts:315:16:315:16 | [LocalTypeAccess] T | semmle.order | -2 |
| tst.ts:318:1:321:2 | [CallExpr] f({ p ... se() }) | file://:0:0:0:0 | (Arguments) | semmle.label | 1 |
| tst.ts:318:1:321:2 | [CallExpr] f({ p ... se() }) | file://:0:0:0:0 | (Arguments) | semmle.order | 1 |
| tst.ts:318:1:321:2 | [CallExpr] f({ p ... se() }) | tst.ts:318:1:318:1 | [VarRef] f | semmle.label | 0 |
@@ -4113,8 +4113,8 @@ edges
| tst.ts:344:8:344:25 | [FunctionExpr] (value: T) => void | tst.ts:344:22:344:25 | [KeywordTypeExpr] void | semmle.order | 4 |
| tst.ts:344:8:344:25 | [FunctionTypeExpr] (value: T) => void | tst.ts:344:8:344:25 | [FunctionExpr] (value: T) => void | semmle.label | 1 |
| tst.ts:344:8:344:25 | [FunctionTypeExpr] (value: T) => void | tst.ts:344:8:344:25 | [FunctionExpr] (value: T) => void | semmle.order | 1 |
-| tst.ts:344:9:344:13 | [SimpleParameter] value | tst.ts:344:16:344:16 | [LocalTypeAccess] T | semmle.label | 0 |
-| tst.ts:344:9:344:13 | [SimpleParameter] value | tst.ts:344:16:344:16 | [LocalTypeAccess] T | semmle.order | 0 |
+| tst.ts:344:9:344:13 | [SimpleParameter] value | tst.ts:344:16:344:16 | [LocalTypeAccess] T | semmle.label | -2 |
+| tst.ts:344:9:344:13 | [SimpleParameter] value | tst.ts:344:16:344:16 | [LocalTypeAccess] T | semmle.order | -2 |
| tst.ts:347:1:350:1 | [DeclStmt] const state = ... | tst.ts:347:7:350:1 | [VariableDeclarator] state: ... > { } } | semmle.label | 1 |
| tst.ts:347:1:350:1 | [DeclStmt] const state = ... | tst.ts:347:7:350:1 | [VariableDeclarator] state: ... > { } } | semmle.order | 1 |
| tst.ts:347:7:350:1 | [VariableDeclarator] state: ... > { } } | tst.ts:347:7:347:11 | [VarDecl] state | semmle.label | 1 |
@@ -4277,10 +4277,10 @@ edges
| tst.ts:383:5:383:54 | [FunctionDeclStmt] declare ... T): T; | tst.ts:383:53:383:53 | [LocalTypeAccess] T | semmle.order | 4 |
| tst.ts:383:37:383:37 | [TypeParameter] T | tst.ts:383:37:383:37 | [Identifier] T | semmle.label | 1 |
| tst.ts:383:37:383:37 | [TypeParameter] T | tst.ts:383:37:383:37 | [Identifier] T | semmle.order | 1 |
-| tst.ts:383:40:383:40 | [SimpleParameter] x | tst.ts:383:43:383:43 | [LocalTypeAccess] T | semmle.label | 0 |
-| tst.ts:383:40:383:40 | [SimpleParameter] x | tst.ts:383:43:383:43 | [LocalTypeAccess] T | semmle.order | 0 |
-| tst.ts:383:46:383:46 | [SimpleParameter] y | tst.ts:383:49:383:49 | [LocalTypeAccess] T | semmle.label | 0 |
-| tst.ts:383:46:383:46 | [SimpleParameter] y | tst.ts:383:49:383:49 | [LocalTypeAccess] T | semmle.order | 0 |
+| tst.ts:383:40:383:40 | [SimpleParameter] x | tst.ts:383:43:383:43 | [LocalTypeAccess] T | semmle.label | -2 |
+| tst.ts:383:40:383:40 | [SimpleParameter] x | tst.ts:383:43:383:43 | [LocalTypeAccess] T | semmle.order | -2 |
+| tst.ts:383:46:383:46 | [SimpleParameter] y | tst.ts:383:49:383:49 | [LocalTypeAccess] T | semmle.label | -2 |
+| tst.ts:383:46:383:46 | [SimpleParameter] y | tst.ts:383:49:383:49 | [LocalTypeAccess] T | semmle.order | -2 |
| tst.ts:385:5:385:74 | [DeclStmt] let [a, ... ye!"]); | tst.ts:385:9:385:73 | [VariableDeclarator] [a, b, ... bye!"]) | semmle.label | 1 |
| tst.ts:385:5:385:74 | [DeclStmt] let [a, ... ye!"]); | tst.ts:385:9:385:73 | [VariableDeclarator] [a, b, ... bye!"]) | semmle.order | 1 |
| tst.ts:385:9:385:17 | [ArrayPattern] [a, b, c] | tst.ts:385:10:385:10 | [VarDecl] a | semmle.label | 1 |
@@ -4443,8 +4443,8 @@ edges
| tst.ts:412:3:416:3 | [FunctionDeclStmt] functio ... } } | tst.ts:412:12:412:19 | [VarDecl] setColor | semmle.order | 0 |
| tst.ts:412:3:416:3 | [FunctionDeclStmt] functio ... } } | tst.ts:412:45:416:3 | [BlockStmt] { i ... } } | semmle.label | 5 |
| tst.ts:412:3:416:3 | [FunctionDeclStmt] functio ... } } | tst.ts:412:45:416:3 | [BlockStmt] { i ... } } | semmle.order | 5 |
-| tst.ts:412:21:412:25 | [SimpleParameter] color | tst.ts:412:28:412:42 | [UnionTypeExpr] RGBObj \| HSVObj | semmle.label | 0 |
-| tst.ts:412:21:412:25 | [SimpleParameter] color | tst.ts:412:28:412:42 | [UnionTypeExpr] RGBObj \| HSVObj | semmle.order | 0 |
+| tst.ts:412:21:412:25 | [SimpleParameter] color | tst.ts:412:28:412:42 | [UnionTypeExpr] RGBObj \| HSVObj | semmle.label | -2 |
+| tst.ts:412:21:412:25 | [SimpleParameter] color | tst.ts:412:28:412:42 | [UnionTypeExpr] RGBObj \| HSVObj | semmle.order | -2 |
| tst.ts:412:28:412:42 | [UnionTypeExpr] RGBObj \| HSVObj | tst.ts:412:28:412:33 | [LocalTypeAccess] RGBObj | semmle.label | 1 |
| tst.ts:412:28:412:42 | [UnionTypeExpr] RGBObj \| HSVObj | tst.ts:412:28:412:33 | [LocalTypeAccess] RGBObj | semmle.order | 1 |
| tst.ts:412:28:412:42 | [UnionTypeExpr] RGBObj \| HSVObj | tst.ts:412:37:412:42 | [LocalTypeAccess] HSVObj | semmle.label | 2 |
@@ -4485,8 +4485,8 @@ edges
| tst.ts:422:5:424:5 | [FunctionExpr] constru ... ; } | file://:0:0:0:0 | (Parameters) | semmle.order | 1 |
| tst.ts:422:5:424:5 | [FunctionExpr] constru ... ; } | tst.ts:422:31:424:5 | [BlockStmt] { ... ; } | semmle.label | 5 |
| tst.ts:422:5:424:5 | [FunctionExpr] constru ... ; } | tst.ts:422:31:424:5 | [BlockStmt] { ... ; } | semmle.order | 5 |
-| tst.ts:422:17:422:20 | [SimpleParameter] name | tst.ts:422:23:422:28 | [KeywordTypeExpr] string | semmle.label | 0 |
-| tst.ts:422:17:422:20 | [SimpleParameter] name | tst.ts:422:23:422:28 | [KeywordTypeExpr] string | semmle.order | 0 |
+| tst.ts:422:17:422:20 | [SimpleParameter] name | tst.ts:422:23:422:28 | [KeywordTypeExpr] string | semmle.label | -2 |
+| tst.ts:422:17:422:20 | [SimpleParameter] name | tst.ts:422:23:422:28 | [KeywordTypeExpr] string | semmle.order | -2 |
| tst.ts:422:31:424:5 | [BlockStmt] { ... ; } | tst.ts:423:7:423:23 | [ExprStmt] this.name = name; | semmle.label | 1 |
| tst.ts:422:31:424:5 | [BlockStmt] { ... ; } | tst.ts:423:7:423:23 | [ExprStmt] this.name = name; | semmle.order | 1 |
| tst.ts:423:7:423:15 | [DotExpr] this.name | tst.ts:423:7:423:10 | [ThisExpr] this | semmle.label | 1 |
@@ -4663,8 +4663,8 @@ edges
| type_alias.ts:14:9:14:32 | [FunctionExpr] [proper ... ]: Json | type_alias.ts:14:29:14:32 | [LocalTypeAccess] Json | semmle.order | 4 |
| type_alias.ts:14:9:14:32 | [IndexSignature] [proper ... ]: Json | type_alias.ts:14:9:14:32 | [FunctionExpr] [proper ... ]: Json | semmle.label | 1 |
| type_alias.ts:14:9:14:32 | [IndexSignature] [proper ... ]: Json | type_alias.ts:14:9:14:32 | [FunctionExpr] [proper ... ]: Json | semmle.order | 1 |
-| type_alias.ts:14:10:14:17 | [SimpleParameter] property | type_alias.ts:14:20:14:25 | [KeywordTypeExpr] string | semmle.label | 0 |
-| type_alias.ts:14:10:14:17 | [SimpleParameter] property | type_alias.ts:14:20:14:25 | [KeywordTypeExpr] string | semmle.order | 0 |
+| type_alias.ts:14:10:14:17 | [SimpleParameter] property | type_alias.ts:14:20:14:25 | [KeywordTypeExpr] string | semmle.label | -2 |
+| type_alias.ts:14:10:14:17 | [SimpleParameter] property | type_alias.ts:14:20:14:25 | [KeywordTypeExpr] string | semmle.order | -2 |
| type_alias.ts:15:7:15:12 | [ArrayTypeExpr] Json[] | type_alias.ts:15:7:15:10 | [LocalTypeAccess] Json | semmle.label | 1 |
| type_alias.ts:15:7:15:12 | [ArrayTypeExpr] Json[] | type_alias.ts:15:7:15:10 | [LocalTypeAccess] Json | semmle.order | 1 |
| type_alias.ts:17:1:17:15 | [DeclStmt] var json = ... | type_alias.ts:17:5:17:14 | [VariableDeclarator] json: Json | semmle.label | 1 |
@@ -4695,8 +4695,8 @@ edges
| type_alias.ts:21:18:21:35 | [FunctionExpr] [key: string]: any | type_alias.ts:21:33:21:35 | [KeywordTypeExpr] any | semmle.order | 4 |
| type_alias.ts:21:18:21:35 | [IndexSignature] [key: string]: any | type_alias.ts:21:18:21:35 | [FunctionExpr] [key: string]: any | semmle.label | 1 |
| type_alias.ts:21:18:21:35 | [IndexSignature] [key: string]: any | type_alias.ts:21:18:21:35 | [FunctionExpr] [key: string]: any | semmle.order | 1 |
-| type_alias.ts:21:19:21:21 | [SimpleParameter] key | type_alias.ts:21:24:21:29 | [KeywordTypeExpr] string | semmle.label | 0 |
-| type_alias.ts:21:19:21:21 | [SimpleParameter] key | type_alias.ts:21:24:21:29 | [KeywordTypeExpr] string | semmle.order | 0 |
+| type_alias.ts:21:19:21:21 | [SimpleParameter] key | type_alias.ts:21:24:21:29 | [KeywordTypeExpr] string | semmle.label | -2 |
+| type_alias.ts:21:19:21:21 | [SimpleParameter] key | type_alias.ts:21:24:21:29 | [KeywordTypeExpr] string | semmle.order | -2 |
| type_alias.ts:21:40:21:55 | [RestTypeExpr] ...VirtualNode[] | type_alias.ts:21:43:21:55 | [ArrayTypeExpr] VirtualNode[] | semmle.label | 1 |
| type_alias.ts:21:40:21:55 | [RestTypeExpr] ...VirtualNode[] | type_alias.ts:21:43:21:55 | [ArrayTypeExpr] VirtualNode[] | semmle.order | 1 |
| type_alias.ts:21:43:21:55 | [ArrayTypeExpr] VirtualNode[] | type_alias.ts:21:43:21:53 | [LocalTypeAccess] VirtualNode | semmle.label | 1 |
From e29e077a030d70b5f1dfa89a83572a738d241048 Mon Sep 17 00:00:00 2001
From: Arthur Baars
Date: Thu, 12 Jan 2023 13:25:37 +0100
Subject: [PATCH 214/381] Ruby/QL4QL: include OS version in cache keys
---
.github/actions/os-version/action.yml | 32 +++++++++++++++++++
.github/workflows/ql-for-ql-build.yml | 10 +++---
.../workflows/ql-for-ql-dataset_measure.yml | 4 ++-
.github/workflows/ql-for-ql-tests.yml | 4 ++-
.github/workflows/ruby-build.yml | 6 ++--
ruby/actions/create-extractor-pack/action.yml | 6 ++--
6 files changed, 52 insertions(+), 10 deletions(-)
create mode 100644 .github/actions/os-version/action.yml
diff --git a/.github/actions/os-version/action.yml b/.github/actions/os-version/action.yml
new file mode 100644
index 00000000000..31a33b7a937
--- /dev/null
+++ b/.github/actions/os-version/action.yml
@@ -0,0 +1,32 @@
+name: OS Version
+description: Get OS version.
+
+outputs:
+ version:
+ description: "OS version"
+ value: ${{ steps.version.outputs.version }}
+
+runs:
+ using: composite
+ steps:
+ - if: runner.os == 'Linux'
+ shell: bash
+ run: |
+ . /etc/os-release
+ echo "VERSION=${NAME} ${VERSION}" >> $GITHUB_ENV
+ - if: runner.os == 'Windows'
+ shell: powershell
+ run: |
+ $objects = systeminfo.exe /FO CSV | ConvertFrom-Csv
+ "VERSION=$($objects.'OS Name') $($objects.'OS Version')" >> $env:GITHUB_ENV
+ - if: runner.os == 'macOS'
+ shell: bash
+ run: |
+ echo "VERSION=$(sw_vers -productName) $(sw_vers -productVersion)" >> $GITHUB_ENV
+ - name: Emit OS version
+ id: version
+ shell: bash
+ run: |
+ echo "$VERSION"
+ echo "version=${VERSION}" >> $GITHUB_OUTPUT
+
diff --git a/.github/workflows/ql-for-ql-build.yml b/.github/workflows/ql-for-ql-build.yml
index 29b8bc16300..553fd7bb51c 100644
--- a/.github/workflows/ql-for-ql-build.yml
+++ b/.github/workflows/ql-for-ql-build.yml
@@ -38,12 +38,14 @@ jobs:
shell: bash
env:
CODEQL: ${{ steps.find-codeql.outputs.codeql-path }}
+ - uses: ./.github/actions/os-version
+ id: os_version
- name: Cache entire pack
id: cache-pack
uses: actions/cache@v3
with:
path: ${{ runner.temp }}/pack
- key: ${{ runner.os }}-pack-${{ hashFiles('ql/**/Cargo.lock') }}-${{ hashFiles('ql/**/*.rs') }}-${{ hashFiles('ql/**/*.ql*') }}-${{ hashFiles('ql/**/qlpack.yml') }}-${{ hashFiles('ql/ql/src/ql.dbscheme*') }}-${{ steps.get-codeql-version.outputs.version }}--${{ hashFiles('.github/workflows/ql-for-ql-build.yml') }}
+ key: ${{ runner.os }}-${{ steps.os_version.outputs.version }}-pack-${{ hashFiles('ql/**/Cargo.lock') }}-${{ hashFiles('ql/**/*.rs') }}-${{ hashFiles('ql/**/*.ql*') }}-${{ hashFiles('ql/**/qlpack.yml') }}-${{ hashFiles('ql/ql/src/ql.dbscheme*') }}-${{ steps.get-codeql-version.outputs.version }}--${{ hashFiles('.github/workflows/ql-for-ql-build.yml') }}
- name: Cache queries
if: steps.cache-pack.outputs.cache-hit != 'true'
id: cache-queries
@@ -77,7 +79,7 @@ jobs:
ql/target/release/ql-autobuilder.exe
ql/target/release/ql-extractor
ql/target/release/ql-extractor.exe
- key: ${{ runner.os }}-extractor-${{ hashFiles('ql/**/Cargo.lock') }}-${{ hashFiles('ql/**/*.rs') }}
+ key: ${{ runner.os }}-${{ steps.os_version.outputs.version }}-extractor-${{ hashFiles('ql/**/Cargo.lock') }}-${{ hashFiles('ql/**/*.rs') }}
- name: Cache cargo
if: steps.cache-extractor.outputs.cache-hit != 'true' && steps.cache-pack.outputs.cache-hit != 'true'
uses: actions/cache@v3
@@ -86,7 +88,7 @@ jobs:
~/.cargo/registry
~/.cargo/git
ql/target
- key: ${{ runner.os }}-rust-cargo-${{ hashFiles('ql/**/Cargo.lock') }}
+ key: ${{ runner.os }}-${{ steps.os_version.outputs.version }}-rust-cargo-${{ hashFiles('ql/**/Cargo.lock') }}
- name: Check formatting
if: steps.cache-extractor.outputs.cache-hit != 'true' && steps.cache-pack.outputs.cache-hit != 'true'
run: cd ql; cargo fmt --all -- --check
@@ -172,4 +174,4 @@ jobs:
with:
name: ql-for-ql-langs
path: split-sarif
- retention-days: 1
\ No newline at end of file
+ retention-days: 1
diff --git a/.github/workflows/ql-for-ql-dataset_measure.yml b/.github/workflows/ql-for-ql-dataset_measure.yml
index 41f95a686ba..90614711d0c 100644
--- a/.github/workflows/ql-for-ql-dataset_measure.yml
+++ b/.github/workflows/ql-for-ql-dataset_measure.yml
@@ -28,13 +28,15 @@ jobs:
uses: github/codeql-action/init@77a8d2d10c0b403a8b4aadbd223dc489ecd22683
with:
languages: javascript # does not matter
+ - uses: ./.github/actions/os-version
+ id: os_version
- uses: actions/cache@v3
with:
path: |
~/.cargo/registry
~/.cargo/git
ql/target
- key: ${{ runner.os }}-qltest-cargo-${{ hashFiles('ql/**/Cargo.lock') }}
+ key: ${{ runner.os }}-${{ steps.os_version.outputs.version }}-qltest-cargo-${{ hashFiles('ql/**/Cargo.lock') }}
- name: Build Extractor
run: cd ql; env "PATH=$PATH:`dirname ${CODEQL}`" ./scripts/create-extractor-pack.sh
env:
diff --git a/.github/workflows/ql-for-ql-tests.yml b/.github/workflows/ql-for-ql-tests.yml
index ce7963e8f79..fd8001de8c7 100644
--- a/.github/workflows/ql-for-ql-tests.yml
+++ b/.github/workflows/ql-for-ql-tests.yml
@@ -25,13 +25,15 @@ jobs:
uses: github/codeql-action/init@77a8d2d10c0b403a8b4aadbd223dc489ecd22683
with:
languages: javascript # does not matter
+ - uses: ./.github/actions/os-version
+ id: os_version
- uses: actions/cache@v3
with:
path: |
~/.cargo/registry
~/.cargo/git
ql/target
- key: ${{ runner.os }}-qltest-cargo-${{ hashFiles('ql/**/Cargo.lock') }}
+ key: ${{ runner.os }}-${{ steps.os_version.outputs.version }}-qltest-cargo-${{ hashFiles('ql/**/Cargo.lock') }}
- name: Build extractor
run: |
cd ql;
diff --git a/.github/workflows/ruby-build.yml b/.github/workflows/ruby-build.yml
index e272f2ba319..e371ffcae27 100644
--- a/.github/workflows/ruby-build.yml
+++ b/.github/workflows/ruby-build.yml
@@ -48,6 +48,8 @@ jobs:
run: |
brew install gnu-tar
echo "/usr/local/opt/gnu-tar/libexec/gnubin" >> $GITHUB_PATH
+ - uses: ./.github/actions/os-version
+ id: os_version
- name: Cache entire extractor
uses: actions/cache@v3
id: cache-extractor
@@ -58,7 +60,7 @@ jobs:
ruby/target/release/ruby-extractor
ruby/target/release/ruby-extractor.exe
ruby/ql/lib/codeql/ruby/ast/internal/TreeSitter.qll
- key: ${{ runner.os }}-ruby-extractor-${{ hashFiles('ruby/rust-toolchain.toml', 'ruby/**/Cargo.lock') }}--${{ hashFiles('ruby/**/*.rs') }}
+ key: ${{ runner.os }}-${{ steps.os_version.outputs.version }}-ruby-extractor-${{ hashFiles('ruby/rust-toolchain.toml', 'ruby/**/Cargo.lock') }}--${{ hashFiles('ruby/**/*.rs') }}
- uses: actions/cache@v3
if: steps.cache-extractor.outputs.cache-hit != 'true'
with:
@@ -66,7 +68,7 @@ jobs:
~/.cargo/registry
~/.cargo/git
ruby/target
- key: ${{ runner.os }}-ruby-rust-cargo-${{ hashFiles('ruby/rust-toolchain.toml', 'ruby/**/Cargo.lock') }}
+ key: ${{ runner.os }}-${{ steps.os_version.outputs.version }}-ruby-rust-cargo-${{ hashFiles('ruby/rust-toolchain.toml', 'ruby/**/Cargo.lock') }}
- name: Check formatting
if: steps.cache-extractor.outputs.cache-hit != 'true'
run: cargo fmt --all -- --check
diff --git a/ruby/actions/create-extractor-pack/action.yml b/ruby/actions/create-extractor-pack/action.yml
index 667158c264c..7062dd0cfcd 100644
--- a/ruby/actions/create-extractor-pack/action.yml
+++ b/ruby/actions/create-extractor-pack/action.yml
@@ -3,12 +3,14 @@ description: Builds the Ruby CodeQL pack
runs:
using: composite
steps:
+ - uses: ./.github/actions/os-version
+ id: os_version
- name: Cache entire extractor
id: cache-extractor
uses: actions/cache@v3
with:
path: ruby/extractor-pack
- key: ${{ runner.os }}-extractor-${{ hashFiles('ruby/rust-toolchain.toml', 'ruby/**/Cargo.lock') }}-${{ hashFiles('ruby/**/*.rs') }}-${{ hashFiles('ruby/codeql-extractor.yml', 'ruby/downgrades', 'ruby/tools', 'ruby/ql/lib/ruby.dbscheme', 'ruby/ql/lib/ruby.dbscheme.stats') }}
+ key: ${{ runner.os }}-${{ steps.os_version.outputs.version }}-extractor-${{ hashFiles('ruby/rust-toolchain.toml', 'ruby/**/Cargo.lock') }}-${{ hashFiles('ruby/**/*.rs') }}-${{ hashFiles('ruby/codeql-extractor.yml', 'ruby/downgrades', 'ruby/tools', 'ruby/ql/lib/ruby.dbscheme', 'ruby/ql/lib/ruby.dbscheme.stats') }}
- name: Cache cargo
uses: actions/cache@v3
if: steps.cache-extractor.outputs.cache-hit != 'true'
@@ -17,7 +19,7 @@ runs:
~/.cargo/registry
~/.cargo/git
ruby/target
- key: ${{ runner.os }}-ruby-qltest-cargo-${{ hashFiles('ruby/rust-toolchain.toml', 'ruby/**/Cargo.lock') }}
+ key: ${{ runner.os }}-${{ steps.os_version.outputs.version }}-ruby-qltest-cargo-${{ hashFiles('ruby/rust-toolchain.toml', 'ruby/**/Cargo.lock') }}
- name: Build Extractor
if: steps.cache-extractor.outputs.cache-hit != 'true'
shell: bash
From e0444449c883aba3b423fc8dc5acb151ab77fe2e Mon Sep 17 00:00:00 2001
From: Jami Cogswell
Date: Thu, 12 Jan 2023 09:58:53 -0500
Subject: [PATCH 215/381] Java: remove Function.apply model
---
java/ql/lib/ext/java.util.function.model.yml | 1 -
java/ql/test/ext/TestModels/Test.java | 6 ------
java/ql/test/ext/TopJdkApis/TopJdkApis.qll | 1 +
java/ql/test/ext/TopJdkApis/TopJdkApisTest.expected | 1 +
4 files changed, 2 insertions(+), 7 deletions(-)
diff --git a/java/ql/lib/ext/java.util.function.model.yml b/java/ql/lib/ext/java.util.function.model.yml
index 9ee54700752..41d0f1f77df 100644
--- a/java/ql/lib/ext/java.util.function.model.yml
+++ b/java/ql/lib/ext/java.util.function.model.yml
@@ -9,5 +9,4 @@ extensions:
pack: codeql/java-all
extensible: summaryModel
data:
- - ["java.util.function", "Function", True, "apply", "(Object)", "", "Argument[0]", "ReturnValue", "taint", "manual"]
- ["java.util.function", "Supplier", False, "get", "()", "", "Argument[-1]", "ReturnValue", "value", "manual"]
diff --git a/java/ql/test/ext/TestModels/Test.java b/java/ql/test/ext/TestModels/Test.java
index c2053d67929..8560ad1e565 100644
--- a/java/ql/test/ext/TestModels/Test.java
+++ b/java/ql/test/ext/TestModels/Test.java
@@ -78,12 +78,6 @@ public class Test {
sink(ar.get()); // $hasValueFlow
// java.util.function
- Function func = a -> a + "";
- sink(func.apply(source())); // $hasTaintFlow
-
- Function half = a -> a / 2.0;
- sink(half.apply((Integer)source())); // $hasTaintFlow
-
Supplier sup = (Supplier)source();
sink(sup.get()); // $hasValueFlow
diff --git a/java/ql/test/ext/TopJdkApis/TopJdkApis.qll b/java/ql/test/ext/TopJdkApis/TopJdkApis.qll
index b00cfb4cad7..013d212fdcb 100644
--- a/java/ql/test/ext/TopJdkApis/TopJdkApis.qll
+++ b/java/ql/test/ext/TopJdkApis/TopJdkApis.qll
@@ -146,6 +146,7 @@ class TopJdkApi extends SummarizedCallableBase {
* `java.lang.String#valueOf(Object)`: a complex case; an alias for `Object.toString`, except the dispatch is hidden
* `java.lang.Throwable#printStackTrace()`: should probably not be a general step, but there might be specialised queries that care
* `java.util.function.Consumer#accept(Object)`: specialized lambda flow
+ * `java.util.function.Function#apply(Object)`: specialized lambda flow
* `java.util.stream.Collectors#joining(CharSequence)`: cannot be modeled completely without a model for `java.util.stream.Stream#collect(Collector)` as well
* `java.util.stream.Collectors#toMap(Function,Function)`: specialized collectors flow
* `java.util.stream.Stream#collect(Collector)`: handled separately on a case-by-case basis as it is too complex for MaD
diff --git a/java/ql/test/ext/TopJdkApis/TopJdkApisTest.expected b/java/ql/test/ext/TopJdkApis/TopJdkApisTest.expected
index 2023810b44d..fd63ca00a53 100644
--- a/java/ql/test/ext/TopJdkApis/TopJdkApisTest.expected
+++ b/java/ql/test/ext/TopJdkApis/TopJdkApisTest.expected
@@ -1,6 +1,7 @@
| java.lang.String#valueOf(Object) | no manual model |
| java.lang.Throwable#printStackTrace() | no manual model |
| java.util.function.Consumer#accept(Object) | no manual model |
+| java.util.function.Function#apply(Object) | no manual model |
| java.util.stream.Collectors#joining(CharSequence) | no manual model |
| java.util.stream.Collectors#toMap(Function,Function) | no manual model |
| java.util.stream.Stream#collect(Collector) | no manual model |
From 7f31c9c7e59270b09235448b05220d4a81171e5f Mon Sep 17 00:00:00 2001
From: Geoffrey White <40627776+geoffw0@users.noreply.github.com>
Date: Thu, 12 Jan 2023 14:48:40 +0000
Subject: [PATCH 216/381] Swift: Add a test.
---
.../elements/type/numerictype/numeric.swift | 32 +++++++++++++++++++
.../type/numerictype/numerictype.expected | 22 +++++++++++++
.../elements/type/numerictype/numerictype.ql | 19 +++++++++++
3 files changed, 73 insertions(+)
create mode 100644 swift/ql/test/library-tests/elements/type/numerictype/numeric.swift
create mode 100644 swift/ql/test/library-tests/elements/type/numerictype/numerictype.expected
create mode 100644 swift/ql/test/library-tests/elements/type/numerictype/numerictype.ql
diff --git a/swift/ql/test/library-tests/elements/type/numerictype/numeric.swift b/swift/ql/test/library-tests/elements/type/numerictype/numeric.swift
new file mode 100644
index 00000000000..6da917e1411
--- /dev/null
+++ b/swift/ql/test/library-tests/elements/type/numerictype/numeric.swift
@@ -0,0 +1,32 @@
+
+typealias MyFloat = Float
+
+func test() {
+ var f1: Float
+ let f2 = 123.456
+ let f3 = f2
+ var f4: Float?
+ var f5: MyFloat
+ var f6: MyFloat?
+
+ var d: Double
+
+ var c: Character
+
+ var i1: Int
+ let i2 = 123
+ let i3 = 0xFFFF
+ var i4: Int8
+ var i5: Int16
+ var i6: Int32
+ var i7: Int64
+
+ var u1: UInt
+ var u2: UInt8
+ var u3: UInt16
+ var u4: UInt32
+ var u5: UInt64
+
+ var b1: Bool
+ let b2 = true
+}
diff --git a/swift/ql/test/library-tests/elements/type/numerictype/numerictype.expected b/swift/ql/test/library-tests/elements/type/numerictype/numerictype.expected
new file mode 100644
index 00000000000..5670aededb8
--- /dev/null
+++ b/swift/ql/test/library-tests/elements/type/numerictype/numerictype.expected
@@ -0,0 +1,22 @@
+| numeric.swift:5:6:5:6 | f1 | Float | FloatingPointType, NumericType |
+| numeric.swift:6:6:6:6 | f2 | Double | FloatingPointType, NumericType |
+| numeric.swift:7:6:7:6 | f3 | Double | FloatingPointType, NumericType |
+| numeric.swift:8:6:8:6 | f4 | Float? | |
+| numeric.swift:9:6:9:6 | f5 | MyFloat | |
+| numeric.swift:10:6:10:6 | f6 | MyFloat? | |
+| numeric.swift:12:6:12:6 | d | Double | FloatingPointType, NumericType |
+| numeric.swift:14:6:14:6 | c | Character | CharacterType |
+| numeric.swift:16:6:16:6 | i1 | Int | IntegralType, NumericType |
+| numeric.swift:17:6:17:6 | i2 | Int | IntegralType, NumericType |
+| numeric.swift:18:6:18:6 | i3 | Int | IntegralType, NumericType |
+| numeric.swift:19:6:19:6 | i4 | Int8 | IntegralType, NumericType |
+| numeric.swift:20:6:20:6 | i5 | Int16 | IntegralType, NumericType |
+| numeric.swift:21:6:21:6 | i6 | Int32 | IntegralType, NumericType |
+| numeric.swift:22:6:22:6 | i7 | Int64 | IntegralType, NumericType |
+| numeric.swift:24:6:24:6 | u1 | UInt | IntegralType, NumericType |
+| numeric.swift:25:6:25:6 | u2 | UInt8 | IntegralType, NumericType |
+| numeric.swift:26:6:26:6 | u3 | UInt16 | IntegralType, NumericType |
+| numeric.swift:27:6:27:6 | u4 | UInt32 | IntegralType, NumericType |
+| numeric.swift:28:6:28:6 | u5 | UInt64 | IntegralType, NumericType |
+| numeric.swift:30:6:30:6 | b1 | Bool | BoolType |
+| numeric.swift:31:6:31:6 | b2 | Bool | BoolType |
diff --git a/swift/ql/test/library-tests/elements/type/numerictype/numerictype.ql b/swift/ql/test/library-tests/elements/type/numerictype/numerictype.ql
new file mode 100644
index 00000000000..7f3fb4591f8
--- /dev/null
+++ b/swift/ql/test/library-tests/elements/type/numerictype/numerictype.ql
@@ -0,0 +1,19 @@
+import swift
+
+string describe(Type t) {
+ t instanceof FloatingPointType and result = "FloatingPointType"
+ or
+ t instanceof CharacterType and result = "CharacterType"
+ or
+ t instanceof IntegralType and result = "IntegralType"
+ or
+ t instanceof BoolType and result = "BoolType"
+ or
+ t instanceof NumericType and result = "NumericType"
+}
+
+from VarDecl v, Type t
+where
+ v.getLocation().getFile().getBaseName() != "" and
+ t = v.getType()
+select v, t.toString(), concat(describe(t), ", ")
From 09d8a50494ce0049daff3bc6e7d94091759b8ed4 Mon Sep 17 00:00:00 2001
From: Chris Smowton
Date: Thu, 12 Jan 2023 17:46:00 +0000
Subject: [PATCH 217/381] Spelling
---
java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.qhelp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.qhelp b/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.qhelp
index c991e037791..6806527e442 100644
--- a/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.qhelp
+++ b/java/ql/src/Security/CWE/CWE-502/UnsafeDeserialization.qhelp
@@ -70,7 +70,7 @@ Recommendations specific to particular frameworks supported by this query:
XML Decoder - Standard Java Library
-
Secure by Defauly: No
+
Secure by Default: No
Recommendation: Do not use with untrusted user input.
From a9f1c9551312d842ddd92fd34b030ac75e1ccd31 Mon Sep 17 00:00:00 2001
From: Michael Nebel
Date: Fri, 6 Jan 2023 15:10:13 +0100
Subject: [PATCH 218/381] C#: Rename shift assignment expression classes.
---
.../semmle/code/csharp/exprs/Assignment.qll | 18 ++++++++++++------
.../raw/internal/TranslatedExpr.qll | 8 ++++----
.../test/experimental/ir/ir/PrintAst.expected | 4 ++--
3 files changed, 18 insertions(+), 12 deletions(-)
diff --git a/csharp/ql/lib/semmle/code/csharp/exprs/Assignment.qll b/csharp/ql/lib/semmle/code/csharp/exprs/Assignment.qll
index 562a4dd9cd5..ce5022c5f89 100644
--- a/csharp/ql/lib/semmle/code/csharp/exprs/Assignment.qll
+++ b/csharp/ql/lib/semmle/code/csharp/exprs/Assignment.qll
@@ -150,8 +150,8 @@ class AssignRemExpr extends AssignArithmeticOperation, @assign_rem_expr {
* operation (`AssignAndExpr`), a bitwise-or assignment
* operation (`AssignOrExpr`), a bitwise exclusive-or assignment
* operation (`AssignXorExpr`), a left-shift assignment
- * operation (`AssignLShiftExpr`), or a right-shift assignment
- * operation (`AssignRShiftExpr`).
+ * operation (`AssignLeftShiftExpr`), or a right-shift assignment
+ * operation (`AssignRightShiftExpr`).
*/
class AssignBitwiseOperation extends AssignOperation, @assign_bitwise_expr { }
@@ -185,21 +185,27 @@ class AssignXorExpr extends AssignBitwiseOperation, @assign_xor_expr {
/**
* A left-shift assignment operation, for example `x <<= y`.
*/
-class AssignLShiftExpr extends AssignBitwiseOperation, @assign_lshift_expr {
+class AssignLeftShiftExpr extends AssignBitwiseOperation, @assign_lshift_expr {
override string getOperator() { result = "<<=" }
- override string getAPrimaryQlClass() { result = "AssignLShiftExpr" }
+ override string getAPrimaryQlClass() { result = "AssignLeftShiftExpr" }
}
+/** DEPRECATED: Alias for AssignLeftShipExpr. */
+deprecated class AssignLShiftExpr = AssignLeftShiftExpr;
+
/**
* A right-shift assignment operation, for example `x >>= y`.
*/
-class AssignRShiftExpr extends AssignBitwiseOperation, @assign_rshift_expr {
+class AssignRightShiftExpr extends AssignBitwiseOperation, @assign_rshift_expr {
override string getOperator() { result = ">>=" }
- override string getAPrimaryQlClass() { result = "AssignRShiftExpr" }
+ override string getAPrimaryQlClass() { result = "AssignRightShiftExpr" }
}
+/** DEPRECATED: Alias for AssignRightShiftExpr. */
+deprecated class AssignRShiftExpr = AssignRightShiftExpr;
+
/**
* An event assignment. Either an event addition (`AddEventExpr`) or an event
* removal (`RemoveEventExpr`).
diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedExpr.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedExpr.qll
index 1bcca401565..7be1fa40ebb 100644
--- a/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedExpr.qll
+++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedExpr.qll
@@ -1377,8 +1377,8 @@ class TranslatedAssignOperation extends TranslatedAssignment {
private Type getConvertedLeftOperandType() {
if
- expr instanceof AssignLShiftExpr or
- expr instanceof AssignRShiftExpr
+ expr instanceof AssignLeftShiftExpr or
+ expr instanceof AssignRightShiftExpr
then result = this.getLeftOperand().getResultType()
else
// The right operand has already been converted to the type of the op.
@@ -1416,9 +1416,9 @@ class TranslatedAssignOperation extends TranslatedAssignment {
or
expr instanceof AssignXorExpr and result instanceof Opcode::BitXor
or
- expr instanceof AssignLShiftExpr and result instanceof Opcode::ShiftLeft
+ expr instanceof AssignLeftShiftExpr and result instanceof Opcode::ShiftLeft
or
- expr instanceof AssignRShiftExpr and result instanceof Opcode::ShiftRight
+ expr instanceof AssignRightShiftExpr and result instanceof Opcode::ShiftRight
}
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) {
diff --git a/csharp/ql/test/experimental/ir/ir/PrintAst.expected b/csharp/ql/test/experimental/ir/ir/PrintAst.expected
index 41b5b6daead..480b63f4241 100644
--- a/csharp/ql/test/experimental/ir/ir/PrintAst.expected
+++ b/csharp/ql/test/experimental/ir/ir/PrintAst.expected
@@ -152,11 +152,11 @@ assignop.cs:
# 12| 0: [LocalVariableAccess] access to local variable c
# 12| 1: [LocalVariableAccess] access to local variable a
# 13| 7: [ExprStmt] ...;
-# 13| 0: [AssignLShiftExpr] ... <<= ...
+# 13| 0: [AssignLeftShiftExpr] ... <<= ...
# 13| 0: [LocalVariableAccess] access to local variable c
# 13| 1: [IntLiteral] 2
# 14| 8: [ExprStmt] ...;
-# 14| 0: [AssignRShiftExpr] ... >>= ...
+# 14| 0: [AssignRightShiftExpr] ... >>= ...
# 14| 0: [LocalVariableAccess] access to local variable c
# 14| 1: [IntLiteral] 2
# 15| 9: [ExprStmt] ...;
From 36980bbf4221524a98d914b2e99da487ab74d87f Mon Sep 17 00:00:00 2001
From: Michael Nebel
Date: Fri, 6 Jan 2023 15:26:19 +0100
Subject: [PATCH 219/381] C#: Rename shift expression classes.
---
.../code/csharp/dataflow/ModulusAnalysis.qll | 2 +-
.../rangeanalysis/ModulusAnalysisSpecific.qll | 5 ++++-
.../internal/rangeanalysis/RangeUtils.qll | 14 ++++++++++----
.../rangeanalysis/SignAnalysisSpecific.qll | 4 ++--
.../code/csharp/exprs/BitwiseOperation.qll | 16 +++++++++++-----
.../raw/internal/TranslatedExpr.qll | 4 ++--
.../library-tests/indexers/PrintAst.expected | 14 +++++++-------
7 files changed, 37 insertions(+), 22 deletions(-)
diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/ModulusAnalysis.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/ModulusAnalysis.qll
index b919d143a39..5b2a39ad6c9 100644
--- a/csharp/ql/lib/semmle/code/csharp/dataflow/ModulusAnalysis.qll
+++ b/csharp/ql/lib/semmle/code/csharp/dataflow/ModulusAnalysis.qll
@@ -105,7 +105,7 @@ private predicate evenlyDivisibleExpr(Expr e, int factor) {
exists(ConstantIntegerExpr c, int k | k = c.getIntValue() |
e.(MulExpr).getAnOperand() = c and factor = k.abs() and factor >= 2
or
- e.(LShiftExpr).getRhs() = c and factor = 2.pow(k) and k > 0
+ e.(LeftShiftExpr).getRhs() = c and factor = 2.pow(k) and k > 0
or
e.(BitwiseAndExpr).getAnOperand() = c and factor = max(int f | andmaskFactor(k, f))
)
diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/ModulusAnalysisSpecific.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/ModulusAnalysisSpecific.qll
index 74aee61e690..3b7e29888d2 100644
--- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/ModulusAnalysisSpecific.qll
+++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/ModulusAnalysisSpecific.qll
@@ -30,7 +30,10 @@ module Private {
class MulExpr = RU::ExprNode::MulExpr;
- class LShiftExpr = RU::ExprNode::LShiftExpr;
+ class LeftShiftExpr = RU::ExprNode::LeftShiftExpr;
+
+ /** DEPRECATED: Alias for LeftShiftExpr. */
+ deprecated class LShiftExpr = LeftShiftExpr;
predicate guardDirectlyControlsSsaRead = RU::guardControlsSsaRead/3;
diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/RangeUtils.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/RangeUtils.qll
index ce7637ccd92..0f1dcdb7673 100644
--- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/RangeUtils.qll
+++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/RangeUtils.qll
@@ -391,19 +391,25 @@ module ExprNode {
}
/** A left-shift operation. */
- class LShiftExpr extends BinaryOperation {
- override CS::LShiftExpr e;
+ class LeftShiftExpr extends BinaryOperation {
+ override CS::LeftShiftExpr e;
override TLShiftOp getOp() { any() }
}
+ /** DEPRECATED: Alias for LeftShiftExpr. */
+ deprecated class LShiftExpr = LeftShiftExpr;
+
/** A right-shift operation. */
- class RShiftExpr extends BinaryOperation {
- override CS::RShiftExpr e;
+ class RightShiftExpr extends BinaryOperation {
+ override CS::RightShiftExpr e;
override TRShiftOp getOp() { any() }
}
+ /** DEPRECATED: Alias for RightShiftExpr. */
+ deprecated class RShiftExpr = RightShiftExpr;
+
/** A conditional expression. */
class ConditionalExpr extends ExprNode {
override CS::ConditionalExpr e;
diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SignAnalysisSpecific.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SignAnalysisSpecific.qll
index 9102bf29131..ebff0c94e54 100644
--- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SignAnalysisSpecific.qll
+++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SignAnalysisSpecific.qll
@@ -211,8 +211,8 @@ private module Impl {
not e.getExpr() instanceof BitwiseAndExpr and
not e.getExpr() instanceof BitwiseOrExpr and
not e.getExpr() instanceof BitwiseXorExpr and
- not e.getExpr() instanceof LShiftExpr and
- not e.getExpr() instanceof RShiftExpr and
+ not e.getExpr() instanceof LeftShiftExpr and
+ not e.getExpr() instanceof RightShiftExpr and
not e.getExpr() instanceof ConditionalExpr and
not e.getExpr() instanceof RefExpr and
not e.getExpr() instanceof LocalVariableDeclAndInitExpr and
diff --git a/csharp/ql/lib/semmle/code/csharp/exprs/BitwiseOperation.qll b/csharp/ql/lib/semmle/code/csharp/exprs/BitwiseOperation.qll
index a23da710465..23e02756ce2 100644
--- a/csharp/ql/lib/semmle/code/csharp/exprs/BitwiseOperation.qll
+++ b/csharp/ql/lib/semmle/code/csharp/exprs/BitwiseOperation.qll
@@ -31,7 +31,7 @@ class ComplementExpr extends UnaryBitwiseOperation, @bit_not_expr {
* A binary bitwise operation. Either a bitwise-and operation
* (`BitwiseAndExpr`), a bitwise-or operation (`BitwiseOrExpr`),
* a bitwise exclusive-or operation (`BitwiseXorExpr`), a left-shift
- * operation (`LShiftExpr`), or a right-shift operation (`RShiftExpr`).
+ * operation (`LeftShiftExpr`), or a right-shift operation (`RightShiftExpr`).
*/
class BinaryBitwiseOperation extends BitwiseOperation, BinaryOperation, @bin_bit_op_expr {
override string getOperator() { none() }
@@ -40,21 +40,27 @@ class BinaryBitwiseOperation extends BitwiseOperation, BinaryOperation, @bin_bit
/**
* A left-shift operation, for example `x << y`.
*/
-class LShiftExpr extends BinaryBitwiseOperation, @lshift_expr {
+class LeftShiftExpr extends BinaryBitwiseOperation, @lshift_expr {
override string getOperator() { result = "<<" }
- override string getAPrimaryQlClass() { result = "LShiftExpr" }
+ override string getAPrimaryQlClass() { result = "LeftShiftExpr" }
}
+/** DEPRECATED: Alias for LeftShiftExpr. */
+deprecated class LShiftExpr = LeftShiftExpr;
+
/**
* A right-shift operation, for example `x >> y`.
*/
-class RShiftExpr extends BinaryBitwiseOperation, @rshift_expr {
+class RightShiftExpr extends BinaryBitwiseOperation, @rshift_expr {
override string getOperator() { result = ">>" }
- override string getAPrimaryQlClass() { result = "RShiftExpr" }
+ override string getAPrimaryQlClass() { result = "RightShiftExpr" }
}
+/** DEPRECATED: Alias for RightShiftExpr. */
+deprecated class RShiftExpr = RightShiftExpr;
+
/**
* A bitwise-and operation, for example `x & y`.
*/
diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedExpr.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedExpr.qll
index 7be1fa40ebb..56c2621afb9 100644
--- a/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedExpr.qll
+++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedExpr.qll
@@ -1091,9 +1091,9 @@ class TranslatedCast extends TranslatedNonConstantExpr {
}
private Opcode binaryBitwiseOpcode(BinaryBitwiseOperation expr) {
- expr instanceof LShiftExpr and result instanceof Opcode::ShiftLeft
+ expr instanceof LeftShiftExpr and result instanceof Opcode::ShiftLeft
or
- expr instanceof RShiftExpr and result instanceof Opcode::ShiftRight
+ expr instanceof RightShiftExpr and result instanceof Opcode::ShiftRight
or
expr instanceof BitwiseAndExpr and result instanceof Opcode::BitAnd
or
diff --git a/csharp/ql/test/library-tests/indexers/PrintAst.expected b/csharp/ql/test/library-tests/indexers/PrintAst.expected
index cd97a04290a..36f15f11909 100644
--- a/csharp/ql/test/library-tests/indexers/PrintAst.expected
+++ b/csharp/ql/test/library-tests/indexers/PrintAst.expected
@@ -25,7 +25,7 @@ indexers.cs:
# 18| -1: [TypeMention] Int32[]
# 18| 1: [TypeMention] int
# 18| 0: [AddExpr] ... + ...
-# 18| 0: [RShiftExpr] ... >> ...
+# 18| 0: [RightShiftExpr] ... >> ...
# 18| 0: [SubExpr] ... - ...
# 18| 0: [ParameterAccess] access to parameter length
# 18| 1: [IntLiteral] 1
@@ -68,10 +68,10 @@ indexers.cs:
# 32| 0: [BitwiseAndExpr] ... & ...
# 32| 0: [ArrayAccess] access to array element
# 32| -1: [FieldAccess] access to field bits
-# 32| 0: [RShiftExpr] ... >> ...
+# 32| 0: [RightShiftExpr] ... >> ...
# 32| 0: [ParameterAccess] access to parameter index
# 32| 1: [IntLiteral] 5
-# 32| 1: [LShiftExpr] ... << ...
+# 32| 1: [LeftShiftExpr] ... << ...
# 32| 0: [IntLiteral] 1
# 32| 1: [ParameterAccess] access to parameter index
# 32| 1: [IntLiteral] 0
@@ -99,10 +99,10 @@ indexers.cs:
# 42| 0: [AssignOrExpr] ... |= ...
# 42| 0: [ArrayAccess] access to array element
# 42| -1: [FieldAccess] access to field bits
-# 42| 0: [RShiftExpr] ... >> ...
+# 42| 0: [RightShiftExpr] ... >> ...
# 42| 0: [ParameterAccess] access to parameter index
# 42| 1: [IntLiteral] 5
-# 42| 1: [LShiftExpr] ... << ...
+# 42| 1: [LeftShiftExpr] ... << ...
# 42| 0: [IntLiteral] 1
# 42| 1: [ParameterAccess] access to parameter index
# 45| 2: [BlockStmt] {...}
@@ -110,11 +110,11 @@ indexers.cs:
# 46| 0: [AssignAndExpr] ... &= ...
# 46| 0: [ArrayAccess] access to array element
# 46| -1: [FieldAccess] access to field bits
-# 46| 0: [RShiftExpr] ... >> ...
+# 46| 0: [RightShiftExpr] ... >> ...
# 46| 0: [ParameterAccess] access to parameter index
# 46| 1: [IntLiteral] 5
# 46| 1: [ComplementExpr] ~...
-# 46| 0: [LShiftExpr] ... << ...
+# 46| 0: [LeftShiftExpr] ... << ...
# 46| 0: [IntLiteral] 1
# 46| 1: [ParameterAccess] access to parameter index
# 53| 2: [Class] CountPrimes
From 902b0a60d086b100263ee4e105a16821201b602a Mon Sep 17 00:00:00 2001
From: Michael Nebel
Date: Mon, 9 Jan 2023 11:16:17 +0100
Subject: [PATCH 220/381] C#: Fixup ShiftExpr rename.
---
.../internal/rangeanalysis/ModulusAnalysisSpecific.qll | 3 ---
.../csharp/dataflow/internal/rangeanalysis/RangeUtils.qll | 6 ------
2 files changed, 9 deletions(-)
diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/ModulusAnalysisSpecific.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/ModulusAnalysisSpecific.qll
index 3b7e29888d2..4a9c3cdbe6d 100644
--- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/ModulusAnalysisSpecific.qll
+++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/ModulusAnalysisSpecific.qll
@@ -32,9 +32,6 @@ module Private {
class LeftShiftExpr = RU::ExprNode::LeftShiftExpr;
- /** DEPRECATED: Alias for LeftShiftExpr. */
- deprecated class LShiftExpr = LeftShiftExpr;
-
predicate guardDirectlyControlsSsaRead = RU::guardControlsSsaRead/3;
predicate guardControlsSsaRead = RU::guardControlsSsaRead/3;
diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/RangeUtils.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/RangeUtils.qll
index 0f1dcdb7673..4b2894721b5 100644
--- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/RangeUtils.qll
+++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/RangeUtils.qll
@@ -397,9 +397,6 @@ module ExprNode {
override TLShiftOp getOp() { any() }
}
- /** DEPRECATED: Alias for LeftShiftExpr. */
- deprecated class LShiftExpr = LeftShiftExpr;
-
/** A right-shift operation. */
class RightShiftExpr extends BinaryOperation {
override CS::RightShiftExpr e;
@@ -407,9 +404,6 @@ module ExprNode {
override TRShiftOp getOp() { any() }
}
- /** DEPRECATED: Alias for RightShiftExpr. */
- deprecated class RShiftExpr = RightShiftExpr;
-
/** A conditional expression. */
class ConditionalExpr extends ExprNode {
override CS::ConditionalExpr e;
From 14c92e6eb34b4a71d0ba55ac744b7730fd8a51c0 Mon Sep 17 00:00:00 2001
From: Michael Nebel
Date: Fri, 6 Jan 2023 16:16:15 +0100
Subject: [PATCH 221/381] C#: Add expressions kind including dummy stats for
unsigned right shift and unsigned right shift assigment.
---
.../extractor/Semmle.Extraction.CSharp/Kinds/ExprKind.cs | 2 ++
csharp/ql/lib/semmlecode.csharp.dbscheme | 6 ++++--
csharp/ql/lib/semmlecode.csharp.dbscheme.stats | 8 ++++++++
3 files changed, 14 insertions(+), 2 deletions(-)
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Kinds/ExprKind.cs b/csharp/extractor/Semmle.Extraction.CSharp/Kinds/ExprKind.cs
index a56ccf4c746..ef0b9412ef4 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Kinds/ExprKind.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Kinds/ExprKind.cs
@@ -127,6 +127,8 @@ namespace Semmle.Extraction.Kinds
WITH = 130,
LIST_PATTERN = 131,
SLICE_PATTERN = 132,
+ URSHIFT = 133,
+ ASSIGN_URSHIFT = 134,
DEFINE_SYMBOL = 999,
}
}
diff --git a/csharp/ql/lib/semmlecode.csharp.dbscheme b/csharp/ql/lib/semmlecode.csharp.dbscheme
index 83aca6b3e4f..d0fba103f7d 100644
--- a/csharp/ql/lib/semmlecode.csharp.dbscheme
+++ b/csharp/ql/lib/semmlecode.csharp.dbscheme
@@ -1137,6 +1137,8 @@ case @expr.kind of
/* C# 11.0 */
| 131 = @list_pattern_expr
| 132 = @slice_pattern_expr
+| 133 = @urshift_expr
+| 134 = @assign_urshift_expr
/* Preprocessor */
| 999 = @define_symbol_expr
;
@@ -1160,7 +1162,7 @@ case @expr.kind of
@assign_arith_expr = @assign_add_expr | @assign_sub_expr | @assign_mul_expr | @assign_div_expr
| @assign_rem_expr
@assign_bitwise_expr = @assign_and_expr | @assign_or_expr | @assign_xor_expr
- | @assign_lshift_expr | @assign_rshift_expr;
+ | @assign_lshift_expr | @assign_rshift_expr | @assign_urshift_expr;
@member_access_expr = @field_access_expr | @property_access_expr | @indexer_access_expr | @event_access_expr
| @method_access_expr | @type_access_expr | @dynamic_member_access_expr;
@@ -1191,7 +1193,7 @@ case @expr.kind of
@log_expr = @un_log_op_expr | @bin_log_op_expr | @ternary_log_op_expr;
@bin_bit_op_expr = @bit_and_expr | @bit_or_expr | @bit_xor_expr | @lshift_expr
- | @rshift_expr;
+ | @rshift_expr | @urshift_expr;
@un_bit_op_expr = @bit_not_expr;
@bit_expr = @un_bit_op_expr | @bin_bit_op_expr;
diff --git a/csharp/ql/lib/semmlecode.csharp.dbscheme.stats b/csharp/ql/lib/semmlecode.csharp.dbscheme.stats
index 04516487ee9..8204b7b9aaa 100644
--- a/csharp/ql/lib/semmlecode.csharp.dbscheme.stats
+++ b/csharp/ql/lib/semmlecode.csharp.dbscheme.stats
@@ -644,6 +644,10 @@
@rshift_expr5127
+
+ @urshift_expr
+ 0
+ @lt_expr34251
@@ -836,6 +840,10 @@
@assign_rshift_expr455
+
+ @assign_urshift_expr
+ 0
+ @par_expr0
From 99b7bc3b73bb9768a09a3a47bce0a558bc270406 Mon Sep 17 00:00:00 2001
From: Michael Nebel
Date: Fri, 6 Jan 2023 16:18:00 +0100
Subject: [PATCH 222/381] C#: Implement extractor support for unsigned right
shift.
---
.../Semmle.Extraction.CSharp/Entities/Expression.cs | 2 +-
.../Entities/Expressions/Assignment.cs | 4 ++++
.../Entities/Expressions/Binary.cs | 1 +
.../Entities/Expressions/Factory.cs | 2 ++
.../Entities/UserOperator.cs | 12 +++++++-----
5 files changed, 15 insertions(+), 6 deletions(-)
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs
index 6e0380da693..3984e7c00cf 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expression.cs
@@ -240,7 +240,7 @@ namespace Semmle.Extraction.CSharp.Entities
var callType = GetCallType(Context, node);
if (callType == CallType.Dynamic)
{
- UserOperator.OperatorSymbol(method.Name, out var operatorName);
+ UserOperator.TryGetOperatorSymbol(method.Name, out var operatorName);
trapFile.dynamic_member_name(this, operatorName);
return;
}
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Assignment.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Assignment.cs
index 553d6d8349a..cbd7afbc9fa 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Assignment.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Assignment.cs
@@ -71,6 +71,8 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
return ExprKind.ASSIGN_LSHIFT;
case SyntaxKind.GreaterThanGreaterThanEqualsToken:
return ExprKind.ASSIGN_RSHIFT;
+ case SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken:
+ return ExprKind.ASSIGN_URSHIFT;
case SyntaxKind.QuestionQuestionEqualsToken:
return ExprKind.ASSIGN_COALESCE;
default:
@@ -141,6 +143,8 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
return ExprKind.REM;
case ExprKind.ASSIGN_RSHIFT:
return ExprKind.RSHIFT;
+ case ExprKind.ASSIGN_URSHIFT:
+ return ExprKind.URSHIFT;
case ExprKind.ASSIGN_SUB:
return ExprKind.SUB;
case ExprKind.ASSIGN_XOR:
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Binary.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Binary.cs
index 5153c856a25..45d43ac94c0 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Binary.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Binary.cs
@@ -50,6 +50,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
case SyntaxKind.BarBarToken: return ExprKind.LOG_OR;
case SyntaxKind.GreaterThanEqualsToken: return ExprKind.GE;
case SyntaxKind.GreaterThanGreaterThanToken: return ExprKind.RSHIFT;
+ case SyntaxKind.GreaterThanGreaterThanGreaterThanToken: return ExprKind.URSHIFT;
case SyntaxKind.LessThanLessThanToken: return ExprKind.LSHIFT;
case SyntaxKind.CaretToken: return ExprKind.BIT_XOR;
case SyntaxKind.QuestionQuestionToken: return ExprKind.NULL_COALESCING;
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Factory.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Factory.cs
index a92715c4e1c..57e9dd47ef3 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Factory.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/Expressions/Factory.cs
@@ -38,6 +38,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
case SyntaxKind.IsExpression:
case SyntaxKind.AsExpression:
case SyntaxKind.RightShiftExpression:
+ case SyntaxKind.UnsignedRightShiftExpression:
case SyntaxKind.LeftShiftExpression:
case SyntaxKind.ExclusiveOrExpression:
case SyntaxKind.CoalesceExpression:
@@ -76,6 +77,7 @@ namespace Semmle.Extraction.CSharp.Entities.Expressions
case SyntaxKind.ExclusiveOrAssignmentExpression:
case SyntaxKind.LeftShiftAssignmentExpression:
case SyntaxKind.RightShiftAssignmentExpression:
+ case SyntaxKind.UnsignedRightShiftAssignmentExpression:
case SyntaxKind.DivideAssignmentExpression:
case SyntaxKind.ModuloAssignmentExpression:
case SyntaxKind.CoalesceAssignmentExpression:
diff --git a/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs b/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs
index 536af5065ed..f478d991919 100644
--- a/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs
+++ b/csharp/extractor/Semmle.Extraction.CSharp/Entities/UserOperator.cs
@@ -61,8 +61,7 @@ namespace Semmle.Extraction.CSharp.Entities
containingType = Symbol.ContainingType;
if (containingType is not null)
{
- var containingNamedType = containingType as INamedTypeSymbol;
- return containingNamedType is null ||
+ return containingType is not INamedTypeSymbol containingNamedType ||
!containingNamedType.GetMembers(Symbol.Name).Contains(Symbol);
}
@@ -83,7 +82,7 @@ namespace Semmle.Extraction.CSharp.Entities
///
/// The method name.
/// The converted operator name.
- public static bool OperatorSymbol(string methodName, out string operatorName)
+ public static bool TryGetOperatorSymbol(string methodName, out string operatorName)
{
var success = true;
switch (methodName)
@@ -147,6 +146,9 @@ namespace Semmle.Extraction.CSharp.Entities
case "op_RightShift":
operatorName = ">>";
break;
+ case "op_UnsignedRightShift":
+ operatorName = ">>>";
+ break;
case "op_LeftShift":
operatorName = "<<";
break;
@@ -166,7 +168,7 @@ namespace Semmle.Extraction.CSharp.Entities
var match = Regex.Match(methodName, "^op_Checked(.*)$");
if (match.Success)
{
- OperatorSymbol("op_" + match.Groups[1], out var uncheckedName);
+ TryGetOperatorSymbol("op_" + match.Groups[1], out var uncheckedName);
operatorName = "checked " + uncheckedName;
break;
}
@@ -190,7 +192,7 @@ namespace Semmle.Extraction.CSharp.Entities
return OperatorSymbol(cx, method.ExplicitInterfaceImplementations.First());
var methodName = method.Name;
- if (!OperatorSymbol(methodName, out var result))
+ if (!TryGetOperatorSymbol(methodName, out var result))
cx.ModelError(method, $"Unhandled operator name in OperatorSymbol(): '{methodName}'");
return result;
}
From 9eb793377803810209ca2d80fb57f61a20e74606 Mon Sep 17 00:00:00 2001
From: Michael Nebel
Date: Fri, 6 Jan 2023 16:18:33 +0100
Subject: [PATCH 223/381] C#: Implement library support for unsigned right
shift.
---
.../ql/lib/semmle/code/csharp/exprs/Assignment.qll | 12 +++++++++++-
.../semmle/code/csharp/exprs/BitwiseOperation.qll | 12 +++++++++++-
2 files changed, 22 insertions(+), 2 deletions(-)
diff --git a/csharp/ql/lib/semmle/code/csharp/exprs/Assignment.qll b/csharp/ql/lib/semmle/code/csharp/exprs/Assignment.qll
index ce5022c5f89..14da6da266f 100644
--- a/csharp/ql/lib/semmle/code/csharp/exprs/Assignment.qll
+++ b/csharp/ql/lib/semmle/code/csharp/exprs/Assignment.qll
@@ -151,7 +151,8 @@ class AssignRemExpr extends AssignArithmeticOperation, @assign_rem_expr {
* operation (`AssignOrExpr`), a bitwise exclusive-or assignment
* operation (`AssignXorExpr`), a left-shift assignment
* operation (`AssignLeftShiftExpr`), or a right-shift assignment
- * operation (`AssignRightShiftExpr`).
+ * operation (`AssignRightShiftExpr`), or an unsigned right-shift assignment
+ * operation (`AssignUnsignedRightShiftExpr`).
*/
class AssignBitwiseOperation extends AssignOperation, @assign_bitwise_expr { }
@@ -206,6 +207,15 @@ class AssignRightShiftExpr extends AssignBitwiseOperation, @assign_rshift_expr {
/** DEPRECATED: Alias for AssignRightShiftExpr. */
deprecated class AssignRShiftExpr = AssignRightShiftExpr;
+/**
+ * An unsigned right-shift assignment operation, for example `x >>>= y`.
+ */
+class AssignUnsighedRightShiftExpr extends AssignBitwiseOperation, @assign_urshift_expr {
+ override string getOperator() { result = ">>>=" }
+
+ override string getAPrimaryQlClass() { result = "AssignUnsighedRightShiftExpr" }
+}
+
/**
* An event assignment. Either an event addition (`AddEventExpr`) or an event
* removal (`RemoveEventExpr`).
diff --git a/csharp/ql/lib/semmle/code/csharp/exprs/BitwiseOperation.qll b/csharp/ql/lib/semmle/code/csharp/exprs/BitwiseOperation.qll
index 23e02756ce2..d32485a51f8 100644
--- a/csharp/ql/lib/semmle/code/csharp/exprs/BitwiseOperation.qll
+++ b/csharp/ql/lib/semmle/code/csharp/exprs/BitwiseOperation.qll
@@ -31,7 +31,8 @@ class ComplementExpr extends UnaryBitwiseOperation, @bit_not_expr {
* A binary bitwise operation. Either a bitwise-and operation
* (`BitwiseAndExpr`), a bitwise-or operation (`BitwiseOrExpr`),
* a bitwise exclusive-or operation (`BitwiseXorExpr`), a left-shift
- * operation (`LeftShiftExpr`), or a right-shift operation (`RightShiftExpr`).
+ * operation (`LeftShiftExpr`), a right-shift operation (`RightShiftExpr`),
+ * or an unsigned right-shift operation (`UnsignedRightShiftExpr`).
*/
class BinaryBitwiseOperation extends BitwiseOperation, BinaryOperation, @bin_bit_op_expr {
override string getOperator() { none() }
@@ -61,6 +62,15 @@ class RightShiftExpr extends BinaryBitwiseOperation, @rshift_expr {
/** DEPRECATED: Alias for RightShiftExpr. */
deprecated class RShiftExpr = RightShiftExpr;
+/**
+ * An unsigned right-shift operation, for example `x >>> y`.
+ */
+class UnsignedRightShiftExpr extends BinaryBitwiseOperation, @urshift_expr {
+ override string getOperator() { result = ">>>" }
+
+ override string getAPrimaryQlClass() { result = "UnsignedRightShiftExpr" }
+}
+
/**
* A bitwise-and operation, for example `x & y`.
*/
From d06a877709ec03ea3750bdd4ab69a5db9a79353a Mon Sep 17 00:00:00 2001
From: Michael Nebel
Date: Fri, 6 Jan 2023 16:21:36 +0100
Subject: [PATCH 224/381] C#: Introduce test cases and expected result for
unsigned right shift.
---
.../test/library-tests/csharp11/Operators.cs | 15 +++++++++++++
.../library-tests/csharp11/operators.expected | 6 ++++++
.../test/library-tests/csharp11/operators.ql | 21 +++++++++++++++++++
3 files changed, 42 insertions(+)
create mode 100644 csharp/ql/test/library-tests/csharp11/Operators.cs
create mode 100644 csharp/ql/test/library-tests/csharp11/operators.expected
create mode 100644 csharp/ql/test/library-tests/csharp11/operators.ql
diff --git a/csharp/ql/test/library-tests/csharp11/Operators.cs b/csharp/ql/test/library-tests/csharp11/Operators.cs
new file mode 100644
index 00000000000..9208654629b
--- /dev/null
+++ b/csharp/ql/test/library-tests/csharp11/Operators.cs
@@ -0,0 +1,15 @@
+
+public class MyClass
+{
+ public void M1()
+ {
+ var x1 = 1;
+ var x2 = x1 >>> 2;
+
+ var y1 = -2;
+ var y2 = y1 >>> 3;
+
+ var z = -4;
+ z >>>= 5;
+ }
+}
\ No newline at end of file
diff --git a/csharp/ql/test/library-tests/csharp11/operators.expected b/csharp/ql/test/library-tests/csharp11/operators.expected
new file mode 100644
index 00000000000..3b700fc2f4c
--- /dev/null
+++ b/csharp/ql/test/library-tests/csharp11/operators.expected
@@ -0,0 +1,6 @@
+binarybitwise
+| Operators.cs:7:18:7:25 | ... >>> ... | Operators.cs:7:18:7:19 | access to local variable x1 | Operators.cs:7:25:7:25 | 2 | >>> | UnsignedRightShiftExpr |
+| Operators.cs:10:18:10:25 | ... >>> ... | Operators.cs:10:18:10:19 | access to local variable y1 | Operators.cs:10:25:10:25 | 3 | >>> | UnsignedRightShiftExpr |
+| Operators.cs:13:9:13:16 | ... >>> ... | Operators.cs:13:9:13:9 | access to local variable z | Operators.cs:13:16:13:16 | 5 | >>> | UnsignedRightShiftExpr |
+assignbitwise
+| Operators.cs:13:9:13:16 | ... >>>= ... | Operators.cs:13:9:13:9 | access to local variable z | Operators.cs:13:16:13:16 | 5 | >>>= | AssignUnsighedRightShiftExpr |
diff --git a/csharp/ql/test/library-tests/csharp11/operators.ql b/csharp/ql/test/library-tests/csharp11/operators.ql
new file mode 100644
index 00000000000..f70897e8da5
--- /dev/null
+++ b/csharp/ql/test/library-tests/csharp11/operators.ql
@@ -0,0 +1,21 @@
+import csharp
+
+query predicate binarybitwise(
+ BinaryBitwiseOperation op, Expr left, Expr right, string name, string qlclass
+) {
+ op.getFile().getStem() = "Operators" and
+ left = op.getLeftOperand() and
+ right = op.getRightOperand() and
+ name = op.getOperator() and
+ qlclass = op.getAPrimaryQlClass()
+}
+
+query predicate assignbitwise(
+ AssignBitwiseOperation op, Expr left, Expr right, string name, string qlclass
+) {
+ op.getFile().getStem() = "Operators" and
+ left = op.getLValue() and
+ right = op.getRValue() and
+ name = op.getOperator() and
+ qlclass = op.getAPrimaryQlClass()
+}
From 2568318460b3a8da3a4f2d35ff45dfd124354766 Mon Sep 17 00:00:00 2001
From: Michael Nebel
Date: Mon, 9 Jan 2023 10:39:02 +0100
Subject: [PATCH 225/381] C#: Sign analysis support for unsigned right shift.
---
.../csharp/dataflow/internal/rangeanalysis/RangeUtils.qll | 7 +++++++
.../internal/rangeanalysis/SignAnalysisSpecific.qll | 1 +
2 files changed, 8 insertions(+)
diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/RangeUtils.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/RangeUtils.qll
index 4b2894721b5..69054d88205 100644
--- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/RangeUtils.qll
+++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/RangeUtils.qll
@@ -404,6 +404,13 @@ module ExprNode {
override TRShiftOp getOp() { any() }
}
+ /** An unsigned right-shift operation. */
+ class UnsignedRightShiftExpr extends BinaryOperation {
+ override CS::UnsignedRightShiftExpr e;
+
+ override TURShiftOp getOp() { any() }
+ }
+
/** A conditional expression. */
class ConditionalExpr extends ExprNode {
override CS::ConditionalExpr e;
diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SignAnalysisSpecific.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SignAnalysisSpecific.qll
index ebff0c94e54..5b61ca54682 100644
--- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SignAnalysisSpecific.qll
+++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/SignAnalysisSpecific.qll
@@ -213,6 +213,7 @@ private module Impl {
not e.getExpr() instanceof BitwiseXorExpr and
not e.getExpr() instanceof LeftShiftExpr and
not e.getExpr() instanceof RightShiftExpr and
+ not e.getExpr() instanceof UnsignedRightShiftExpr and
not e.getExpr() instanceof ConditionalExpr and
not e.getExpr() instanceof RefExpr and
not e.getExpr() instanceof LocalVariableDeclAndInitExpr and
From 0f032c5be991b92782caf59d9c67e292ab30da66 Mon Sep 17 00:00:00 2001
From: Michael Nebel
Date: Mon, 9 Jan 2023 13:06:19 +0100
Subject: [PATCH 226/381] C#: Sign analysis testcase for unsigned right shift.
---
.../library-tests/csharp11/SignAnalysis.cs | 42 +++++++++++++++++++
.../csharp11/signAnalysis.expected | 7 ++++
.../library-tests/csharp11/signAnalysis.ql | 9 ++++
3 files changed, 58 insertions(+)
create mode 100644 csharp/ql/test/library-tests/csharp11/SignAnalysis.cs
create mode 100644 csharp/ql/test/library-tests/csharp11/signAnalysis.expected
create mode 100644 csharp/ql/test/library-tests/csharp11/signAnalysis.ql
diff --git a/csharp/ql/test/library-tests/csharp11/SignAnalysis.cs b/csharp/ql/test/library-tests/csharp11/SignAnalysis.cs
new file mode 100644
index 00000000000..09e7ceb9fdc
--- /dev/null
+++ b/csharp/ql/test/library-tests/csharp11/SignAnalysis.cs
@@ -0,0 +1,42 @@
+public class MySignAnalysis
+{
+
+ public void UnsignedRightShiftSign(int x, int y)
+ {
+ int z;
+ if (x == 0)
+ {
+ z = x >>> y;
+ }
+
+ if (y == 0)
+ {
+ z = x >>> y;
+ }
+
+ if (x > 0 && y == 0)
+ {
+ z = x >>> y;
+ }
+
+ if (x > 0 && y > 0)
+ {
+ z = x >>> y;
+ }
+
+ if (x > 0 && y < 0)
+ {
+ z = x >>> y;
+ }
+
+ if (x < 0 && y > 0)
+ {
+ z = x >>> y;
+ }
+
+ if (x < 0 && y < 0)
+ {
+ z = x >>> y;
+ }
+ }
+}
\ No newline at end of file
diff --git a/csharp/ql/test/library-tests/csharp11/signAnalysis.expected b/csharp/ql/test/library-tests/csharp11/signAnalysis.expected
new file mode 100644
index 00000000000..952719939ad
--- /dev/null
+++ b/csharp/ql/test/library-tests/csharp11/signAnalysis.expected
@@ -0,0 +1,7 @@
+| SignAnalysis.cs:9:17:9:23 | ... >>> ... | 0 |
+| SignAnalysis.cs:14:17:14:23 | ... >>> ... | + - 0 |
+| SignAnalysis.cs:19:17:19:23 | ... >>> ... | + |
+| SignAnalysis.cs:24:17:24:23 | ... >>> ... | + 0 |
+| SignAnalysis.cs:29:17:29:23 | ... >>> ... | + 0 |
+| SignAnalysis.cs:34:17:34:23 | ... >>> ... | + - |
+| SignAnalysis.cs:39:17:39:23 | ... >>> ... | + - |
diff --git a/csharp/ql/test/library-tests/csharp11/signAnalysis.ql b/csharp/ql/test/library-tests/csharp11/signAnalysis.ql
new file mode 100644
index 00000000000..2aeb57e29fb
--- /dev/null
+++ b/csharp/ql/test/library-tests/csharp11/signAnalysis.ql
@@ -0,0 +1,9 @@
+import csharp
+import semmle.code.csharp.dataflow.internal.rangeanalysis.SignAnalysisCommon as Common
+
+from ControlFlow::Nodes::ExprNode e, Expr expr
+where
+ e.getExpr() = expr and
+ expr.getFile().getStem() = "SignAnalysis" and
+ expr instanceof UnsignedRightShiftExpr
+select e, strictconcat(string s | s = Common::exprSign(e).toString() | s, " ")
From f74c7c28ae66c6d6f3d496989e10a2f75beda4cf Mon Sep 17 00:00:00 2001
From: Michael Nebel
Date: Mon, 9 Jan 2023 13:23:38 +0100
Subject: [PATCH 227/381] C#: Auto format test file and update expected test
output.
---
.../test/experimental/ir/ir/PrintAst.expected | 76 ++++++++---------
csharp/ql/test/experimental/ir/ir/assignop.cs | 22 ++---
.../test/experimental/ir/ir/raw_ir.expected | 82 +++++++++----------
3 files changed, 91 insertions(+), 89 deletions(-)
diff --git a/csharp/ql/test/experimental/ir/ir/PrintAst.expected b/csharp/ql/test/experimental/ir/ir/PrintAst.expected
index 480b63f4241..e15284672aa 100644
--- a/csharp/ql/test/experimental/ir/ir/PrintAst.expected
+++ b/csharp/ql/test/experimental/ir/ir/PrintAst.expected
@@ -118,59 +118,59 @@ array.cs:
# 20| 0: [IntLiteral] 1
assignop.cs:
# 3| [Class] AssignOp
-# 4| 5: [Method] Main
-# 4| -1: [TypeMention] Void
-# 4| 4: [BlockStmt] {...}
-# 5| 0: [LocalVariableDeclStmt] ... ...;
-# 5| 0: [LocalVariableDeclAndInitExpr] Int32 a = ...
-# 5| -1: [TypeMention] int
-# 5| 0: [LocalVariableAccess] access to local variable a
-# 5| 1: [IntLiteral] 1
-# 6| 1: [LocalVariableDeclStmt] ... ...;
-# 6| 0: [LocalVariableDeclAndInitExpr] Int32 c = ...
-# 6| -1: [TypeMention] int
-# 6| 0: [LocalVariableAccess] access to local variable c
-# 6| 1: [IntLiteral] 1
-# 8| 2: [ExprStmt] ...;
-# 8| 0: [AssignAddExpr] ... += ...
+# 5| 5: [Method] Main
+# 5| -1: [TypeMention] Void
+# 6| 4: [BlockStmt] {...}
+# 7| 0: [LocalVariableDeclStmt] ... ...;
+# 7| 0: [LocalVariableDeclAndInitExpr] Int32 a = ...
+# 7| -1: [TypeMention] int
+# 7| 0: [LocalVariableAccess] access to local variable a
+# 7| 1: [IntLiteral] 1
+# 8| 1: [LocalVariableDeclStmt] ... ...;
+# 8| 0: [LocalVariableDeclAndInitExpr] Int32 c = ...
+# 8| -1: [TypeMention] int
# 8| 0: [LocalVariableAccess] access to local variable c
-# 8| 1: [LocalVariableAccess] access to local variable a
-# 9| 3: [ExprStmt] ...;
-# 9| 0: [AssignSubExpr] ... -= ...
-# 9| 0: [LocalVariableAccess] access to local variable c
-# 9| 1: [LocalVariableAccess] access to local variable a
-# 10| 4: [ExprStmt] ...;
-# 10| 0: [AssignMulExpr] ... *= ...
+# 8| 1: [IntLiteral] 1
+# 10| 2: [ExprStmt] ...;
+# 10| 0: [AssignAddExpr] ... += ...
# 10| 0: [LocalVariableAccess] access to local variable c
# 10| 1: [LocalVariableAccess] access to local variable a
-# 11| 5: [ExprStmt] ...;
-# 11| 0: [AssignDivExpr] ... /= ...
+# 11| 3: [ExprStmt] ...;
+# 11| 0: [AssignSubExpr] ... -= ...
# 11| 0: [LocalVariableAccess] access to local variable c
# 11| 1: [LocalVariableAccess] access to local variable a
-# 12| 6: [ExprStmt] ...;
-# 12| 0: [AssignRemExpr] ... %= ...
+# 12| 4: [ExprStmt] ...;
+# 12| 0: [AssignMulExpr] ... *= ...
# 12| 0: [LocalVariableAccess] access to local variable c
# 12| 1: [LocalVariableAccess] access to local variable a
-# 13| 7: [ExprStmt] ...;
-# 13| 0: [AssignLeftShiftExpr] ... <<= ...
+# 13| 5: [ExprStmt] ...;
+# 13| 0: [AssignDivExpr] ... /= ...
# 13| 0: [LocalVariableAccess] access to local variable c
-# 13| 1: [IntLiteral] 2
-# 14| 8: [ExprStmt] ...;
-# 14| 0: [AssignRightShiftExpr] ... >>= ...
+# 13| 1: [LocalVariableAccess] access to local variable a
+# 14| 6: [ExprStmt] ...;
+# 14| 0: [AssignRemExpr] ... %= ...
# 14| 0: [LocalVariableAccess] access to local variable c
-# 14| 1: [IntLiteral] 2
-# 15| 9: [ExprStmt] ...;
-# 15| 0: [AssignAndExpr] ... &= ...
+# 14| 1: [LocalVariableAccess] access to local variable a
+# 15| 7: [ExprStmt] ...;
+# 15| 0: [AssignLeftShiftExpr] ... <<= ...
# 15| 0: [LocalVariableAccess] access to local variable c
# 15| 1: [IntLiteral] 2
-# 16| 10: [ExprStmt] ...;
-# 16| 0: [AssignXorExpr] ... ^= ...
+# 16| 8: [ExprStmt] ...;
+# 16| 0: [AssignRightShiftExpr] ... >>= ...
# 16| 0: [LocalVariableAccess] access to local variable c
# 16| 1: [IntLiteral] 2
-# 17| 11: [ExprStmt] ...;
-# 17| 0: [AssignOrExpr] ... |= ...
+# 17| 9: [ExprStmt] ...;
+# 17| 0: [AssignAndExpr] ... &= ...
# 17| 0: [LocalVariableAccess] access to local variable c
# 17| 1: [IntLiteral] 2
+# 18| 10: [ExprStmt] ...;
+# 18| 0: [AssignXorExpr] ... ^= ...
+# 18| 0: [LocalVariableAccess] access to local variable c
+# 18| 1: [IntLiteral] 2
+# 19| 11: [ExprStmt] ...;
+# 19| 0: [AssignOrExpr] ... |= ...
+# 19| 0: [LocalVariableAccess] access to local variable c
+# 19| 1: [IntLiteral] 2
casts.cs:
# 1| [Class] Casts_A
# 5| [Class] Casts_B
diff --git a/csharp/ql/test/experimental/ir/ir/assignop.cs b/csharp/ql/test/experimental/ir/ir/assignop.cs
index f5c2a6fa19d..d672a6d5022 100644
--- a/csharp/ql/test/experimental/ir/ir/assignop.cs
+++ b/csharp/ql/test/experimental/ir/ir/assignop.cs
@@ -1,19 +1,21 @@
using System;
-class AssignOp {
- static void Main() {
+class AssignOp
+{
+ static void Main()
+ {
int a = 1;
int c = 1;
-
- c += a;
+
+ c += a;
c -= a;
- c *= a;
+ c *= a;
c /= a;
- c %= a;
- c <<= 2;
- c >>= 2;
- c &= 2;
- c ^= 2;
+ c %= a;
+ c <<= 2;
+ c >>= 2;
+ c &= 2;
+ c ^= 2;
c |= 2;
}
}
diff --git a/csharp/ql/test/experimental/ir/ir/raw_ir.expected b/csharp/ql/test/experimental/ir/ir/raw_ir.expected
index bf639694da5..39b8d6323ff 100644
--- a/csharp/ql/test/experimental/ir/ir/raw_ir.expected
+++ b/csharp/ql/test/experimental/ir/ir/raw_ir.expected
@@ -145,74 +145,74 @@ array.cs:
# 13| v13_6(Void) = ExitFunction :
assignop.cs:
-# 4| System.Void AssignOp.Main()
-# 4| Block 0
-# 4| v4_1(Void) = EnterFunction :
-# 4| mu4_2() = AliasedDefinition :
-# 5| r5_1(glval) = VariableAddress[a] :
-# 5| r5_2(Int32) = Constant[1] :
-# 5| mu5_3(Int32) = Store[a] : &:r5_1, r5_2
-# 6| r6_1(glval) = VariableAddress[c] :
-# 6| r6_2(Int32) = Constant[1] :
-# 6| mu6_3(Int32) = Store[c] : &:r6_1, r6_2
-# 8| r8_1(glval) = VariableAddress[a] :
-# 8| r8_2(Int32) = Load[a] : &:r8_1, ~m?
-# 8| r8_3(glval) = VariableAddress[c] :
-# 8| r8_4(Int32) = Load[c] : &:r8_3, ~m?
-# 8| r8_5(Int32) = Add : r8_4, r8_2
-# 8| mu8_6(Int32) = Store[c] : &:r8_3, r8_5
-# 9| r9_1(glval) = VariableAddress[a] :
-# 9| r9_2(Int32) = Load[a] : &:r9_1, ~m?
-# 9| r9_3(glval) = VariableAddress[c] :
-# 9| r9_4(Int32) = Load[c] : &:r9_3, ~m?
-# 9| r9_5(Int32) = Sub : r9_4, r9_2
-# 9| mu9_6(Int32) = Store[c] : &:r9_3, r9_5
+# 5| System.Void AssignOp.Main()
+# 5| Block 0
+# 5| v5_1(Void) = EnterFunction :
+# 5| mu5_2() = AliasedDefinition :
+# 7| r7_1(glval) = VariableAddress[a] :
+# 7| r7_2(Int32) = Constant[1] :
+# 7| mu7_3(Int32) = Store[a] : &:r7_1, r7_2
+# 8| r8_1(glval) = VariableAddress[c] :
+# 8| r8_2(Int32) = Constant[1] :
+# 8| mu8_3(Int32) = Store[c] : &:r8_1, r8_2
# 10| r10_1(glval) = VariableAddress[a] :
# 10| r10_2(Int32) = Load[a] : &:r10_1, ~m?
# 10| r10_3(glval) = VariableAddress[c] :
# 10| r10_4(Int32) = Load[c] : &:r10_3, ~m?
-# 10| r10_5(Int32) = Mul : r10_4, r10_2
+# 10| r10_5(Int32) = Add : r10_4, r10_2
# 10| mu10_6(Int32) = Store[c] : &:r10_3, r10_5
# 11| r11_1(glval) = VariableAddress[a] :
# 11| r11_2(Int32) = Load[a] : &:r11_1, ~m?
# 11| r11_3(glval) = VariableAddress[c] :
# 11| r11_4(Int32) = Load[c] : &:r11_3, ~m?
-# 11| r11_5(Int32) = Div : r11_4, r11_2
+# 11| r11_5(Int32) = Sub : r11_4, r11_2
# 11| mu11_6(Int32) = Store[c] : &:r11_3, r11_5
# 12| r12_1(glval) = VariableAddress[a] :
# 12| r12_2(Int32) = Load[a] : &:r12_1, ~m?
# 12| r12_3(glval) = VariableAddress[c] :
# 12| r12_4(Int32) = Load[c] : &:r12_3, ~m?
-# 12| r12_5(Int32) = Rem : r12_4, r12_2
+# 12| r12_5(Int32) = Mul : r12_4, r12_2
# 12| mu12_6(Int32) = Store[c] : &:r12_3, r12_5
-# 13| r13_1(Int32) = Constant[2] :
-# 13| r13_2(glval) = VariableAddress[c] :
-# 13| r13_3(Int32) = Load[c] : &:r13_2, ~m?
-# 13| r13_4(Int32) = ShiftLeft : r13_3, r13_1
-# 13| mu13_5(Int32) = Store[c] : &:r13_2, r13_4
-# 14| r14_1(Int32) = Constant[2] :
-# 14| r14_2(glval) = VariableAddress[c] :
-# 14| r14_3(Int32) = Load[c] : &:r14_2, ~m?
-# 14| r14_4(Int32) = ShiftRight : r14_3, r14_1
-# 14| mu14_5(Int32) = Store[c] : &:r14_2, r14_4
+# 13| r13_1(glval) = VariableAddress[a] :
+# 13| r13_2(Int32) = Load[a] : &:r13_1, ~m?
+# 13| r13_3(glval) = VariableAddress[c] :
+# 13| r13_4(Int32) = Load[c] : &:r13_3, ~m?
+# 13| r13_5(Int32) = Div : r13_4, r13_2
+# 13| mu13_6(Int32) = Store[c] : &:r13_3, r13_5
+# 14| r14_1(glval) = VariableAddress[a] :
+# 14| r14_2(Int32) = Load[a] : &:r14_1, ~m?
+# 14| r14_3(glval) = VariableAddress[c] :
+# 14| r14_4(Int32) = Load[c] : &:r14_3, ~m?
+# 14| r14_5(Int32) = Rem : r14_4, r14_2
+# 14| mu14_6(Int32) = Store[c] : &:r14_3, r14_5
# 15| r15_1(Int32) = Constant[2] :
# 15| r15_2(glval) = VariableAddress[c] :
# 15| r15_3(Int32) = Load[c] : &:r15_2, ~m?
-# 15| r15_4(Int32) = BitAnd : r15_3, r15_1
+# 15| r15_4(Int32) = ShiftLeft : r15_3, r15_1
# 15| mu15_5(Int32) = Store[c] : &:r15_2, r15_4
# 16| r16_1(Int32) = Constant[2] :
# 16| r16_2(glval) = VariableAddress[c] :
# 16| r16_3(Int32) = Load[c] : &:r16_2, ~m?
-# 16| r16_4(Int32) = BitXor : r16_3, r16_1
+# 16| r16_4(Int32) = ShiftRight : r16_3, r16_1
# 16| mu16_5(Int32) = Store[c] : &:r16_2, r16_4
# 17| r17_1(Int32) = Constant[2] :
# 17| r17_2(glval) = VariableAddress[c] :
# 17| r17_3(Int32) = Load[c] : &:r17_2, ~m?
-# 17| r17_4(Int32) = BitOr : r17_3, r17_1
+# 17| r17_4(Int32) = BitAnd : r17_3, r17_1
# 17| mu17_5(Int32) = Store[c] : &:r17_2, r17_4
-# 4| v4_3(Void) = ReturnVoid :
-# 4| v4_4(Void) = AliasedUse : ~m?
-# 4| v4_5(Void) = ExitFunction :
+# 18| r18_1(Int32) = Constant[2] :
+# 18| r18_2(glval) = VariableAddress[c] :
+# 18| r18_3(Int32) = Load[c] : &:r18_2, ~m?
+# 18| r18_4(Int32) = BitXor : r18_3, r18_1
+# 18| mu18_5(Int32) = Store[c] : &:r18_2, r18_4
+# 19| r19_1(Int32) = Constant[2] :
+# 19| r19_2(glval) = VariableAddress[c] :
+# 19| r19_3(Int32) = Load[c] : &:r19_2, ~m?
+# 19| r19_4(Int32) = BitOr : r19_3, r19_1
+# 19| mu19_5(Int32) = Store[c] : &:r19_2, r19_4
+# 5| v5_3(Void) = ReturnVoid :
+# 5| v5_4(Void) = AliasedUse : ~m?
+# 5| v5_5(Void) = ExitFunction :
casts.cs:
# 11| System.Void Casts.Main()
From 5bb8f8ed5cdafd9bcbb3e3e744a793c30e4fb168 Mon Sep 17 00:00:00 2001
From: Michael Nebel
Date: Mon, 9 Jan 2023 15:06:32 +0100
Subject: [PATCH 228/381] C#: Support for unsigned shift right in the
experimental intermediate representation.
---
.../ql/src/experimental/ir/implementation/Opcode.qll | 10 ++++++++++
.../ir/implementation/raw/Instruction.qll | 11 +++++++++++
.../ir/implementation/raw/internal/TranslatedExpr.qll | 7 ++++++-
.../ir/implementation/unaliased_ssa/Instruction.qll | 11 +++++++++++
.../experimental/ir/rangeanalysis/SignAnalysis.qll | 2 ++
5 files changed, 40 insertions(+), 1 deletion(-)
diff --git a/csharp/ql/src/experimental/ir/implementation/Opcode.qll b/csharp/ql/src/experimental/ir/implementation/Opcode.qll
index c4134d240ab..b4def7fe4ae 100644
--- a/csharp/ql/src/experimental/ir/implementation/Opcode.qll
+++ b/csharp/ql/src/experimental/ir/implementation/Opcode.qll
@@ -30,6 +30,7 @@ private newtype TOpcode =
TNegate() or
TShiftLeft() or
TShiftRight() or
+ TUnsignedShiftRight() or
TBitAnd() or
TBitOr() or
TBitXor() or
@@ -652,6 +653,15 @@ module Opcode {
final override string toString() { result = "ShiftRight" }
}
+ /**
+ * The `Opcode` for a `UnsignedShiftRightInstruction`.
+ *
+ * See the `UnsignedShiftRightInstruction` documentation for more details.
+ */
+ class UnsignedShiftRight extends BinaryBitwiseOpcode, TUnsignedShiftRight {
+ final override string toString() { result = "UnsignedShiftRight" }
+ }
+
/**
* The `Opcode` for a `BitAndInstruction`.
*
diff --git a/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll b/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll
index 7afe954023b..0aa7c552638 100644
--- a/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll
+++ b/csharp/ql/src/experimental/ir/implementation/raw/Instruction.qll
@@ -1204,6 +1204,17 @@ class ShiftRightInstruction extends BinaryBitwiseInstruction {
ShiftRightInstruction() { this.getOpcode() instanceof Opcode::ShiftRight }
}
+/**
+ * An instruction that shifts its left operand to the right by the number of bits specified by its
+ * right operand.
+ *
+ * Both operands must have an integer type. The result has the same type as the left operand.
+ * The leftmost bits are zero-filled.
+ */
+class UnsignedShiftRightInstruction extends BinaryBitwiseInstruction {
+ UnsignedShiftRightInstruction() { this.getOpcode() instanceof Opcode::UnsignedShiftRight }
+}
+
/**
* An instruction that performs a binary arithmetic operation involving at least one pointer
* operand.
diff --git a/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedExpr.qll b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedExpr.qll
index 56c2621afb9..06391c010b4 100644
--- a/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedExpr.qll
+++ b/csharp/ql/src/experimental/ir/implementation/raw/internal/TranslatedExpr.qll
@@ -1095,6 +1095,8 @@ private Opcode binaryBitwiseOpcode(BinaryBitwiseOperation expr) {
or
expr instanceof RightShiftExpr and result instanceof Opcode::ShiftRight
or
+ expr instanceof UnsignedRightShiftExpr and result instanceof Opcode::UnsignedShiftRight
+ or
expr instanceof BitwiseAndExpr and result instanceof Opcode::BitAnd
or
expr instanceof BitwiseOrExpr and result instanceof Opcode::BitOr
@@ -1378,7 +1380,8 @@ class TranslatedAssignOperation extends TranslatedAssignment {
private Type getConvertedLeftOperandType() {
if
expr instanceof AssignLeftShiftExpr or
- expr instanceof AssignRightShiftExpr
+ expr instanceof AssignRightShiftExpr or
+ expr instanceof AssignUnsighedRightShiftExpr
then result = this.getLeftOperand().getResultType()
else
// The right operand has already been converted to the type of the op.
@@ -1419,6 +1422,8 @@ class TranslatedAssignOperation extends TranslatedAssignment {
expr instanceof AssignLeftShiftExpr and result instanceof Opcode::ShiftLeft
or
expr instanceof AssignRightShiftExpr and result instanceof Opcode::ShiftRight
+ or
+ expr instanceof AssignUnsighedRightShiftExpr and result instanceof Opcode::UnsignedShiftRight
}
override predicate hasInstruction(Opcode opcode, InstructionTag tag, CSharpType resultType) {
diff --git a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll
index 7afe954023b..0aa7c552638 100644
--- a/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll
+++ b/csharp/ql/src/experimental/ir/implementation/unaliased_ssa/Instruction.qll
@@ -1204,6 +1204,17 @@ class ShiftRightInstruction extends BinaryBitwiseInstruction {
ShiftRightInstruction() { this.getOpcode() instanceof Opcode::ShiftRight }
}
+/**
+ * An instruction that shifts its left operand to the right by the number of bits specified by its
+ * right operand.
+ *
+ * Both operands must have an integer type. The result has the same type as the left operand.
+ * The leftmost bits are zero-filled.
+ */
+class UnsignedShiftRightInstruction extends BinaryBitwiseInstruction {
+ UnsignedShiftRightInstruction() { this.getOpcode() instanceof Opcode::UnsignedShiftRight }
+}
+
/**
* An instruction that performs a binary arithmetic operation involving at least one pointer
* operand.
diff --git a/csharp/ql/src/experimental/ir/rangeanalysis/SignAnalysis.qll b/csharp/ql/src/experimental/ir/rangeanalysis/SignAnalysis.qll
index 44548e0517a..b74f7c90db5 100644
--- a/csharp/ql/src/experimental/ir/rangeanalysis/SignAnalysis.qll
+++ b/csharp/ql/src/experimental/ir/rangeanalysis/SignAnalysis.qll
@@ -522,6 +522,8 @@ module SignAnalysisCached {
i instanceof ShiftRightInstruction and
not i.getResultType().(IntegralType) instanceof SignedIntegralType and
result = s1.urshift(s2)
+ or
+ i instanceof UnsignedShiftRightInstruction and result = s1.urshift(s2)
)
or
// use hasGuard here?
From d92b226041bbc70157f1d1aebfd183b41080757a Mon Sep 17 00:00:00 2001
From: Michael Nebel
Date: Mon, 9 Jan 2023 15:07:18 +0100
Subject: [PATCH 229/381] C#: Add test example for unsigned right shift
assignment in intermediate representation.
---
csharp/ql/test/experimental/ir/ir/PrintAst.expected | 4 ++++
csharp/ql/test/experimental/ir/ir/assignop.cs | 1 +
csharp/ql/test/experimental/ir/ir/raw_ir.expected | 5 +++++
3 files changed, 10 insertions(+)
diff --git a/csharp/ql/test/experimental/ir/ir/PrintAst.expected b/csharp/ql/test/experimental/ir/ir/PrintAst.expected
index e15284672aa..cc96a82bbc1 100644
--- a/csharp/ql/test/experimental/ir/ir/PrintAst.expected
+++ b/csharp/ql/test/experimental/ir/ir/PrintAst.expected
@@ -171,6 +171,10 @@ assignop.cs:
# 19| 0: [AssignOrExpr] ... |= ...
# 19| 0: [LocalVariableAccess] access to local variable c
# 19| 1: [IntLiteral] 2
+# 20| 12: [ExprStmt] ...;
+# 20| 0: [AssignUnsighedRightShiftExpr] ... >>>= ...
+# 20| 0: [LocalVariableAccess] access to local variable c
+# 20| 1: [IntLiteral] 2
casts.cs:
# 1| [Class] Casts_A
# 5| [Class] Casts_B
diff --git a/csharp/ql/test/experimental/ir/ir/assignop.cs b/csharp/ql/test/experimental/ir/ir/assignop.cs
index d672a6d5022..21fdfccbcf9 100644
--- a/csharp/ql/test/experimental/ir/ir/assignop.cs
+++ b/csharp/ql/test/experimental/ir/ir/assignop.cs
@@ -17,5 +17,6 @@ class AssignOp
c &= 2;
c ^= 2;
c |= 2;
+ c >>>= 2;
}
}
diff --git a/csharp/ql/test/experimental/ir/ir/raw_ir.expected b/csharp/ql/test/experimental/ir/ir/raw_ir.expected
index 39b8d6323ff..2461e6602b9 100644
--- a/csharp/ql/test/experimental/ir/ir/raw_ir.expected
+++ b/csharp/ql/test/experimental/ir/ir/raw_ir.expected
@@ -210,6 +210,11 @@ assignop.cs:
# 19| r19_3(Int32) = Load[c] : &:r19_2, ~m?
# 19| r19_4(Int32) = BitOr : r19_3, r19_1
# 19| mu19_5(Int32) = Store[c] : &:r19_2, r19_4
+# 20| r20_1(Int32) = Constant[2] :
+# 20| r20_2(glval) = VariableAddress[c] :
+# 20| r20_3(Int32) = Load[c] : &:r20_2, ~m?
+# 20| r20_4(Int32) = UnsignedShiftRight : r20_3, r20_1
+# 20| mu20_5(Int32) = Store[c] : &:r20_2, r20_4
# 5| v5_3(Void) = ReturnVoid :
# 5| v5_4(Void) = AliasedUse : ~m?
# 5| v5_5(Void) = ExitFunction :
From f48eda829ff67da79ec651d03c071c5d5caf5af1 Mon Sep 17 00:00:00 2001
From: Michael Nebel
Date: Mon, 9 Jan 2023 15:31:01 +0100
Subject: [PATCH 230/381] C#: Rename some of the TBinarySignOperation
constructors.
---
.../dataflow/internal/rangeanalysis/RangeUtils.qll | 6 +++---
.../csharp/dataflow/internal/rangeanalysis/Sign.qll | 12 ++++++------
2 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/RangeUtils.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/RangeUtils.qll
index 69054d88205..fe4505b6e2e 100644
--- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/RangeUtils.qll
+++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/RangeUtils.qll
@@ -394,21 +394,21 @@ module ExprNode {
class LeftShiftExpr extends BinaryOperation {
override CS::LeftShiftExpr e;
- override TLShiftOp getOp() { any() }
+ override TLeftShiftOp getOp() { any() }
}
/** A right-shift operation. */
class RightShiftExpr extends BinaryOperation {
override CS::RightShiftExpr e;
- override TRShiftOp getOp() { any() }
+ override TRightShiftOp getOp() { any() }
}
/** An unsigned right-shift operation. */
class UnsignedRightShiftExpr extends BinaryOperation {
override CS::UnsignedRightShiftExpr e;
- override TURShiftOp getOp() { any() }
+ override TUnsignedRightShiftOp getOp() { any() }
}
/** A conditional expression. */
diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/Sign.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/Sign.qll
index b2058a27114..649b4216996 100644
--- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/Sign.qll
+++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/rangeanalysis/Sign.qll
@@ -18,9 +18,9 @@ newtype TBinarySignOperation =
TBitAndOp() or
TBitOrOp() or
TBitXorOp() or
- TLShiftOp() or
- TRShiftOp() or
- TURShiftOp()
+ TLeftShiftOp() or
+ TRightShiftOp() or
+ TUnsignedRightShiftOp()
/** Class representing expression signs (+, -, 0). */
class Sign extends TSign {
@@ -271,10 +271,10 @@ class Sign extends TSign {
or
op = TBitXorOp() and result = bitxor(s)
or
- op = TLShiftOp() and result = lshift(s)
+ op = TLeftShiftOp() and result = lshift(s)
or
- op = TRShiftOp() and result = rshift(s)
+ op = TRightShiftOp() and result = rshift(s)
or
- op = TURShiftOp() and result = urshift(s)
+ op = TUnsignedRightShiftOp() and result = urshift(s)
}
}
From 148dc6de5a604685e284c10ba588dc9409406970 Mon Sep 17 00:00:00 2001
From: Michael Nebel
Date: Mon, 9 Jan 2023 15:36:03 +0100
Subject: [PATCH 231/381] C#: Rename shift operator classes.
---
csharp/ql/lib/semmle/code/csharp/Callable.qll | 22 ++++++++++++-------
1 file changed, 14 insertions(+), 8 deletions(-)
diff --git a/csharp/ql/lib/semmle/code/csharp/Callable.qll b/csharp/ql/lib/semmle/code/csharp/Callable.qll
index bc8e1294adb..3f19198085e 100644
--- a/csharp/ql/lib/semmle/code/csharp/Callable.qll
+++ b/csharp/ql/lib/semmle/code/csharp/Callable.qll
@@ -636,8 +636,8 @@ class TrueOperator extends UnaryOperator {
* (`SubOperator`), a multiplication operator (`MulOperator`), a division
* operator (`DivOperator`), a remainder operator (`RemOperator`), an and
* operator (`AndOperator`), an or operator (`OrOperator`), an xor
- * operator (`XorOperator`), a left shift operator (`LShiftOperator`),
- * a right shift operator (`RShiftOperator`), an equals operator (`EQOperator`),
+ * operator (`XorOperator`), a left shift operator (`LeftShiftOperator`),
+ * a right shift operator (`RightShiftOperator`), an equals operator (`EQOperator`),
* a not equals operator (`NEOperator`), a lesser than operator (`LTOperator`),
* a greater than operator (`GTOperator`), a less than or equals operator
* (`LEOperator`), or a greater than or equals operator (`GEOperator`).
@@ -791,14 +791,17 @@ class XorOperator extends BinaryOperator {
* }
* ```
*/
-class LShiftOperator extends BinaryOperator {
- LShiftOperator() { this.getName() = "<<" }
+class LeftShiftOperator extends BinaryOperator {
+ LeftShiftOperator() { this.getName() = "<<" }
override string getFunctionName() { result = "op_LeftShift" }
- override string getAPrimaryQlClass() { result = "LShiftOperator" }
+ override string getAPrimaryQlClass() { result = "LeftShiftOperator" }
}
+/** DEPRECATED: Alias for LeftShiftOperator. */
+deprecated class LShiftOperator = LeftShiftOperator;
+
/**
* A user-defined right shift operator (`>>`), for example
*
@@ -808,14 +811,17 @@ class LShiftOperator extends BinaryOperator {
* }
* ```
*/
-class RShiftOperator extends BinaryOperator {
- RShiftOperator() { this.getName() = ">>" }
+class RightShiftOperator extends BinaryOperator {
+ RightShiftOperator() { this.getName() = ">>" }
override string getFunctionName() { result = "op_RightShift" }
- override string getAPrimaryQlClass() { result = "RShiftOperator" }
+ override string getAPrimaryQlClass() { result = "RightShiftOperator" }
}
+/** DEPRECATED: Alias for RightShiftOperator. */
+deprecated class RShiftOperator = RightShiftOperator;
+
/**
* A user-defined equals operator (`==`), for example
*
From 30738103f05ce5e5201787e0ee4bdd4c382e90ad Mon Sep 17 00:00:00 2001
From: Michael Nebel
Date: Mon, 9 Jan 2023 15:47:32 +0100
Subject: [PATCH 232/381] C#: Add unsigned right shift operator class.
---
csharp/ql/lib/semmle/code/csharp/Callable.qll | 20 ++++++++++++++++++-
1 file changed, 19 insertions(+), 1 deletion(-)
diff --git a/csharp/ql/lib/semmle/code/csharp/Callable.qll b/csharp/ql/lib/semmle/code/csharp/Callable.qll
index 3f19198085e..ea88f814bce 100644
--- a/csharp/ql/lib/semmle/code/csharp/Callable.qll
+++ b/csharp/ql/lib/semmle/code/csharp/Callable.qll
@@ -637,7 +637,8 @@ class TrueOperator extends UnaryOperator {
* operator (`DivOperator`), a remainder operator (`RemOperator`), an and
* operator (`AndOperator`), an or operator (`OrOperator`), an xor
* operator (`XorOperator`), a left shift operator (`LeftShiftOperator`),
- * a right shift operator (`RightShiftOperator`), an equals operator (`EQOperator`),
+ * a right shift operator (`RightShiftOperator`), an unsigned right shift
+ * operator(`UnsignedRightShiftOperator`), an equals operator (`EQOperator`),
* a not equals operator (`NEOperator`), a lesser than operator (`LTOperator`),
* a greater than operator (`GTOperator`), a less than or equals operator
* (`LEOperator`), or a greater than or equals operator (`GEOperator`).
@@ -822,6 +823,23 @@ class RightShiftOperator extends BinaryOperator {
/** DEPRECATED: Alias for RightShiftOperator. */
deprecated class RShiftOperator = RightShiftOperator;
+/**
+ * A user-defined unsigned right shift operator (`>>>`), for example
+ *
+ * ```csharp
+ * public static Widget operator >>>(Widget lhs, Widget rhs) {
+ * ...
+ * }
+ * ```
+ */
+class UnsignedRightShiftOperator extends BinaryOperator {
+ UnsignedRightShiftOperator() { this.getName() = ">>>" }
+
+ override string getFunctionName() { result = "op_UnsignedRightShift" }
+
+ override string getAPrimaryQlClass() { result = "UnsignedRightShiftOperator" }
+}
+
/**
* A user-defined equals operator (`==`), for example
*
From 49a87e152a2936c7f0f3fd52ecbc0174f1861577 Mon Sep 17 00:00:00 2001
From: Michael Nebel
Date: Mon, 9 Jan 2023 15:48:07 +0100
Subject: [PATCH 233/381] C#: Add unsigned right shift operator test case.
---
csharp/ql/test/library-tests/csharp11/Operators.cs | 5 +++++
csharp/ql/test/library-tests/csharp11/operators.expected | 2 ++
csharp/ql/test/library-tests/csharp11/operators.ql | 6 ++++++
3 files changed, 13 insertions(+)
diff --git a/csharp/ql/test/library-tests/csharp11/Operators.cs b/csharp/ql/test/library-tests/csharp11/Operators.cs
index 9208654629b..d5c4f8be091 100644
--- a/csharp/ql/test/library-tests/csharp11/Operators.cs
+++ b/csharp/ql/test/library-tests/csharp11/Operators.cs
@@ -12,4 +12,9 @@ public class MyClass
var z = -4;
z >>>= 5;
}
+}
+
+public class MyOperatorClass
+{
+ public static MyOperatorClass operator >>>(MyOperatorClass a, MyOperatorClass b) { return null; }
}
\ No newline at end of file
diff --git a/csharp/ql/test/library-tests/csharp11/operators.expected b/csharp/ql/test/library-tests/csharp11/operators.expected
index 3b700fc2f4c..2c7bda6800d 100644
--- a/csharp/ql/test/library-tests/csharp11/operators.expected
+++ b/csharp/ql/test/library-tests/csharp11/operators.expected
@@ -4,3 +4,5 @@ binarybitwise
| Operators.cs:13:9:13:16 | ... >>> ... | Operators.cs:13:9:13:9 | access to local variable z | Operators.cs:13:16:13:16 | 5 | >>> | UnsignedRightShiftExpr |
assignbitwise
| Operators.cs:13:9:13:16 | ... >>>= ... | Operators.cs:13:9:13:9 | access to local variable z | Operators.cs:13:16:13:16 | 5 | >>>= | AssignUnsighedRightShiftExpr |
+userdefined
+| Operators.cs:19:44:19:46 | >>> | op_UnsignedRightShift | UnsignedRightShiftOperator |
diff --git a/csharp/ql/test/library-tests/csharp11/operators.ql b/csharp/ql/test/library-tests/csharp11/operators.ql
index f70897e8da5..607efac0c26 100644
--- a/csharp/ql/test/library-tests/csharp11/operators.ql
+++ b/csharp/ql/test/library-tests/csharp11/operators.ql
@@ -19,3 +19,9 @@ query predicate assignbitwise(
name = op.getOperator() and
qlclass = op.getAPrimaryQlClass()
}
+
+query predicate userdefined(Operator op, string fname, string qlclass) {
+ op.getFile().getStem() = "Operators" and
+ fname = op.getFunctionName() and
+ qlclass = op.getAPrimaryQlClass()
+}
From 5c466f331912ac195a844e4fa8957083d9b4ba2c Mon Sep 17 00:00:00 2001
From: Michael Nebel
Date: Tue, 10 Jan 2023 09:42:20 +0100
Subject: [PATCH 234/381] Java: Sync files and update other relavant files
related to the new naming of shift.
---
java/ql/lib/semmle/code/java/Expr.qll | 48 +++++++++++++------
.../code/java/dataflow/ModulusAnalysis.qll | 2 +-
.../code/java/dataflow/RangeAnalysis.qll | 12 ++---
.../rangeanalysis/ModulusAnalysisSpecific.qll | 8 ++--
.../dataflow/internal/rangeanalysis/Sign.qll | 12 ++---
.../rangeanalysis/SignAnalysisSpecific.qll | 24 +++++-----
.../Arithmetic/LShiftLargerThanTypeWidth.ql | 2 +-
.../WhitespaceContradictsPrecedence.ql | 6 +--
.../Comparison/UselessComparisonTest.ql | 4 +-
.../Security/CWE/CWE-190/ArithmeticCommon.qll | 6 +--
.../CWE/CWE-681/NumericCastCommon.qll | 8 ++--
.../library-tests/exprs/PrintAst.expected | 12 ++---
.../kotlin/library-tests/exprs/exprs.expected | 12 ++---
.../library-tests/constants/PrintAst.expected | 8 ++--
14 files changed, 91 insertions(+), 73 deletions(-)
diff --git a/java/ql/lib/semmle/code/java/Expr.qll b/java/ql/lib/semmle/code/java/Expr.qll
index a10da9ecc9f..78eda1dba8d 100644
--- a/java/ql/lib/semmle/code/java/Expr.qll
+++ b/java/ql/lib/semmle/code/java/Expr.qll
@@ -366,11 +366,11 @@ class CompileTimeConstantExpr extends Expr {
or
b instanceof SubExpr and result = v1 - v2
or
- b instanceof LShiftExpr and result = v1.bitShiftLeft(v2)
+ b instanceof LeftShiftExpr and result = v1.bitShiftLeft(v2)
or
- b instanceof RShiftExpr and result = v1.bitShiftRightSigned(v2)
+ b instanceof RightShiftExpr and result = v1.bitShiftRightSigned(v2)
or
- b instanceof URShiftExpr and result = v1.bitShiftRight(v2)
+ b instanceof UnsignedRightShiftExpr and result = v1.bitShiftRight(v2)
or
b instanceof AndBitwiseExpr and result = v1.bitAnd(v2)
or
@@ -623,26 +623,35 @@ class AssignXorExpr extends AssignOp, @assignxorexpr {
}
/** A compound assignment expression using the `<<=` operator. */
-class AssignLShiftExpr extends AssignOp, @assignlshiftexpr {
+class AssignLeftShiftExpr extends AssignOp, @assignlshiftexpr {
override string getOp() { result = "<<=" }
- override string getAPrimaryQlClass() { result = "AssignLShiftExpr" }
+ override string getAPrimaryQlClass() { result = "AssignLeftShiftExpr" }
}
+/** DEPRECATED: Alias for AssignLeftShiftExpr. */
+deprecated class AssignLShiftExpr = AssignLeftShiftExpr;
+
/** A compound assignment expression using the `>>=` operator. */
-class AssignRShiftExpr extends AssignOp, @assignrshiftexpr {
+class AssignRightShiftExpr extends AssignOp, @assignrshiftexpr {
override string getOp() { result = ">>=" }
- override string getAPrimaryQlClass() { result = "AssignRShiftExpr" }
+ override string getAPrimaryQlClass() { result = "AssignRightShiftExpr" }
}
+/** DEPRECATED: Alias for AssignRightShiftExpr. */
+deprecated class AssignRShiftExpr = AssignRightShiftExpr;
+
/** A compound assignment expression using the `>>>=` operator. */
-class AssignURShiftExpr extends AssignOp, @assignurshiftexpr {
+class AssignUnsignedRightShiftExpr extends AssignOp, @assignurshiftexpr {
override string getOp() { result = ">>>=" }
- override string getAPrimaryQlClass() { result = "AssignURShiftExpr" }
+ override string getAPrimaryQlClass() { result = "AssignUnsignedRightShiftExpr" }
}
+/** DEPRECATED: Alias for AssignUnsignedRightShiftExpr. */
+deprecated class AssignURShiftExpr = AssignUnsignedRightShiftExpr;
+
/** A common super-class to represent constant literals. */
class Literal extends Expr, @literal {
/**
@@ -904,26 +913,35 @@ class SubExpr extends BinaryExpr, @subexpr {
}
/** A binary expression using the `<<` operator. */
-class LShiftExpr extends BinaryExpr, @lshiftexpr {
+class LeftShiftExpr extends BinaryExpr, @lshiftexpr {
override string getOp() { result = " << " }
- override string getAPrimaryQlClass() { result = "LShiftExpr" }
+ override string getAPrimaryQlClass() { result = "LeftShiftExpr" }
}
+/** DEPRECATED: Alias for LeftShiftExpr. */
+deprecated class LShiftExpr = LeftShiftExpr;
+
/** A binary expression using the `>>` operator. */
-class RShiftExpr extends BinaryExpr, @rshiftexpr {
+class RightShiftExpr extends BinaryExpr, @rshiftexpr {
override string getOp() { result = " >> " }
- override string getAPrimaryQlClass() { result = "RShiftExpr" }
+ override string getAPrimaryQlClass() { result = "RightShiftExpr" }
}
+/** DEPRECATED: Alias for RightShiftExpr. */
+deprecated class RShiftExpr = RightShiftExpr;
+
/** A binary expression using the `>>>` operator. */
-class URShiftExpr extends BinaryExpr, @urshiftexpr {
+class UnsignedRightShiftExpr extends BinaryExpr, @urshiftexpr {
override string getOp() { result = " >>> " }
- override string getAPrimaryQlClass() { result = "URShiftExpr" }
+ override string getAPrimaryQlClass() { result = "UnsignedRightShiftExpr" }
}
+/** DEPRECATED: Alias for UnsignedRightShiftExpr. */
+deprecated class URShiftExpr = UnsignedRightShiftExpr;
+
/** A binary expression using the `&` operator. */
class AndBitwiseExpr extends BinaryExpr, @andbitexpr {
override string getOp() { result = " & " }
diff --git a/java/ql/lib/semmle/code/java/dataflow/ModulusAnalysis.qll b/java/ql/lib/semmle/code/java/dataflow/ModulusAnalysis.qll
index b919d143a39..5b2a39ad6c9 100644
--- a/java/ql/lib/semmle/code/java/dataflow/ModulusAnalysis.qll
+++ b/java/ql/lib/semmle/code/java/dataflow/ModulusAnalysis.qll
@@ -105,7 +105,7 @@ private predicate evenlyDivisibleExpr(Expr e, int factor) {
exists(ConstantIntegerExpr c, int k | k = c.getIntValue() |
e.(MulExpr).getAnOperand() = c and factor = k.abs() and factor >= 2
or
- e.(LShiftExpr).getRhs() = c and factor = 2.pow(k) and k > 0
+ e.(LeftShiftExpr).getRhs() = c and factor = 2.pow(k) and k > 0
or
e.(BitwiseAndExpr).getAnOperand() = c and factor = max(int f | andmaskFactor(k, f))
)
diff --git a/java/ql/lib/semmle/code/java/dataflow/RangeAnalysis.qll b/java/ql/lib/semmle/code/java/dataflow/RangeAnalysis.qll
index 835c4a20ac3..aeb79ee99e1 100644
--- a/java/ql/lib/semmle/code/java/dataflow/RangeAnalysis.qll
+++ b/java/ql/lib/semmle/code/java/dataflow/RangeAnalysis.qll
@@ -528,11 +528,11 @@ private predicate boundFlowStepMul(Expr e2, Expr e1, int factor) {
or
exists(AssignMulExpr e | e = e2 and e.getDest() = c and e.getRhs() = e1 and factor = k)
or
- exists(LShiftExpr e |
+ exists(LeftShiftExpr e |
e = e2 and e.getLeftOperand() = e1 and e.getRightOperand() = c and factor = 2.pow(k)
)
or
- exists(AssignLShiftExpr e |
+ exists(AssignLeftShiftExpr e |
e = e2 and e.getDest() = e1 and e.getRhs() = c and factor = 2.pow(k)
)
)
@@ -552,19 +552,19 @@ private predicate boundFlowStepDiv(Expr e2, Expr e1, int factor) {
or
exists(AssignDivExpr e | e = e2 and e.getDest() = e1 and e.getRhs() = c and factor = k)
or
- exists(RShiftExpr e |
+ exists(RightShiftExpr e |
e = e2 and e.getLeftOperand() = e1 and e.getRightOperand() = c and factor = 2.pow(k)
)
or
- exists(AssignRShiftExpr e |
+ exists(AssignRightShiftExpr e |
e = e2 and e.getDest() = e1 and e.getRhs() = c and factor = 2.pow(k)
)
or
- exists(URShiftExpr e |
+ exists(UnsignedRightShiftExpr e |
e = e2 and e.getLeftOperand() = e1 and e.getRightOperand() = c and factor = 2.pow(k)
)
or
- exists(AssignURShiftExpr e |
+ exists(AssignUnsignedRightShiftExpr e |
e = e2 and e.getDest() = e1 and e.getRhs() = c and factor = 2.pow(k)
)
)
diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/ModulusAnalysisSpecific.qll b/java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/ModulusAnalysisSpecific.qll
index c5d5bc98009..7e13861c0da 100644
--- a/java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/ModulusAnalysisSpecific.qll
+++ b/java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/ModulusAnalysisSpecific.qll
@@ -72,13 +72,13 @@ module Private {
}
/** A left shift or an assign-lshift expression. */
- class LShiftExpr extends J::Expr {
- LShiftExpr() { this instanceof J::LShiftExpr or this instanceof J::AssignLShiftExpr }
+ class LeftShiftExpr extends J::Expr {
+ LeftShiftExpr() { this instanceof J::LeftShiftExpr or this instanceof J::AssignLeftShiftExpr }
/** Gets the RHS operand of this shift. */
Expr getRhs() {
- result = this.(J::LShiftExpr).getRightOperand() or
- result = this.(J::AssignLShiftExpr).getRhs()
+ result = this.(J::LeftShiftExpr).getRightOperand() or
+ result = this.(J::AssignLeftShiftExpr).getRhs()
}
}
diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/Sign.qll b/java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/Sign.qll
index b2058a27114..649b4216996 100644
--- a/java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/Sign.qll
+++ b/java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/Sign.qll
@@ -18,9 +18,9 @@ newtype TBinarySignOperation =
TBitAndOp() or
TBitOrOp() or
TBitXorOp() or
- TLShiftOp() or
- TRShiftOp() or
- TURShiftOp()
+ TLeftShiftOp() or
+ TRightShiftOp() or
+ TUnsignedRightShiftOp()
/** Class representing expression signs (+, -, 0). */
class Sign extends TSign {
@@ -271,10 +271,10 @@ class Sign extends TSign {
or
op = TBitXorOp() and result = bitxor(s)
or
- op = TLShiftOp() and result = lshift(s)
+ op = TLeftShiftOp() and result = lshift(s)
or
- op = TRShiftOp() and result = rshift(s)
+ op = TRightShiftOp() and result = rshift(s)
or
- op = TURShiftOp() and result = urshift(s)
+ op = TUnsignedRightShiftOp() and result = urshift(s)
}
}
diff --git a/java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/SignAnalysisSpecific.qll b/java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/SignAnalysisSpecific.qll
index b2b63ff3633..59f7f4580a8 100644
--- a/java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/SignAnalysisSpecific.qll
+++ b/java/ql/lib/semmle/code/java/dataflow/internal/rangeanalysis/SignAnalysisSpecific.qll
@@ -102,12 +102,12 @@ module Private {
this instanceof J::AssignOrExpr or
this instanceof J::XorBitwiseExpr or
this instanceof J::AssignXorExpr or
- this instanceof J::LShiftExpr or
- this instanceof J::AssignLShiftExpr or
- this instanceof J::RShiftExpr or
- this instanceof J::AssignRShiftExpr or
- this instanceof J::URShiftExpr or
- this instanceof J::AssignURShiftExpr
+ this instanceof J::LeftShiftExpr or
+ this instanceof J::AssignLeftShiftExpr or
+ this instanceof J::RightShiftExpr or
+ this instanceof J::AssignRightShiftExpr or
+ this instanceof J::UnsignedRightShiftExpr or
+ this instanceof J::AssignUnsignedRightShiftExpr
}
/** Returns the operation representing this expression. */
@@ -144,17 +144,17 @@ module Private {
or
this instanceof J::AssignXorExpr and result = TBitXorOp()
or
- this instanceof J::LShiftExpr and result = TLShiftOp()
+ this instanceof J::LeftShiftExpr and result = TLeftShiftOp()
or
- this instanceof J::AssignLShiftExpr and result = TLShiftOp()
+ this instanceof J::AssignLeftShiftExpr and result = TLeftShiftOp()
or
- this instanceof J::RShiftExpr and result = TRShiftOp()
+ this instanceof J::RightShiftExpr and result = TRightShiftOp()
or
- this instanceof J::AssignRShiftExpr and result = TRShiftOp()
+ this instanceof J::AssignRightShiftExpr and result = TRightShiftOp()
or
- this instanceof J::URShiftExpr and result = TURShiftOp()
+ this instanceof J::UnsignedRightShiftExpr and result = TUnsignedRightShiftOp()
or
- this instanceof J::AssignURShiftExpr and result = TURShiftOp()
+ this instanceof J::AssignUnsignedRightShiftExpr and result = TUnsignedRightShiftOp()
}
Expr getLeftOperand() {
diff --git a/java/ql/src/Likely Bugs/Arithmetic/LShiftLargerThanTypeWidth.ql b/java/ql/src/Likely Bugs/Arithmetic/LShiftLargerThanTypeWidth.ql
index 92bec98fd5e..f3c0b220080 100644
--- a/java/ql/src/Likely Bugs/Arithmetic/LShiftLargerThanTypeWidth.ql
+++ b/java/ql/src/Likely Bugs/Arithmetic/LShiftLargerThanTypeWidth.ql
@@ -14,7 +14,7 @@ int integralTypeWidth(IntegralType t) {
if t.hasName("long") or t.hasName("Long") then result = 64 else result = 32
}
-from LShiftExpr shift, IntegralType t, int v, string typname, int width
+from LeftShiftExpr shift, IntegralType t, int v, string typname, int width
where
shift.getLeftOperand().getType() = t and
shift.getRightOperand().(CompileTimeConstantExpr).getIntValue() = v and
diff --git a/java/ql/src/Likely Bugs/Arithmetic/WhitespaceContradictsPrecedence.ql b/java/ql/src/Likely Bugs/Arithmetic/WhitespaceContradictsPrecedence.ql
index db806ef760c..b0508b8eb38 100644
--- a/java/ql/src/Likely Bugs/Arithmetic/WhitespaceContradictsPrecedence.ql
+++ b/java/ql/src/Likely Bugs/Arithmetic/WhitespaceContradictsPrecedence.ql
@@ -33,9 +33,9 @@ class ArithmeticExpr extends BinaryExpr {
*/
class ShiftExpr extends BinaryExpr {
ShiftExpr() {
- this instanceof LShiftExpr or
- this instanceof RShiftExpr or
- this instanceof URShiftExpr
+ this instanceof LeftShiftExpr or
+ this instanceof RightShiftExpr or
+ this instanceof UnsignedRightShiftExpr
}
}
diff --git a/java/ql/src/Likely Bugs/Comparison/UselessComparisonTest.ql b/java/ql/src/Likely Bugs/Comparison/UselessComparisonTest.ql
index 964a5a6060a..b4076bee00b 100644
--- a/java/ql/src/Likely Bugs/Comparison/UselessComparisonTest.ql
+++ b/java/ql/src/Likely Bugs/Comparison/UselessComparisonTest.ql
@@ -99,7 +99,7 @@ Expr overFlowCand() {
|
bin instanceof AddExpr or
bin instanceof MulExpr or
- bin instanceof LShiftExpr
+ bin instanceof LeftShiftExpr
)
or
exists(AssignOp op |
@@ -109,7 +109,7 @@ Expr overFlowCand() {
|
op instanceof AssignAddExpr or
op instanceof AssignMulExpr or
- op instanceof AssignLShiftExpr
+ op instanceof AssignLeftShiftExpr
)
or
exists(AddExpr add, CompileTimeConstantExpr c |
diff --git a/java/ql/src/Security/CWE/CWE-190/ArithmeticCommon.qll b/java/ql/src/Security/CWE/CWE-190/ArithmeticCommon.qll
index 8287ebc869e..122f6b75b4a 100644
--- a/java/ql/src/Security/CWE/CWE-190/ArithmeticCommon.qll
+++ b/java/ql/src/Security/CWE/CWE-190/ArithmeticCommon.qll
@@ -153,9 +153,9 @@ predicate upcastToWiderType(Expr e) {
/** Holds if the result of `exp` has certain bits filtered by a bitwise and. */
private predicate inBitwiseAnd(Expr exp) {
exists(AndBitwiseExpr a | a.getAnOperand() = exp) or
- inBitwiseAnd(exp.(LShiftExpr).getAnOperand()) or
- inBitwiseAnd(exp.(RShiftExpr).getAnOperand()) or
- inBitwiseAnd(exp.(URShiftExpr).getAnOperand())
+ inBitwiseAnd(exp.(LeftShiftExpr).getAnOperand()) or
+ inBitwiseAnd(exp.(RightShiftExpr).getAnOperand()) or
+ inBitwiseAnd(exp.(UnsignedRightShiftExpr).getAnOperand())
}
/** Holds if overflow/underflow is irrelevant for this expression. */
diff --git a/java/ql/src/Security/CWE/CWE-681/NumericCastCommon.qll b/java/ql/src/Security/CWE/CWE-681/NumericCastCommon.qll
index 4dec14a204f..5a77c0a8d6e 100644
--- a/java/ql/src/Security/CWE/CWE-681/NumericCastCommon.qll
+++ b/java/ql/src/Security/CWE/CWE-681/NumericCastCommon.qll
@@ -16,10 +16,10 @@ class NumericNarrowingCastExpr extends CastExpr {
class RightShiftOp extends Expr {
RightShiftOp() {
- this instanceof RShiftExpr or
- this instanceof URShiftExpr or
- this instanceof AssignRShiftExpr or
- this instanceof AssignURShiftExpr
+ this instanceof RightShiftExpr or
+ this instanceof UnsignedRightShiftExpr or
+ this instanceof AssignRightShiftExpr or
+ this instanceof AssignUnsignedRightShiftExpr
}
private Expr getLhs() {
diff --git a/java/ql/test/kotlin/library-tests/exprs/PrintAst.expected b/java/ql/test/kotlin/library-tests/exprs/PrintAst.expected
index 78bf583ec0d..3b4cc35d4d4 100644
--- a/java/ql/test/kotlin/library-tests/exprs/PrintAst.expected
+++ b/java/ql/test/kotlin/library-tests/exprs/PrintAst.expected
@@ -1944,17 +1944,17 @@ exprs.kt:
# 15| 1: [VarAccess] y
# 16| 5: [LocalVariableDeclStmt] var ...;
# 16| 1: [LocalVariableDeclExpr] i6
-# 16| 0: [LShiftExpr] ... << ...
+# 16| 0: [LeftShiftExpr] ... << ...
# 16| 0: [VarAccess] x
# 16| 1: [VarAccess] y
# 17| 6: [LocalVariableDeclStmt] var ...;
# 17| 1: [LocalVariableDeclExpr] i7
-# 17| 0: [RShiftExpr] ... >> ...
+# 17| 0: [RightShiftExpr] ... >> ...
# 17| 0: [VarAccess] x
# 17| 1: [VarAccess] y
# 18| 7: [LocalVariableDeclStmt] var ...;
# 18| 1: [LocalVariableDeclExpr] i8
-# 18| 0: [URShiftExpr] ... >>> ...
+# 18| 0: [UnsignedRightShiftExpr] ... >>> ...
# 18| 0: [VarAccess] x
# 18| 1: [VarAccess] y
# 19| 8: [LocalVariableDeclStmt] var ...;
@@ -2236,17 +2236,17 @@ exprs.kt:
# 72| 1: [VarAccess] ly
# 73| 59: [LocalVariableDeclStmt] var ...;
# 73| 1: [LocalVariableDeclExpr] l6
-# 73| 0: [LShiftExpr] ... << ...
+# 73| 0: [LeftShiftExpr] ... << ...
# 73| 0: [VarAccess] lx
# 73| 1: [VarAccess] y
# 74| 60: [LocalVariableDeclStmt] var ...;
# 74| 1: [LocalVariableDeclExpr] l7
-# 74| 0: [RShiftExpr] ... >> ...
+# 74| 0: [RightShiftExpr] ... >> ...
# 74| 0: [VarAccess] lx
# 74| 1: [VarAccess] y
# 75| 61: [LocalVariableDeclStmt] var ...;
# 75| 1: [LocalVariableDeclExpr] l8
-# 75| 0: [URShiftExpr] ... >>> ...
+# 75| 0: [UnsignedRightShiftExpr] ... >>> ...
# 75| 0: [VarAccess] lx
# 75| 1: [VarAccess] y
# 76| 62: [LocalVariableDeclStmt] var ...;
diff --git a/java/ql/test/kotlin/library-tests/exprs/exprs.expected b/java/ql/test/kotlin/library-tests/exprs/exprs.expected
index 5d35293eb22..07d57c444e4 100644
--- a/java/ql/test/kotlin/library-tests/exprs/exprs.expected
+++ b/java/ql/test/kotlin/library-tests/exprs/exprs.expected
@@ -924,15 +924,15 @@
| exprs.kt:15:18:15:18 | y | exprs.kt:4:1:142:1 | topLevelMethod | VarAccess |
| exprs.kt:16:9:16:10 | i6 | exprs.kt:4:1:142:1 | topLevelMethod | LocalVariableDeclExpr |
| exprs.kt:16:14:16:14 | x | exprs.kt:4:1:142:1 | topLevelMethod | VarAccess |
-| exprs.kt:16:14:16:20 | ... << ... | exprs.kt:4:1:142:1 | topLevelMethod | LShiftExpr |
+| exprs.kt:16:14:16:20 | ... << ... | exprs.kt:4:1:142:1 | topLevelMethod | LeftShiftExpr |
| exprs.kt:16:20:16:20 | y | exprs.kt:4:1:142:1 | topLevelMethod | VarAccess |
| exprs.kt:17:9:17:10 | i7 | exprs.kt:4:1:142:1 | topLevelMethod | LocalVariableDeclExpr |
| exprs.kt:17:14:17:14 | x | exprs.kt:4:1:142:1 | topLevelMethod | VarAccess |
-| exprs.kt:17:14:17:20 | ... >> ... | exprs.kt:4:1:142:1 | topLevelMethod | RShiftExpr |
+| exprs.kt:17:14:17:20 | ... >> ... | exprs.kt:4:1:142:1 | topLevelMethod | RightShiftExpr |
| exprs.kt:17:20:17:20 | y | exprs.kt:4:1:142:1 | topLevelMethod | VarAccess |
| exprs.kt:18:9:18:10 | i8 | exprs.kt:4:1:142:1 | topLevelMethod | LocalVariableDeclExpr |
| exprs.kt:18:14:18:14 | x | exprs.kt:4:1:142:1 | topLevelMethod | VarAccess |
-| exprs.kt:18:14:18:21 | ... >>> ... | exprs.kt:4:1:142:1 | topLevelMethod | URShiftExpr |
+| exprs.kt:18:14:18:21 | ... >>> ... | exprs.kt:4:1:142:1 | topLevelMethod | UnsignedRightShiftExpr |
| exprs.kt:18:21:18:21 | y | exprs.kt:4:1:142:1 | topLevelMethod | VarAccess |
| exprs.kt:19:9:19:10 | i9 | exprs.kt:4:1:142:1 | topLevelMethod | LocalVariableDeclExpr |
| exprs.kt:19:14:19:14 | x | exprs.kt:4:1:142:1 | topLevelMethod | VarAccess |
@@ -1162,15 +1162,15 @@
| exprs.kt:72:19:72:20 | ly | exprs.kt:4:1:142:1 | topLevelMethod | VarAccess |
| exprs.kt:73:9:73:10 | l6 | exprs.kt:4:1:142:1 | topLevelMethod | LocalVariableDeclExpr |
| exprs.kt:73:14:73:15 | lx | exprs.kt:4:1:142:1 | topLevelMethod | VarAccess |
-| exprs.kt:73:14:73:21 | ... << ... | exprs.kt:4:1:142:1 | topLevelMethod | LShiftExpr |
+| exprs.kt:73:14:73:21 | ... << ... | exprs.kt:4:1:142:1 | topLevelMethod | LeftShiftExpr |
| exprs.kt:73:21:73:21 | y | exprs.kt:4:1:142:1 | topLevelMethod | VarAccess |
| exprs.kt:74:9:74:10 | l7 | exprs.kt:4:1:142:1 | topLevelMethod | LocalVariableDeclExpr |
| exprs.kt:74:14:74:15 | lx | exprs.kt:4:1:142:1 | topLevelMethod | VarAccess |
-| exprs.kt:74:14:74:21 | ... >> ... | exprs.kt:4:1:142:1 | topLevelMethod | RShiftExpr |
+| exprs.kt:74:14:74:21 | ... >> ... | exprs.kt:4:1:142:1 | topLevelMethod | RightShiftExpr |
| exprs.kt:74:21:74:21 | y | exprs.kt:4:1:142:1 | topLevelMethod | VarAccess |
| exprs.kt:75:9:75:10 | l8 | exprs.kt:4:1:142:1 | topLevelMethod | LocalVariableDeclExpr |
| exprs.kt:75:14:75:15 | lx | exprs.kt:4:1:142:1 | topLevelMethod | VarAccess |
-| exprs.kt:75:14:75:22 | ... >>> ... | exprs.kt:4:1:142:1 | topLevelMethod | URShiftExpr |
+| exprs.kt:75:14:75:22 | ... >>> ... | exprs.kt:4:1:142:1 | topLevelMethod | UnsignedRightShiftExpr |
| exprs.kt:75:22:75:22 | y | exprs.kt:4:1:142:1 | topLevelMethod | VarAccess |
| exprs.kt:76:9:76:10 | l9 | exprs.kt:4:1:142:1 | topLevelMethod | LocalVariableDeclExpr |
| exprs.kt:76:14:76:15 | lx | exprs.kt:4:1:142:1 | topLevelMethod | VarAccess |
diff --git a/java/ql/test/library-tests/constants/PrintAst.expected b/java/ql/test/library-tests/constants/PrintAst.expected
index 241d837ea3c..63d59f7287e 100644
--- a/java/ql/test/library-tests/constants/PrintAst.expected
+++ b/java/ql/test/library-tests/constants/PrintAst.expected
@@ -376,26 +376,26 @@ constants/Values.java:
# 62| 43: [LocalVariableDeclStmt] var ...;
# 62| 0: [TypeAccess] int
# 62| 1: [LocalVariableDeclExpr] lshift
-# 62| 0: [LShiftExpr] ... << ...
+# 62| 0: [LeftShiftExpr] ... << ...
# 62| 0: [IntegerLiteral] 21
# 62| 1: [IntegerLiteral] 2
# 63| 44: [LocalVariableDeclStmt] var ...;
# 63| 0: [TypeAccess] int
# 63| 1: [LocalVariableDeclExpr] lshift_parameter
-# 63| 0: [LShiftExpr] ... << ...
+# 63| 0: [LeftShiftExpr] ... << ...
# 63| 0: [VarAccess] notConstant
# 63| 1: [VarAccess] notConstant
# 65| 45: [LocalVariableDeclStmt] var ...;
# 65| 0: [TypeAccess] int
# 65| 1: [LocalVariableDeclExpr] rshift
-# 65| 0: [RShiftExpr] ... >> ...
+# 65| 0: [RightShiftExpr] ... >> ...
# 65| 0: [MinusExpr] -...
# 65| 0: [IntegerLiteral] 1
# 65| 1: [IntegerLiteral] 2
# 66| 46: [LocalVariableDeclStmt] var ...;
# 66| 0: [TypeAccess] int
# 66| 1: [LocalVariableDeclExpr] urshift
-# 66| 0: [URShiftExpr] ... >>> ...
+# 66| 0: [UnsignedRightShiftExpr] ... >>> ...
# 66| 0: [MinusExpr] -...
# 66| 0: [IntegerLiteral] 1
# 66| 1: [IntegerLiteral] 1
From 529be7ef1804b4a60cbd2ace923b8769f873c6ce Mon Sep 17 00:00:00 2001
From: Michael Nebel
Date: Tue, 10 Jan 2023 09:54:35 +0100
Subject: [PATCH 235/381] C++: Sync files.
---
.../lib/semmle/code/cpp/ir/implementation/Opcode.qll | 10 ++++++++++
.../cpp/ir/implementation/aliased_ssa/Instruction.qll | 11 +++++++++++
.../code/cpp/ir/implementation/raw/Instruction.qll | 11 +++++++++++
.../ir/implementation/unaliased_ssa/Instruction.qll | 11 +++++++++++
4 files changed, 43 insertions(+)
diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/Opcode.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/Opcode.qll
index c4134d240ab..b4def7fe4ae 100644
--- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/Opcode.qll
+++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/Opcode.qll
@@ -30,6 +30,7 @@ private newtype TOpcode =
TNegate() or
TShiftLeft() or
TShiftRight() or
+ TUnsignedShiftRight() or
TBitAnd() or
TBitOr() or
TBitXor() or
@@ -652,6 +653,15 @@ module Opcode {
final override string toString() { result = "ShiftRight" }
}
+ /**
+ * The `Opcode` for a `UnsignedShiftRightInstruction`.
+ *
+ * See the `UnsignedShiftRightInstruction` documentation for more details.
+ */
+ class UnsignedShiftRight extends BinaryBitwiseOpcode, TUnsignedShiftRight {
+ final override string toString() { result = "UnsignedShiftRight" }
+ }
+
/**
* The `Opcode` for a `BitAndInstruction`.
*
diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll
index 7afe954023b..0aa7c552638 100644
--- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll
+++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/aliased_ssa/Instruction.qll
@@ -1204,6 +1204,17 @@ class ShiftRightInstruction extends BinaryBitwiseInstruction {
ShiftRightInstruction() { this.getOpcode() instanceof Opcode::ShiftRight }
}
+/**
+ * An instruction that shifts its left operand to the right by the number of bits specified by its
+ * right operand.
+ *
+ * Both operands must have an integer type. The result has the same type as the left operand.
+ * The leftmost bits are zero-filled.
+ */
+class UnsignedShiftRightInstruction extends BinaryBitwiseInstruction {
+ UnsignedShiftRightInstruction() { this.getOpcode() instanceof Opcode::UnsignedShiftRight }
+}
+
/**
* An instruction that performs a binary arithmetic operation involving at least one pointer
* operand.
diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Instruction.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Instruction.qll
index 7afe954023b..0aa7c552638 100644
--- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Instruction.qll
+++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/raw/Instruction.qll
@@ -1204,6 +1204,17 @@ class ShiftRightInstruction extends BinaryBitwiseInstruction {
ShiftRightInstruction() { this.getOpcode() instanceof Opcode::ShiftRight }
}
+/**
+ * An instruction that shifts its left operand to the right by the number of bits specified by its
+ * right operand.
+ *
+ * Both operands must have an integer type. The result has the same type as the left operand.
+ * The leftmost bits are zero-filled.
+ */
+class UnsignedShiftRightInstruction extends BinaryBitwiseInstruction {
+ UnsignedShiftRightInstruction() { this.getOpcode() instanceof Opcode::UnsignedShiftRight }
+}
+
/**
* An instruction that performs a binary arithmetic operation involving at least one pointer
* operand.
diff --git a/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll b/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll
index 7afe954023b..0aa7c552638 100644
--- a/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll
+++ b/cpp/ql/lib/semmle/code/cpp/ir/implementation/unaliased_ssa/Instruction.qll
@@ -1204,6 +1204,17 @@ class ShiftRightInstruction extends BinaryBitwiseInstruction {
ShiftRightInstruction() { this.getOpcode() instanceof Opcode::ShiftRight }
}
+/**
+ * An instruction that shifts its left operand to the right by the number of bits specified by its
+ * right operand.
+ *
+ * Both operands must have an integer type. The result has the same type as the left operand.
+ * The leftmost bits are zero-filled.
+ */
+class UnsignedShiftRightInstruction extends BinaryBitwiseInstruction {
+ UnsignedShiftRightInstruction() { this.getOpcode() instanceof Opcode::UnsignedShiftRight }
+}
+
/**
* An instruction that performs a binary arithmetic operation involving at least one pointer
* operand.
From 5e89119b3d9559e1b6855d5f25994c2aa928a486 Mon Sep 17 00:00:00 2001
From: Michael Nebel
Date: Wed, 11 Jan 2023 15:09:00 +0100
Subject: [PATCH 236/381] C#: Add upgrade- and downgrade scripts for unsigned
right shift operators.
---
.../expressions.ql | 13 +
.../old.dbscheme | 2069 +++++++++++++++++
.../semmlecode.csharp.dbscheme | 2067 ++++++++++++++++
.../upgrade.properties | 3 +
.../old.dbscheme | 2067 ++++++++++++++++
.../semmlecode.csharp.dbscheme | 2069 +++++++++++++++++
.../upgrade.properties | 2 +
7 files changed, 8290 insertions(+)
create mode 100644 csharp/downgrades/d0fba103f7dee477dd7d9f6c038518b3f683b2c7/expressions.ql
create mode 100644 csharp/downgrades/d0fba103f7dee477dd7d9f6c038518b3f683b2c7/old.dbscheme
create mode 100644 csharp/downgrades/d0fba103f7dee477dd7d9f6c038518b3f683b2c7/semmlecode.csharp.dbscheme
create mode 100644 csharp/downgrades/d0fba103f7dee477dd7d9f6c038518b3f683b2c7/upgrade.properties
create mode 100644 csharp/ql/lib/upgrades/83aca6b3e4fa38dd2b97b9b51dfc199a2ba9c7f2/old.dbscheme
create mode 100644 csharp/ql/lib/upgrades/83aca6b3e4fa38dd2b97b9b51dfc199a2ba9c7f2/semmlecode.csharp.dbscheme
create mode 100644 csharp/ql/lib/upgrades/83aca6b3e4fa38dd2b97b9b51dfc199a2ba9c7f2/upgrade.properties
diff --git a/csharp/downgrades/d0fba103f7dee477dd7d9f6c038518b3f683b2c7/expressions.ql b/csharp/downgrades/d0fba103f7dee477dd7d9f6c038518b3f683b2c7/expressions.ql
new file mode 100644
index 00000000000..6afabce797e
--- /dev/null
+++ b/csharp/downgrades/d0fba103f7dee477dd7d9f6c038518b3f683b2c7/expressions.ql
@@ -0,0 +1,13 @@
+class Expression extends @expr {
+ string toString() { none() }
+}
+
+class TypeOrRef extends @type_or_ref {
+ string toString() { none() }
+}
+
+from Expression e, int k, int kind, TypeOrRef t
+where
+ expressions(e, k, t) and
+ if k = [133, 134] then kind = 106 else kind = k
+select e, kind, t
diff --git a/csharp/downgrades/d0fba103f7dee477dd7d9f6c038518b3f683b2c7/old.dbscheme b/csharp/downgrades/d0fba103f7dee477dd7d9f6c038518b3f683b2c7/old.dbscheme
new file mode 100644
index 00000000000..d0fba103f7d
--- /dev/null
+++ b/csharp/downgrades/d0fba103f7dee477dd7d9f6c038518b3f683b2c7/old.dbscheme
@@ -0,0 +1,2069 @@
+/* This is a dummy line to alter the dbscheme, so we can make a database upgrade
+ * without actually changing any of the dbscheme predicates. It contains a date
+ * to allow for such updates in the future as well.
+ *
+ * 2021-07-14
+ *
+ * DO NOT remove this comment carelessly, since it can revert the dbscheme back to a
+ * previously seen state (matching a previously seen SHA), which would make the upgrade
+ * mechanism not work properly.
+ */
+
+/**
+ * An invocation of the compiler. Note that more than one file may be
+ * compiled per invocation. For example, this command compiles three
+ * source files:
+ *
+ * csc f1.cs f2.cs f3.cs
+ *
+ * The `id` simply identifies the invocation, while `cwd` is the working
+ * directory from which the compiler was invoked.
+ */
+compilations(
+ unique int id : @compilation,
+ string cwd : string ref
+);
+
+/**
+ * The arguments that were passed to the extractor for a compiler
+ * invocation. If `id` is for the compiler invocation
+ *
+ * csc f1.cs f2.cs f3.cs
+ *
+ * then typically there will be rows for
+ *
+ * num | arg
+ * --- | ---
+ * 0 | --compiler
+ * 1 | *path to compiler*
+ * 2 | f1.cs
+ * 3 | f2.cs
+ * 4 | f3.cs
+ */
+#keyset[id, num]
+compilation_args(
+ int id : @compilation ref,
+ int num : int ref,
+ string arg : string ref
+);
+
+/**
+ * The source files that are compiled by a compiler invocation.
+ * If `id` is for the compiler invocation
+ *
+ * csc f1.cs f2.cs f3.cs
+ *
+ * then there will be rows for
+ *
+ * num | arg
+ * --- | ---
+ * 0 | f1.cs
+ * 1 | f2.cs
+ * 2 | f3.cs
+ */
+#keyset[id, num]
+compilation_compiling_files(
+ int id : @compilation ref,
+ int num : int ref,
+ int file : @file ref
+);
+
+/**
+ * The references used by a compiler invocation.
+ * If `id` is for the compiler invocation
+ *
+ * csc f1.cs f2.cs f3.cs /r:ref1.dll /r:ref2.dll /r:ref3.dll
+ *
+ * then there will be rows for
+ *
+ * num | arg
+ * --- | ---
+ * 0 | ref1.dll
+ * 1 | ref2.dll
+ * 2 | ref3.dll
+ */
+#keyset[id, num]
+compilation_referencing_files(
+ int id : @compilation ref,
+ int num : int ref,
+ int file : @file ref
+);
+
+/**
+ * The time taken by the extractor for a compiler invocation.
+ *
+ * For each file `num`, there will be rows for
+ *
+ * kind | seconds
+ * ---- | ---
+ * 1 | CPU seconds used by the extractor frontend
+ * 2 | Elapsed seconds during the extractor frontend
+ * 3 | CPU seconds used by the extractor backend
+ * 4 | Elapsed seconds during the extractor backend
+ */
+#keyset[id, num, kind]
+compilation_time(
+ int id : @compilation ref,
+ int num : int ref,
+ /* kind:
+ 1 = frontend_cpu_seconds
+ 2 = frontend_elapsed_seconds
+ 3 = extractor_cpu_seconds
+ 4 = extractor_elapsed_seconds
+ */
+ int kind : int ref,
+ float seconds : float ref
+);
+
+/**
+ * An error or warning generated by the extractor.
+ * The diagnostic message `diagnostic` was generated during compiler
+ * invocation `compilation`, and is the `file_number_diagnostic_number`th
+ * message generated while extracting the `file_number`th file of that
+ * invocation.
+ */
+#keyset[compilation, file_number, file_number_diagnostic_number]
+diagnostic_for(
+ unique int diagnostic : @diagnostic ref,
+ int compilation : @compilation ref,
+ int file_number : int ref,
+ int file_number_diagnostic_number : int ref
+);
+
+diagnostics(
+ unique int id: @diagnostic,
+ int severity: int ref,
+ string error_tag: string ref,
+ string error_message: string ref,
+ string full_error_message: string ref,
+ int location: @location_default ref
+);
+
+extractor_messages(
+ unique int id: @extractor_message,
+ int severity: int ref,
+ string origin : string ref,
+ string text : string ref,
+ string entity : string ref,
+ int location: @location_default ref,
+ string stack_trace : string ref
+);
+
+/**
+ * If extraction was successful, then `cpu_seconds` and
+ * `elapsed_seconds` are the CPU time and elapsed time (respectively)
+ * that extraction took for compiler invocation `id`.
+ */
+compilation_finished(
+ unique int id : @compilation ref,
+ float cpu_seconds : float ref,
+ float elapsed_seconds : float ref
+);
+
+compilation_assembly(
+ unique int id : @compilation ref,
+ int assembly: @assembly ref
+)
+
+// Populated by the CSV extractor
+externalData(
+ int id: @externalDataElement,
+ string path: string ref,
+ int column: int ref,
+ string value: string ref);
+
+sourceLocationPrefix(
+ string prefix: string ref);
+
+/*
+ * C# dbscheme
+ */
+
+/** ELEMENTS **/
+
+@element = @declaration | @stmt | @expr | @modifier | @attribute | @namespace_declaration
+ | @using_directive | @type_parameter_constraints | @externalDataElement
+ | @xmllocatable | @asp_element | @namespace | @preprocessor_directive;
+
+@declaration = @callable | @generic | @assignable | @namespace;
+
+@named_element = @namespace | @declaration;
+
+@declaration_with_accessors = @property | @indexer | @event;
+
+@assignable = @variable | @assignable_with_accessors | @event;
+
+@assignable_with_accessors = @property | @indexer;
+
+@attributable = @assembly | @field | @parameter | @operator | @method | @constructor
+ | @destructor | @callable_accessor | @value_or_ref_type | @declaration_with_accessors
+ | @local_function | @lambda_expr;
+
+/** LOCATIONS, ASEMMBLIES, MODULES, FILES and FOLDERS **/
+
+@location = @location_default | @assembly;
+
+locations_default(
+ unique int id: @location_default,
+ int file: @file ref,
+ int beginLine: int ref,
+ int beginColumn: int ref,
+ int endLine: int ref,
+ int endColumn: int ref);
+
+locations_mapped(
+ unique int id: @location_default ref,
+ int mapped_to: @location_default ref);
+
+@sourceline = @file | @callable | @xmllocatable;
+
+numlines(
+ int element_id: @sourceline ref,
+ int num_lines: int ref,
+ int num_code: int ref,
+ int num_comment: int ref);
+
+assemblies(
+ unique int id: @assembly,
+ int file: @file ref,
+ string fullname: string ref,
+ string name: string ref,
+ string version: string ref);
+
+files(
+ unique int id: @file,
+ string name: string ref);
+
+folders(
+ unique int id: @folder,
+ string name: string ref);
+
+@container = @folder | @file ;
+
+containerparent(
+ int parent: @container ref,
+ unique int child: @container ref);
+
+file_extraction_mode(
+ unique int file: @file ref,
+ int mode: int ref
+ /* 0 = normal, 1 = standalone extractor */
+ );
+
+/** NAMESPACES **/
+
+@type_container = @namespace | @type;
+
+namespaces(
+ unique int id: @namespace,
+ string name: string ref);
+
+namespace_declarations(
+ unique int id: @namespace_declaration,
+ int namespace_id: @namespace ref);
+
+namespace_declaration_location(
+ unique int id: @namespace_declaration ref,
+ int loc: @location ref);
+
+parent_namespace(
+ unique int child_id: @type_container ref,
+ int namespace_id: @namespace ref);
+
+@declaration_or_directive = @namespace_declaration | @type | @using_directive;
+
+parent_namespace_declaration(
+ int child_id: @declaration_or_directive ref, // cannot be unique because of partial classes
+ int namespace_id: @namespace_declaration ref);
+
+@using_directive = @using_namespace_directive | @using_static_directive;
+
+using_global(
+ unique int id: @using_directive ref
+);
+
+using_namespace_directives(
+ unique int id: @using_namespace_directive,
+ int namespace_id: @namespace ref);
+
+using_static_directives(
+ unique int id: @using_static_directive,
+ int type_id: @type_or_ref ref);
+
+using_directive_location(
+ unique int id: @using_directive ref,
+ int loc: @location ref);
+
+@preprocessor_directive = @pragma_warning | @pragma_checksum | @directive_define | @directive_undefine | @directive_warning
+ | @directive_error | @directive_nullable | @directive_line | @directive_region | @directive_endregion | @directive_if
+ | @directive_elif | @directive_else | @directive_endif;
+
+@conditional_directive = @directive_if | @directive_elif;
+@branch_directive = @directive_if | @directive_elif | @directive_else;
+
+directive_ifs(
+ unique int id: @directive_if,
+ int branchTaken: int ref, /* 0: false, 1: true */
+ int conditionValue: int ref); /* 0: false, 1: true */
+
+directive_elifs(
+ unique int id: @directive_elif,
+ int branchTaken: int ref, /* 0: false, 1: true */
+ int conditionValue: int ref, /* 0: false, 1: true */
+ int parent: @directive_if ref,
+ int index: int ref);
+
+directive_elses(
+ unique int id: @directive_else,
+ int branchTaken: int ref, /* 0: false, 1: true */
+ int parent: @directive_if ref,
+ int index: int ref);
+
+#keyset[id, start]
+directive_endifs(
+ unique int id: @directive_endif,
+ unique int start: @directive_if ref);
+
+directive_define_symbols(
+ unique int id: @define_symbol_expr ref,
+ string name: string ref);
+
+directive_regions(
+ unique int id: @directive_region,
+ string name: string ref);
+
+#keyset[id, start]
+directive_endregions(
+ unique int id: @directive_endregion,
+ unique int start: @directive_region ref);
+
+directive_lines(
+ unique int id: @directive_line,
+ int kind: int ref); /* 0: default, 1: hidden, 2: numeric, 3: span */
+
+directive_line_value(
+ unique int id: @directive_line ref,
+ int line: int ref);
+
+directive_line_file(
+ unique int id: @directive_line ref,
+ int file: @file ref);
+
+directive_line_offset(
+ unique int id: @directive_line ref,
+ int offset: int ref);
+
+directive_line_span(
+ unique int id: @directive_line ref,
+ int startLine: int ref,
+ int startColumn: int ref,
+ int endLine: int ref,
+ int endColumn: int ref);
+
+directive_nullables(
+ unique int id: @directive_nullable,
+ int setting: int ref, /* 0: disable, 1: enable, 2: restore */
+ int target: int ref); /* 0: none, 1: annotations, 2: warnings */
+
+directive_warnings(
+ unique int id: @directive_warning,
+ string message: string ref);
+
+directive_errors(
+ unique int id: @directive_error,
+ string message: string ref);
+
+directive_undefines(
+ unique int id: @directive_undefine,
+ string name: string ref);
+
+directive_defines(
+ unique int id: @directive_define,
+ string name: string ref);
+
+pragma_checksums(
+ unique int id: @pragma_checksum,
+ int file: @file ref,
+ string guid: string ref,
+ string bytes: string ref);
+
+pragma_warnings(
+ unique int id: @pragma_warning,
+ int kind: int ref /* 0 = disable, 1 = restore */);
+
+#keyset[id, index]
+pragma_warning_error_codes(
+ int id: @pragma_warning ref,
+ string errorCode: string ref,
+ int index: int ref);
+
+preprocessor_directive_location(
+ unique int id: @preprocessor_directive ref,
+ int loc: @location ref);
+
+preprocessor_directive_compilation(
+ unique int id: @preprocessor_directive ref,
+ int compilation: @compilation ref);
+
+preprocessor_directive_active(
+ unique int id: @preprocessor_directive ref,
+ int active: int ref); /* 0: false, 1: true */
+
+/** TYPES **/
+
+types(
+ unique int id: @type,
+ int kind: int ref,
+ string name: string ref);
+
+case @type.kind of
+ 1 = @bool_type
+| 2 = @char_type
+| 3 = @decimal_type
+| 4 = @sbyte_type
+| 5 = @short_type
+| 6 = @int_type
+| 7 = @long_type
+| 8 = @byte_type
+| 9 = @ushort_type
+| 10 = @uint_type
+| 11 = @ulong_type
+| 12 = @float_type
+| 13 = @double_type
+| 14 = @enum_type
+| 15 = @struct_type
+| 17 = @class_type
+| 19 = @interface_type
+| 20 = @delegate_type
+| 21 = @null_type
+| 22 = @type_parameter
+| 23 = @pointer_type
+| 24 = @nullable_type
+| 25 = @array_type
+| 26 = @void_type
+| 27 = @int_ptr_type
+| 28 = @uint_ptr_type
+| 29 = @dynamic_type
+| 30 = @arglist_type
+| 31 = @unknown_type
+| 32 = @tuple_type
+| 33 = @function_pointer_type
+ ;
+
+@simple_type = @bool_type | @char_type | @integral_type | @floating_point_type | @decimal_type;
+@integral_type = @signed_integral_type | @unsigned_integral_type;
+@signed_integral_type = @sbyte_type | @short_type | @int_type | @long_type;
+@unsigned_integral_type = @byte_type | @ushort_type | @uint_type | @ulong_type;
+@floating_point_type = @float_type | @double_type;
+@value_type = @simple_type | @enum_type | @struct_type | @nullable_type | @int_ptr_type
+ | @uint_ptr_type | @tuple_type;
+@ref_type = @class_type | @interface_type | @array_type | @delegate_type | @null_type
+ | @dynamic_type;
+@value_or_ref_type = @value_type | @ref_type;
+
+typerefs(
+ unique int id: @typeref,
+ string name: string ref);
+
+typeref_type(
+ int id: @typeref ref,
+ unique int typeId: @type ref);
+
+@type_or_ref = @type | @typeref;
+
+array_element_type(
+ unique int array: @array_type ref,
+ int dimension: int ref,
+ int rank: int ref,
+ int element: @type_or_ref ref);
+
+nullable_underlying_type(
+ unique int nullable: @nullable_type ref,
+ int underlying: @type_or_ref ref);
+
+pointer_referent_type(
+ unique int pointer: @pointer_type ref,
+ int referent: @type_or_ref ref);
+
+enum_underlying_type(
+ unique int enum_id: @enum_type ref,
+ int underlying_type_id: @type_or_ref ref);
+
+delegate_return_type(
+ unique int delegate_id: @delegate_type ref,
+ int return_type_id: @type_or_ref ref);
+
+function_pointer_return_type(
+ unique int function_pointer_id: @function_pointer_type ref,
+ int return_type_id: @type_or_ref ref);
+
+extend(
+ int sub: @type ref,
+ int super: @type_or_ref ref);
+
+anonymous_types(
+ unique int id: @type ref);
+
+@interface_or_ref = @interface_type | @typeref;
+
+implement(
+ int sub: @type ref,
+ int super: @type_or_ref ref);
+
+type_location(
+ int id: @type ref,
+ int loc: @location ref);
+
+tuple_underlying_type(
+ unique int tuple: @tuple_type ref,
+ int struct: @type_or_ref ref);
+
+#keyset[tuple, index]
+tuple_element(
+ int tuple: @tuple_type ref,
+ int index: int ref,
+ unique int field: @field ref);
+
+attributes(
+ unique int id: @attribute,
+ int kind: int ref,
+ int type_id: @type_or_ref ref,
+ int target: @attributable ref);
+
+case @attribute.kind of
+ 0 = @attribute_default
+| 1 = @attribute_return
+| 2 = @attribute_assembly
+| 3 = @attribute_module
+;
+
+attribute_location(
+ int id: @attribute ref,
+ int loc: @location ref);
+
+@type_mention_parent = @element | @type_mention;
+
+type_mention(
+ unique int id: @type_mention,
+ int type_id: @type_or_ref ref,
+ int parent: @type_mention_parent ref);
+
+type_mention_location(
+ unique int id: @type_mention ref,
+ int loc: @location ref);
+
+@has_type_annotation = @assignable | @type_parameter | @callable | @expr | @delegate_type | @generic | @function_pointer_type;
+
+/**
+ * A direct annotation on an entity, for example `string? x;`.
+ *
+ * Annotations:
+ * 2 = reftype is not annotated "!"
+ * 3 = reftype is annotated "?"
+ * 4 = readonly ref type / in parameter
+ * 5 = ref type parameter, return or local variable
+ * 6 = out parameter
+ *
+ * Note that the annotation depends on the element it annotates.
+ * @assignable: The annotation is on the type of the assignable, for example the variable type.
+ * @type_parameter: The annotation is on the reftype constraint
+ * @callable: The annotation is on the return type
+ * @array_type: The annotation is on the element type
+ */
+type_annotation(int id: @has_type_annotation ref, int annotation: int ref);
+
+nullability(unique int nullability: @nullability, int kind: int ref);
+
+case @nullability.kind of
+ 0 = @oblivious
+| 1 = @not_annotated
+| 2 = @annotated
+;
+
+#keyset[parent, index]
+nullability_parent(int nullability: @nullability ref, int index: int ref, int parent: @nullability ref)
+
+type_nullability(int id: @has_type_annotation ref, int nullability: @nullability ref);
+
+/**
+ * The nullable flow state of an expression, as determined by Roslyn.
+ * 0 = none (default, not populated)
+ * 1 = not null
+ * 2 = maybe null
+ */
+expr_flowstate(unique int id: @expr ref, int state: int ref);
+
+/** GENERICS **/
+
+@generic = @type | @method | @local_function;
+
+type_parameters(
+ unique int id: @type_parameter ref,
+ int index: int ref,
+ int generic_id: @generic ref,
+ int variance: int ref /* none = 0, out = 1, in = 2 */);
+
+#keyset[constructed_id, index]
+type_arguments(
+ int id: @type_or_ref ref,
+ int index: int ref,
+ int constructed_id: @generic_or_ref ref);
+
+@generic_or_ref = @generic | @typeref;
+
+constructed_generic(
+ unique int constructed: @generic ref,
+ int generic: @generic_or_ref ref);
+
+type_parameter_constraints(
+ unique int id: @type_parameter_constraints,
+ int param_id: @type_parameter ref);
+
+type_parameter_constraints_location(
+ int id: @type_parameter_constraints ref,
+ int loc: @location ref);
+
+general_type_parameter_constraints(
+ int id: @type_parameter_constraints ref,
+ int kind: int ref /* class = 1, struct = 2, new = 3 */);
+
+specific_type_parameter_constraints(
+ int id: @type_parameter_constraints ref,
+ int base_id: @type_or_ref ref);
+
+specific_type_parameter_nullability(
+ int id: @type_parameter_constraints ref,
+ int base_id: @type_or_ref ref,
+ int nullability: @nullability ref);
+
+/** FUNCTION POINTERS */
+
+function_pointer_calling_conventions(
+ int id: @function_pointer_type ref,
+ int kind: int ref);
+
+#keyset[id, index]
+has_unmanaged_calling_conventions(
+ int id: @function_pointer_type ref,
+ int index: int ref,
+ int conv_id: @type_or_ref ref);
+
+/** MODIFIERS */
+
+@modifiable = @modifiable_direct | @event_accessor;
+
+@modifiable_direct = @member | @accessor | @local_function | @anonymous_function_expr;
+
+modifiers(
+ unique int id: @modifier,
+ string name: string ref);
+
+has_modifiers(
+ int id: @modifiable_direct ref,
+ int mod_id: @modifier ref);
+
+compiler_generated(unique int id: @modifiable ref);
+
+/** MEMBERS **/
+
+@member = @method | @constructor | @destructor | @field | @property | @event | @operator | @indexer | @type;
+
+@named_exprorstmt = @goto_stmt | @labeled_stmt | @expr;
+
+@virtualizable = @method | @property | @indexer | @event;
+
+exprorstmt_name(
+ unique int parent_id: @named_exprorstmt ref,
+ string name: string ref);
+
+nested_types(
+ unique int id: @type ref,
+ int declaring_type_id: @type ref,
+ int unbound_id: @type ref);
+
+properties(
+ unique int id: @property,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @property ref);
+
+property_location(
+ int id: @property ref,
+ int loc: @location ref);
+
+indexers(
+ unique int id: @indexer,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @indexer ref);
+
+indexer_location(
+ int id: @indexer ref,
+ int loc: @location ref);
+
+accessors(
+ unique int id: @accessor,
+ int kind: int ref,
+ string name: string ref,
+ int declaring_member_id: @member ref,
+ int unbound_id: @accessor ref);
+
+case @accessor.kind of
+ 1 = @getter
+| 2 = @setter
+ ;
+
+init_only_accessors(
+ unique int id: @accessor ref);
+
+accessor_location(
+ int id: @accessor ref,
+ int loc: @location ref);
+
+events(
+ unique int id: @event,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @event ref);
+
+event_location(
+ int id: @event ref,
+ int loc: @location ref);
+
+event_accessors(
+ unique int id: @event_accessor,
+ int kind: int ref,
+ string name: string ref,
+ int declaring_event_id: @event ref,
+ int unbound_id: @event_accessor ref);
+
+case @event_accessor.kind of
+ 1 = @add_event_accessor
+| 2 = @remove_event_accessor
+ ;
+
+event_accessor_location(
+ int id: @event_accessor ref,
+ int loc: @location ref);
+
+operators(
+ unique int id: @operator,
+ string name: string ref,
+ string symbol: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @operator ref);
+
+operator_location(
+ int id: @operator ref,
+ int loc: @location ref);
+
+constant_value(
+ int id: @variable ref,
+ string value: string ref);
+
+/** CALLABLES **/
+
+@callable = @method | @constructor | @destructor | @operator | @callable_accessor | @anonymous_function_expr | @local_function;
+
+@callable_accessor = @accessor | @event_accessor;
+
+methods(
+ unique int id: @method,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @method ref);
+
+method_location(
+ int id: @method ref,
+ int loc: @location ref);
+
+constructors(
+ unique int id: @constructor,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int unbound_id: @constructor ref);
+
+constructor_location(
+ int id: @constructor ref,
+ int loc: @location ref);
+
+destructors(
+ unique int id: @destructor,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int unbound_id: @destructor ref);
+
+destructor_location(
+ int id: @destructor ref,
+ int loc: @location ref);
+
+overrides(
+ int id: @callable ref,
+ int base_id: @callable ref);
+
+explicitly_implements(
+ int id: @member ref,
+ int interface_id: @interface_or_ref ref);
+
+local_functions(
+ unique int id: @local_function,
+ string name: string ref,
+ int return_type: @type ref,
+ int unbound_id: @local_function ref);
+
+local_function_stmts(
+ unique int fn: @local_function_stmt ref,
+ int stmt: @local_function ref);
+
+/** VARIABLES **/
+
+@variable = @local_scope_variable | @field;
+
+@local_scope_variable = @local_variable | @parameter;
+
+fields(
+ unique int id: @field,
+ int kind: int ref,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @field ref);
+
+case @field.kind of
+ 1 = @addressable_field
+| 2 = @constant
+ ;
+
+field_location(
+ int id: @field ref,
+ int loc: @location ref);
+
+localvars(
+ unique int id: @local_variable,
+ int kind: int ref,
+ string name: string ref,
+ int implicitly_typed: int ref /* 0 = no, 1 = yes */,
+ int type_id: @type_or_ref ref,
+ int parent_id: @local_var_decl_expr ref);
+
+case @local_variable.kind of
+ 1 = @addressable_local_variable
+| 2 = @local_constant
+| 3 = @local_variable_ref
+ ;
+
+localvar_location(
+ unique int id: @local_variable ref,
+ int loc: @location ref);
+
+@parameterizable = @callable | @delegate_type | @indexer | @function_pointer_type;
+
+#keyset[name, parent_id]
+#keyset[index, parent_id]
+params(
+ unique int id: @parameter,
+ string name: string ref,
+ int type_id: @type_or_ref ref,
+ int index: int ref,
+ int mode: int ref, /* value = 0, ref = 1, out = 2, array = 3, this = 4 */
+ int parent_id: @parameterizable ref,
+ int unbound_id: @parameter ref);
+
+param_location(
+ int id: @parameter ref,
+ int loc: @location ref);
+
+/** STATEMENTS **/
+
+@exprorstmt_parent = @control_flow_element | @top_level_exprorstmt_parent;
+
+statements(
+ unique int id: @stmt,
+ int kind: int ref);
+
+#keyset[index, parent]
+stmt_parent(
+ unique int stmt: @stmt ref,
+ int index: int ref,
+ int parent: @control_flow_element ref);
+
+@top_level_stmt_parent = @callable;
+
+// [index, parent] is not a keyset because the same parent may be compiled multiple times
+stmt_parent_top_level(
+ unique int stmt: @stmt ref,
+ int index: int ref,
+ int parent: @top_level_stmt_parent ref);
+
+case @stmt.kind of
+ 1 = @block_stmt
+| 2 = @expr_stmt
+| 3 = @if_stmt
+| 4 = @switch_stmt
+| 5 = @while_stmt
+| 6 = @do_stmt
+| 7 = @for_stmt
+| 8 = @foreach_stmt
+| 9 = @break_stmt
+| 10 = @continue_stmt
+| 11 = @goto_stmt
+| 12 = @goto_case_stmt
+| 13 = @goto_default_stmt
+| 14 = @throw_stmt
+| 15 = @return_stmt
+| 16 = @yield_stmt
+| 17 = @try_stmt
+| 18 = @checked_stmt
+| 19 = @unchecked_stmt
+| 20 = @lock_stmt
+| 21 = @using_block_stmt
+| 22 = @var_decl_stmt
+| 23 = @const_decl_stmt
+| 24 = @empty_stmt
+| 25 = @unsafe_stmt
+| 26 = @fixed_stmt
+| 27 = @label_stmt
+| 28 = @catch
+| 29 = @case_stmt
+| 30 = @local_function_stmt
+| 31 = @using_decl_stmt
+ ;
+
+@using_stmt = @using_block_stmt | @using_decl_stmt;
+
+@labeled_stmt = @label_stmt | @case;
+
+@decl_stmt = @var_decl_stmt | @const_decl_stmt | @using_decl_stmt;
+
+@cond_stmt = @if_stmt | @switch_stmt;
+
+@loop_stmt = @while_stmt | @do_stmt | @for_stmt | @foreach_stmt;
+
+@jump_stmt = @break_stmt | @goto_any_stmt | @continue_stmt | @throw_stmt | @return_stmt
+ | @yield_stmt;
+
+@goto_any_stmt = @goto_default_stmt | @goto_case_stmt | @goto_stmt;
+
+
+stmt_location(
+ unique int id: @stmt ref,
+ int loc: @location ref);
+
+catch_type(
+ unique int catch_id: @catch ref,
+ int type_id: @type_or_ref ref,
+ int kind: int ref /* explicit = 1, implicit = 2 */);
+
+foreach_stmt_info(
+ unique int id: @foreach_stmt ref,
+ int kind: int ref /* non-async = 1, async = 2 */);
+
+@foreach_symbol = @method | @property | @type_or_ref;
+
+#keyset[id, kind]
+foreach_stmt_desugar(
+ int id: @foreach_stmt ref,
+ int symbol: @foreach_symbol ref,
+ int kind: int ref /* GetEnumeratorMethod = 1, CurrentProperty = 2, MoveNextMethod = 3, DisposeMethod = 4, ElementType = 5 */);
+
+/** EXPRESSIONS **/
+
+expressions(
+ unique int id: @expr,
+ int kind: int ref,
+ int type_id: @type_or_ref ref);
+
+#keyset[index, parent]
+expr_parent(
+ unique int expr: @expr ref,
+ int index: int ref,
+ int parent: @control_flow_element ref);
+
+@top_level_expr_parent = @attribute | @field | @property | @indexer | @parameter | @directive_if | @directive_elif;
+
+@top_level_exprorstmt_parent = @top_level_expr_parent | @top_level_stmt_parent;
+
+// [index, parent] is not a keyset because the same parent may be compiled multiple times
+expr_parent_top_level(
+ unique int expr: @expr ref,
+ int index: int ref,
+ int parent: @top_level_exprorstmt_parent ref);
+
+case @expr.kind of
+/* literal */
+ 1 = @bool_literal_expr
+| 2 = @char_literal_expr
+| 3 = @decimal_literal_expr
+| 4 = @int_literal_expr
+| 5 = @long_literal_expr
+| 6 = @uint_literal_expr
+| 7 = @ulong_literal_expr
+| 8 = @float_literal_expr
+| 9 = @double_literal_expr
+| 10 = @string_literal_expr
+| 11 = @null_literal_expr
+/* primary & unary */
+| 12 = @this_access_expr
+| 13 = @base_access_expr
+| 14 = @local_variable_access_expr
+| 15 = @parameter_access_expr
+| 16 = @field_access_expr
+| 17 = @property_access_expr
+| 18 = @method_access_expr
+| 19 = @event_access_expr
+| 20 = @indexer_access_expr
+| 21 = @array_access_expr
+| 22 = @type_access_expr
+| 23 = @typeof_expr
+| 24 = @method_invocation_expr
+| 25 = @delegate_invocation_expr
+| 26 = @operator_invocation_expr
+| 27 = @cast_expr
+| 28 = @object_creation_expr
+| 29 = @explicit_delegate_creation_expr
+| 30 = @implicit_delegate_creation_expr
+| 31 = @array_creation_expr
+| 32 = @default_expr
+| 33 = @plus_expr
+| 34 = @minus_expr
+| 35 = @bit_not_expr
+| 36 = @log_not_expr
+| 37 = @post_incr_expr
+| 38 = @post_decr_expr
+| 39 = @pre_incr_expr
+| 40 = @pre_decr_expr
+/* multiplicative */
+| 41 = @mul_expr
+| 42 = @div_expr
+| 43 = @rem_expr
+/* additive */
+| 44 = @add_expr
+| 45 = @sub_expr
+/* shift */
+| 46 = @lshift_expr
+| 47 = @rshift_expr
+/* relational */
+| 48 = @lt_expr
+| 49 = @gt_expr
+| 50 = @le_expr
+| 51 = @ge_expr
+/* equality */
+| 52 = @eq_expr
+| 53 = @ne_expr
+/* logical */
+| 54 = @bit_and_expr
+| 55 = @bit_xor_expr
+| 56 = @bit_or_expr
+| 57 = @log_and_expr
+| 58 = @log_or_expr
+/* type testing */
+| 59 = @is_expr
+| 60 = @as_expr
+/* null coalescing */
+| 61 = @null_coalescing_expr
+/* conditional */
+| 62 = @conditional_expr
+/* assignment */
+| 63 = @simple_assign_expr
+| 64 = @assign_add_expr
+| 65 = @assign_sub_expr
+| 66 = @assign_mul_expr
+| 67 = @assign_div_expr
+| 68 = @assign_rem_expr
+| 69 = @assign_and_expr
+| 70 = @assign_xor_expr
+| 71 = @assign_or_expr
+| 72 = @assign_lshift_expr
+| 73 = @assign_rshift_expr
+/* more */
+| 74 = @object_init_expr
+| 75 = @collection_init_expr
+| 76 = @array_init_expr
+| 77 = @checked_expr
+| 78 = @unchecked_expr
+| 79 = @constructor_init_expr
+| 80 = @add_event_expr
+| 81 = @remove_event_expr
+| 82 = @par_expr
+| 83 = @local_var_decl_expr
+| 84 = @lambda_expr
+| 85 = @anonymous_method_expr
+| 86 = @namespace_expr
+/* dynamic */
+| 92 = @dynamic_element_access_expr
+| 93 = @dynamic_member_access_expr
+/* unsafe */
+| 100 = @pointer_indirection_expr
+| 101 = @address_of_expr
+| 102 = @sizeof_expr
+/* async */
+| 103 = @await_expr
+/* C# 6.0 */
+| 104 = @nameof_expr
+| 105 = @interpolated_string_expr
+| 106 = @unknown_expr
+/* C# 7.0 */
+| 107 = @throw_expr
+| 108 = @tuple_expr
+| 109 = @local_function_invocation_expr
+| 110 = @ref_expr
+| 111 = @discard_expr
+/* C# 8.0 */
+| 112 = @range_expr
+| 113 = @index_expr
+| 114 = @switch_expr
+| 115 = @recursive_pattern_expr
+| 116 = @property_pattern_expr
+| 117 = @positional_pattern_expr
+| 118 = @switch_case_expr
+| 119 = @assign_coalesce_expr
+| 120 = @suppress_nullable_warning_expr
+| 121 = @namespace_access_expr
+/* C# 9.0 */
+| 122 = @lt_pattern_expr
+| 123 = @gt_pattern_expr
+| 124 = @le_pattern_expr
+| 125 = @ge_pattern_expr
+| 126 = @not_pattern_expr
+| 127 = @and_pattern_expr
+| 128 = @or_pattern_expr
+| 129 = @function_pointer_invocation_expr
+| 130 = @with_expr
+/* C# 11.0 */
+| 131 = @list_pattern_expr
+| 132 = @slice_pattern_expr
+| 133 = @urshift_expr
+| 134 = @assign_urshift_expr
+/* Preprocessor */
+| 999 = @define_symbol_expr
+;
+
+@switch = @switch_stmt | @switch_expr;
+@case = @case_stmt | @switch_case_expr;
+@pattern_match = @case | @is_expr;
+@unary_pattern_expr = @not_pattern_expr;
+@relational_pattern_expr = @gt_pattern_expr | @lt_pattern_expr | @ge_pattern_expr | @le_pattern_expr;
+@binary_pattern_expr = @and_pattern_expr | @or_pattern_expr;
+
+@integer_literal_expr = @int_literal_expr | @long_literal_expr | @uint_literal_expr | @ulong_literal_expr;
+@real_literal_expr = @float_literal_expr | @double_literal_expr | @decimal_literal_expr;
+@literal_expr = @bool_literal_expr | @char_literal_expr | @integer_literal_expr | @real_literal_expr
+ | @string_literal_expr | @null_literal_expr;
+
+@assign_expr = @simple_assign_expr | @assign_op_expr | @local_var_decl_expr;
+@assign_op_expr = @assign_arith_expr | @assign_bitwise_expr | @assign_event_expr | @assign_coalesce_expr;
+@assign_event_expr = @add_event_expr | @remove_event_expr;
+
+@assign_arith_expr = @assign_add_expr | @assign_sub_expr | @assign_mul_expr | @assign_div_expr
+ | @assign_rem_expr
+@assign_bitwise_expr = @assign_and_expr | @assign_or_expr | @assign_xor_expr
+ | @assign_lshift_expr | @assign_rshift_expr | @assign_urshift_expr;
+
+@member_access_expr = @field_access_expr | @property_access_expr | @indexer_access_expr | @event_access_expr
+ | @method_access_expr | @type_access_expr | @dynamic_member_access_expr;
+@access_expr = @member_access_expr | @this_access_expr | @base_access_expr | @assignable_access_expr | @namespace_access_expr;
+@element_access_expr = @indexer_access_expr | @array_access_expr | @dynamic_element_access_expr;
+
+@local_variable_access = @local_variable_access_expr | @local_var_decl_expr;
+@local_scope_variable_access_expr = @parameter_access_expr | @local_variable_access;
+@variable_access_expr = @local_scope_variable_access_expr | @field_access_expr;
+
+@assignable_access_expr = @variable_access_expr | @property_access_expr | @element_access_expr
+ | @event_access_expr | @dynamic_member_access_expr;
+
+@objectorcollection_init_expr = @object_init_expr | @collection_init_expr;
+
+@delegate_creation_expr = @explicit_delegate_creation_expr | @implicit_delegate_creation_expr;
+
+@bin_arith_op_expr = @mul_expr | @div_expr | @rem_expr | @add_expr | @sub_expr;
+@incr_op_expr = @pre_incr_expr | @post_incr_expr;
+@decr_op_expr = @pre_decr_expr | @post_decr_expr;
+@mut_op_expr = @incr_op_expr | @decr_op_expr;
+@un_arith_op_expr = @plus_expr | @minus_expr | @mut_op_expr;
+@arith_op_expr = @bin_arith_op_expr | @un_arith_op_expr;
+
+@ternary_log_op_expr = @conditional_expr;
+@bin_log_op_expr = @log_and_expr | @log_or_expr | @null_coalescing_expr;
+@un_log_op_expr = @log_not_expr;
+@log_expr = @un_log_op_expr | @bin_log_op_expr | @ternary_log_op_expr;
+
+@bin_bit_op_expr = @bit_and_expr | @bit_or_expr | @bit_xor_expr | @lshift_expr
+ | @rshift_expr | @urshift_expr;
+@un_bit_op_expr = @bit_not_expr;
+@bit_expr = @un_bit_op_expr | @bin_bit_op_expr;
+
+@equality_op_expr = @eq_expr | @ne_expr;
+@rel_op_expr = @gt_expr | @lt_expr| @ge_expr | @le_expr;
+@comp_expr = @equality_op_expr | @rel_op_expr;
+
+@op_expr = @assign_expr | @un_op | @bin_op | @ternary_op;
+
+@ternary_op = @ternary_log_op_expr;
+@bin_op = @bin_arith_op_expr | @bin_log_op_expr | @bin_bit_op_expr | @comp_expr;
+@un_op = @un_arith_op_expr | @un_log_op_expr | @un_bit_op_expr | @sizeof_expr
+ | @pointer_indirection_expr | @address_of_expr;
+
+@anonymous_function_expr = @lambda_expr | @anonymous_method_expr;
+
+@call = @method_invocation_expr | @constructor_init_expr | @operator_invocation_expr
+ | @delegate_invocation_expr | @object_creation_expr | @call_access_expr
+ | @local_function_invocation_expr | @function_pointer_invocation_expr;
+
+@call_access_expr = @property_access_expr | @event_access_expr | @indexer_access_expr;
+
+@late_bindable_expr = @dynamic_element_access_expr | @dynamic_member_access_expr
+ | @object_creation_expr | @method_invocation_expr | @operator_invocation_expr;
+
+@throw_element = @throw_expr | @throw_stmt;
+
+@implicitly_typeable_object_creation_expr = @object_creation_expr | @explicit_delegate_creation_expr;
+
+implicitly_typed_array_creation(
+ unique int id: @array_creation_expr ref);
+
+explicitly_sized_array_creation(
+ unique int id: @array_creation_expr ref);
+
+stackalloc_array_creation(
+ unique int id: @array_creation_expr ref);
+
+implicitly_typed_object_creation(
+ unique int id: @implicitly_typeable_object_creation_expr ref);
+
+mutator_invocation_mode(
+ unique int id: @operator_invocation_expr ref,
+ int mode: int ref /* prefix = 1, postfix = 2*/);
+
+expr_compiler_generated(
+ unique int id: @expr ref);
+
+expr_value(
+ unique int id: @expr ref,
+ string value: string ref);
+
+expr_call(
+ unique int caller_id: @expr ref,
+ int target_id: @callable ref);
+
+expr_access(
+ unique int accesser_id: @access_expr ref,
+ int target_id: @accessible ref);
+
+@accessible = @method | @assignable | @local_function | @namespace;
+
+expr_location(
+ unique int id: @expr ref,
+ int loc: @location ref);
+
+dynamic_member_name(
+ unique int id: @late_bindable_expr ref,
+ string name: string ref);
+
+@qualifiable_expr = @member_access_expr
+ | @method_invocation_expr
+ | @element_access_expr;
+
+conditional_access(
+ unique int id: @qualifiable_expr ref);
+
+expr_argument(
+ unique int id: @expr ref,
+ int mode: int ref);
+ /* mode is the same as params: value = 0, ref = 1, out = 2 */
+
+expr_argument_name(
+ unique int id: @expr ref,
+ string name: string ref);
+
+lambda_expr_return_type(
+ unique int id: @lambda_expr ref,
+ int type_id: @type_or_ref ref);
+
+/** CONTROL/DATA FLOW **/
+
+@control_flow_element = @stmt | @expr;
+
+/* XML Files */
+
+xmlEncoding (
+ unique int id: @file ref,
+ string encoding: string ref);
+
+xmlDTDs(
+ unique int id: @xmldtd,
+ string root: string ref,
+ string publicId: string ref,
+ string systemId: string ref,
+ int fileid: @file ref);
+
+xmlElements(
+ unique int id: @xmlelement,
+ string name: string ref,
+ int parentid: @xmlparent ref,
+ int idx: int ref,
+ int fileid: @file ref);
+
+xmlAttrs(
+ unique int id: @xmlattribute,
+ int elementid: @xmlelement ref,
+ string name: string ref,
+ string value: string ref,
+ int idx: int ref,
+ int fileid: @file ref);
+
+xmlNs(
+ int id: @xmlnamespace,
+ string prefixName: string ref,
+ string URI: string ref,
+ int fileid: @file ref);
+
+xmlHasNs(
+ int elementId: @xmlnamespaceable ref,
+ int nsId: @xmlnamespace ref,
+ int fileid: @file ref);
+
+xmlComments(
+ unique int id: @xmlcomment,
+ string text: string ref,
+ int parentid: @xmlparent ref,
+ int fileid: @file ref);
+
+xmlChars(
+ unique int id: @xmlcharacters,
+ string text: string ref,
+ int parentid: @xmlparent ref,
+ int idx: int ref,
+ int isCDATA: int ref,
+ int fileid: @file ref);
+
+@xmlparent = @file | @xmlelement;
+@xmlnamespaceable = @xmlelement | @xmlattribute;
+
+xmllocations(
+ int xmlElement: @xmllocatable ref,
+ int location: @location_default ref);
+
+@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace;
+
+/* Comments */
+
+commentline(
+ unique int id: @commentline,
+ int kind: int ref,
+ string text: string ref,
+ string rawtext: string ref);
+
+case @commentline.kind of
+ 0 = @singlelinecomment
+| 1 = @xmldoccomment
+| 2 = @multilinecomment;
+
+commentline_location(
+ unique int id: @commentline ref,
+ int loc: @location ref);
+
+commentblock(
+ unique int id : @commentblock);
+
+commentblock_location(
+ unique int id: @commentblock ref,
+ int loc: @location ref);
+
+commentblock_binding(
+ int id: @commentblock ref,
+ int entity: @element ref,
+ int bindtype: int ref); /* 0: Parent, 1: Best, 2: Before, 3: After */
+
+commentblock_child(
+ int id: @commentblock ref,
+ int commentline: @commentline ref,
+ int index: int ref);
+
+/* ASP.NET */
+
+case @asp_element.kind of
+ 0=@asp_close_tag
+| 1=@asp_code
+| 2=@asp_comment
+| 3=@asp_data_binding
+| 4=@asp_directive
+| 5=@asp_open_tag
+| 6=@asp_quoted_string
+| 7=@asp_text
+| 8=@asp_xml_directive;
+
+@asp_attribute = @asp_code | @asp_data_binding | @asp_quoted_string;
+
+asp_elements(
+ unique int id: @asp_element,
+ int kind: int ref,
+ int loc: @location ref);
+
+asp_comment_server(unique int comment: @asp_comment ref);
+asp_code_inline(unique int code: @asp_code ref);
+asp_directive_attribute(
+ int directive: @asp_directive ref,
+ int index: int ref,
+ string name: string ref,
+ int value: @asp_quoted_string ref);
+asp_directive_name(
+ unique int directive: @asp_directive ref,
+ string name: string ref);
+asp_element_body(
+ unique int element: @asp_element ref,
+ string body: string ref);
+asp_tag_attribute(
+ int tag: @asp_open_tag ref,
+ int index: int ref,
+ string name: string ref,
+ int attribute: @asp_attribute ref);
+asp_tag_name(
+ unique int tag: @asp_open_tag ref,
+ string name: string ref);
+asp_tag_isempty(int tag: @asp_open_tag ref);
+
+/* Common Intermediate Language - CIL */
+
+case @cil_instruction.opcode of
+ 0 = @cil_nop
+| 1 = @cil_break
+| 2 = @cil_ldarg_0
+| 3 = @cil_ldarg_1
+| 4 = @cil_ldarg_2
+| 5 = @cil_ldarg_3
+| 6 = @cil_ldloc_0
+| 7 = @cil_ldloc_1
+| 8 = @cil_ldloc_2
+| 9 = @cil_ldloc_3
+| 10 = @cil_stloc_0
+| 11 = @cil_stloc_1
+| 12 = @cil_stloc_2
+| 13 = @cil_stloc_3
+| 14 = @cil_ldarg_s
+| 15 = @cil_ldarga_s
+| 16 = @cil_starg_s
+| 17 = @cil_ldloc_s
+| 18 = @cil_ldloca_s
+| 19 = @cil_stloc_s
+| 20 = @cil_ldnull
+| 21 = @cil_ldc_i4_m1
+| 22 = @cil_ldc_i4_0
+| 23 = @cil_ldc_i4_1
+| 24 = @cil_ldc_i4_2
+| 25 = @cil_ldc_i4_3
+| 26 = @cil_ldc_i4_4
+| 27 = @cil_ldc_i4_5
+| 28 = @cil_ldc_i4_6
+| 29 = @cil_ldc_i4_7
+| 30 = @cil_ldc_i4_8
+| 31 = @cil_ldc_i4_s
+| 32 = @cil_ldc_i4
+| 33 = @cil_ldc_i8
+| 34 = @cil_ldc_r4
+| 35 = @cil_ldc_r8
+| 37 = @cil_dup
+| 38 = @cil_pop
+| 39 = @cil_jmp
+| 40 = @cil_call
+| 41 = @cil_calli
+| 42 = @cil_ret
+| 43 = @cil_br_s
+| 44 = @cil_brfalse_s
+| 45 = @cil_brtrue_s
+| 46 = @cil_beq_s
+| 47 = @cil_bge_s
+| 48 = @cil_bgt_s
+| 49 = @cil_ble_s
+| 50 = @cil_blt_s
+| 51 = @cil_bne_un_s
+| 52 = @cil_bge_un_s
+| 53 = @cil_bgt_un_s
+| 54 = @cil_ble_un_s
+| 55 = @cil_blt_un_s
+| 56 = @cil_br
+| 57 = @cil_brfalse
+| 58 = @cil_brtrue
+| 59 = @cil_beq
+| 60 = @cil_bge
+| 61 = @cil_bgt
+| 62 = @cil_ble
+| 63 = @cil_blt
+| 64 = @cil_bne_un
+| 65 = @cil_bge_un
+| 66 = @cil_bgt_un
+| 67 = @cil_ble_un
+| 68 = @cil_blt_un
+| 69 = @cil_switch
+| 70 = @cil_ldind_i1
+| 71 = @cil_ldind_u1
+| 72 = @cil_ldind_i2
+| 73 = @cil_ldind_u2
+| 74 = @cil_ldind_i4
+| 75 = @cil_ldind_u4
+| 76 = @cil_ldind_i8
+| 77 = @cil_ldind_i
+| 78 = @cil_ldind_r4
+| 79 = @cil_ldind_r8
+| 80 = @cil_ldind_ref
+| 81 = @cil_stind_ref
+| 82 = @cil_stind_i1
+| 83 = @cil_stind_i2
+| 84 = @cil_stind_i4
+| 85 = @cil_stind_i8
+| 86 = @cil_stind_r4
+| 87 = @cil_stind_r8
+| 88 = @cil_add
+| 89 = @cil_sub
+| 90 = @cil_mul
+| 91 = @cil_div
+| 92 = @cil_div_un
+| 93 = @cil_rem
+| 94 = @cil_rem_un
+| 95 = @cil_and
+| 96 = @cil_or
+| 97 = @cil_xor
+| 98 = @cil_shl
+| 99 = @cil_shr
+| 100 = @cil_shr_un
+| 101 = @cil_neg
+| 102 = @cil_not
+| 103 = @cil_conv_i1
+| 104 = @cil_conv_i2
+| 105 = @cil_conv_i4
+| 106 = @cil_conv_i8
+| 107 = @cil_conv_r4
+| 108 = @cil_conv_r8
+| 109 = @cil_conv_u4
+| 110 = @cil_conv_u8
+| 111 = @cil_callvirt
+| 112 = @cil_cpobj
+| 113 = @cil_ldobj
+| 114 = @cil_ldstr
+| 115 = @cil_newobj
+| 116 = @cil_castclass
+| 117 = @cil_isinst
+| 118 = @cil_conv_r_un
+| 121 = @cil_unbox
+| 122 = @cil_throw
+| 123 = @cil_ldfld
+| 124 = @cil_ldflda
+| 125 = @cil_stfld
+| 126 = @cil_ldsfld
+| 127 = @cil_ldsflda
+| 128 = @cil_stsfld
+| 129 = @cil_stobj
+| 130 = @cil_conv_ovf_i1_un
+| 131 = @cil_conv_ovf_i2_un
+| 132 = @cil_conv_ovf_i4_un
+| 133 = @cil_conv_ovf_i8_un
+| 134 = @cil_conv_ovf_u1_un
+| 135 = @cil_conv_ovf_u2_un
+| 136 = @cil_conv_ovf_u4_un
+| 137 = @cil_conv_ovf_u8_un
+| 138 = @cil_conv_ovf_i_un
+| 139 = @cil_conv_ovf_u_un
+| 140 = @cil_box
+| 141 = @cil_newarr
+| 142 = @cil_ldlen
+| 143 = @cil_ldelema
+| 144 = @cil_ldelem_i1
+| 145 = @cil_ldelem_u1
+| 146 = @cil_ldelem_i2
+| 147 = @cil_ldelem_u2
+| 148 = @cil_ldelem_i4
+| 149 = @cil_ldelem_u4
+| 150 = @cil_ldelem_i8
+| 151 = @cil_ldelem_i
+| 152 = @cil_ldelem_r4
+| 153 = @cil_ldelem_r8
+| 154 = @cil_ldelem_ref
+| 155 = @cil_stelem_i
+| 156 = @cil_stelem_i1
+| 157 = @cil_stelem_i2
+| 158 = @cil_stelem_i4
+| 159 = @cil_stelem_i8
+| 160 = @cil_stelem_r4
+| 161 = @cil_stelem_r8
+| 162 = @cil_stelem_ref
+| 163 = @cil_ldelem
+| 164 = @cil_stelem
+| 165 = @cil_unbox_any
+| 179 = @cil_conv_ovf_i1
+| 180 = @cil_conv_ovf_u1
+| 181 = @cil_conv_ovf_i2
+| 182 = @cil_conv_ovf_u2
+| 183 = @cil_conv_ovf_i4
+| 184 = @cil_conv_ovf_u4
+| 185 = @cil_conv_ovf_i8
+| 186 = @cil_conv_ovf_u8
+| 194 = @cil_refanyval
+| 195 = @cil_ckinfinite
+| 198 = @cil_mkrefany
+| 208 = @cil_ldtoken
+| 209 = @cil_conv_u2
+| 210 = @cil_conv_u1
+| 211 = @cil_conv_i
+| 212 = @cil_conv_ovf_i
+| 213 = @cil_conv_ovf_u
+| 214 = @cil_add_ovf
+| 215 = @cil_add_ovf_un
+| 216 = @cil_mul_ovf
+| 217 = @cil_mul_ovf_un
+| 218 = @cil_sub_ovf
+| 219 = @cil_sub_ovf_un
+| 220 = @cil_endfinally
+| 221 = @cil_leave
+| 222 = @cil_leave_s
+| 223 = @cil_stind_i
+| 224 = @cil_conv_u
+| 65024 = @cil_arglist
+| 65025 = @cil_ceq
+| 65026 = @cil_cgt
+| 65027 = @cil_cgt_un
+| 65028 = @cil_clt
+| 65029 = @cil_clt_un
+| 65030 = @cil_ldftn
+| 65031 = @cil_ldvirtftn
+| 65033 = @cil_ldarg
+| 65034 = @cil_ldarga
+| 65035 = @cil_starg
+| 65036 = @cil_ldloc
+| 65037 = @cil_ldloca
+| 65038 = @cil_stloc
+| 65039 = @cil_localloc
+| 65041 = @cil_endfilter
+| 65042 = @cil_unaligned
+| 65043 = @cil_volatile
+| 65044 = @cil_tail
+| 65045 = @cil_initobj
+| 65046 = @cil_constrained
+| 65047 = @cil_cpblk
+| 65048 = @cil_initblk
+| 65050 = @cil_rethrow
+| 65052 = @cil_sizeof
+| 65053 = @cil_refanytype
+| 65054 = @cil_readonly
+;
+
+// CIL ignored instructions
+
+@cil_ignore = @cil_nop | @cil_break | @cil_volatile | @cil_unaligned;
+
+// CIL local/parameter/field access
+
+@cil_ldarg_any = @cil_ldarg_0 | @cil_ldarg_1 | @cil_ldarg_2 | @cil_ldarg_3 | @cil_ldarg_s | @cil_ldarga_s | @cil_ldarg | @cil_ldarga;
+@cil_starg_any = @cil_starg | @cil_starg_s;
+
+@cil_ldloc_any = @cil_ldloc_0 | @cil_ldloc_1 | @cil_ldloc_2 | @cil_ldloc_3 | @cil_ldloc_s | @cil_ldloca_s | @cil_ldloc | @cil_ldloca;
+@cil_stloc_any = @cil_stloc_0 | @cil_stloc_1 | @cil_stloc_2 | @cil_stloc_3 | @cil_stloc_s | @cil_stloc;
+
+@cil_ldfld_any = @cil_ldfld | @cil_ldsfld | @cil_ldsflda | @cil_ldflda;
+@cil_stfld_any = @cil_stfld | @cil_stsfld;
+
+@cil_local_access = @cil_stloc_any | @cil_ldloc_any;
+@cil_arg_access = @cil_starg_any | @cil_ldarg_any;
+@cil_read_access = @cil_ldloc_any | @cil_ldarg_any | @cil_ldfld_any;
+@cil_write_access = @cil_stloc_any | @cil_starg_any | @cil_stfld_any;
+
+@cil_stack_access = @cil_local_access | @cil_arg_access;
+@cil_field_access = @cil_ldfld_any | @cil_stfld_any;
+
+@cil_access = @cil_read_access | @cil_write_access;
+
+// CIL constant/literal instructions
+
+@cil_ldc_i = @cil_ldc_i4_any | @cil_ldc_i8;
+
+@cil_ldc_i4_any = @cil_ldc_i4_m1 | @cil_ldc_i4_0 | @cil_ldc_i4_1 | @cil_ldc_i4_2 | @cil_ldc_i4_3 |
+ @cil_ldc_i4_4 | @cil_ldc_i4_5 | @cil_ldc_i4_6 | @cil_ldc_i4_7 | @cil_ldc_i4_8 | @cil_ldc_i4_s | @cil_ldc_i4;
+
+@cil_ldc_r = @cil_ldc_r4 | @cil_ldc_r8;
+
+@cil_literal = @cil_ldnull | @cil_ldc_i | @cil_ldc_r | @cil_ldstr;
+
+// Control flow
+
+@cil_conditional_jump = @cil_binary_jump | @cil_unary_jump;
+@cil_binary_jump = @cil_beq_s | @cil_bge_s | @cil_bgt_s | @cil_ble_s | @cil_blt_s |
+ @cil_bne_un_s | @cil_bge_un_s | @cil_bgt_un_s | @cil_ble_un_s | @cil_blt_un_s |
+ @cil_beq | @cil_bge | @cil_bgt | @cil_ble | @cil_blt |
+ @cil_bne_un | @cil_bge_un | @cil_bgt_un | @cil_ble_un | @cil_blt_un;
+@cil_unary_jump = @cil_brfalse_s | @cil_brtrue_s | @cil_brfalse | @cil_brtrue | @cil_switch;
+@cil_unconditional_jump = @cil_br | @cil_br_s | @cil_leave_any;
+@cil_leave_any = @cil_leave | @cil_leave_s;
+@cil_jump = @cil_unconditional_jump | @cil_conditional_jump;
+
+// CIL call instructions
+
+@cil_call_any = @cil_jmp | @cil_call | @cil_calli | @cil_tail | @cil_callvirt | @cil_newobj;
+
+// CIL expression instructions
+
+@cil_expr = @cil_literal | @cil_binary_expr | @cil_unary_expr | @cil_call_any | @cil_read_access |
+ @cil_newarr | @cil_ldtoken | @cil_sizeof |
+ @cil_ldftn | @cil_ldvirtftn | @cil_localloc | @cil_mkrefany | @cil_refanytype | @cil_arglist | @cil_dup;
+
+@cil_unary_expr =
+ @cil_conversion_operation | @cil_unary_arithmetic_operation | @cil_unary_bitwise_operation|
+ @cil_ldlen | @cil_isinst | @cil_box | @cil_ldobj | @cil_castclass | @cil_unbox_any |
+ @cil_ldind | @cil_unbox;
+
+@cil_conversion_operation =
+ @cil_conv_i1 | @cil_conv_i2 | @cil_conv_i4 | @cil_conv_i8 |
+ @cil_conv_u1 | @cil_conv_u2 | @cil_conv_u4 | @cil_conv_u8 |
+ @cil_conv_ovf_i | @cil_conv_ovf_i_un | @cil_conv_ovf_i1 | @cil_conv_ovf_i1_un |
+ @cil_conv_ovf_i2 | @cil_conv_ovf_i2_un | @cil_conv_ovf_i4 | @cil_conv_ovf_i4_un |
+ @cil_conv_ovf_i8 | @cil_conv_ovf_i8_un | @cil_conv_ovf_u | @cil_conv_ovf_u_un |
+ @cil_conv_ovf_u1 | @cil_conv_ovf_u1_un | @cil_conv_ovf_u2 | @cil_conv_ovf_u2_un |
+ @cil_conv_ovf_u4 | @cil_conv_ovf_u4_un | @cil_conv_ovf_u8 | @cil_conv_ovf_u8_un |
+ @cil_conv_r4 | @cil_conv_r8 | @cil_conv_ovf_u2 | @cil_conv_ovf_u2_un |
+ @cil_conv_i | @cil_conv_u | @cil_conv_r_un;
+
+@cil_ldind = @cil_ldind_i | @cil_ldind_i1 | @cil_ldind_i2 | @cil_ldind_i4 | @cil_ldind_i8 |
+ @cil_ldind_r4 | @cil_ldind_r8 | @cil_ldind_ref | @cil_ldind_u1 | @cil_ldind_u2 | @cil_ldind_u4;
+
+@cil_stind = @cil_stind_i | @cil_stind_i1 | @cil_stind_i2 | @cil_stind_i4 | @cil_stind_i8 |
+ @cil_stind_r4 | @cil_stind_r8 | @cil_stind_ref;
+
+@cil_bitwise_operation = @cil_binary_bitwise_operation | @cil_unary_bitwise_operation;
+
+@cil_binary_bitwise_operation = @cil_and | @cil_or | @cil_xor | @cil_shr | @cil_shr | @cil_shr_un | @cil_shl;
+
+@cil_binary_arithmetic_operation = @cil_add | @cil_sub | @cil_mul | @cil_div | @cil_div_un |
+ @cil_rem | @cil_rem_un | @cil_add_ovf | @cil_add_ovf_un | @cil_mul_ovf | @cil_mul_ovf_un |
+ @cil_sub_ovf | @cil_sub_ovf_un;
+
+@cil_unary_bitwise_operation = @cil_not;
+
+@cil_binary_expr = @cil_binary_arithmetic_operation | @cil_binary_bitwise_operation | @cil_read_array | @cil_comparison_operation;
+
+@cil_unary_arithmetic_operation = @cil_neg;
+
+@cil_comparison_operation = @cil_cgt_un | @cil_ceq | @cil_cgt | @cil_clt | @cil_clt_un;
+
+// Elements that retrieve an address of something
+@cil_read_ref = @cil_ldloca_s | @cil_ldarga_s | @cil_ldflda | @cil_ldsflda | @cil_ldelema;
+
+// CIL array instructions
+
+@cil_read_array =
+ @cil_ldelem | @cil_ldelema | @cil_ldelem_i1 | @cil_ldelem_ref | @cil_ldelem_i |
+ @cil_ldelem_i1 | @cil_ldelem_i2 | @cil_ldelem_i4 | @cil_ldelem_i8 | @cil_ldelem_r4 |
+ @cil_ldelem_r8 | @cil_ldelem_u1 | @cil_ldelem_u2 | @cil_ldelem_u4;
+
+@cil_write_array = @cil_stelem | @cil_stelem_ref |
+ @cil_stelem_i | @cil_stelem_i1 | @cil_stelem_i2 | @cil_stelem_i4 | @cil_stelem_i8 |
+ @cil_stelem_r4 | @cil_stelem_r8;
+
+@cil_throw_any = @cil_throw | @cil_rethrow;
+
+#keyset[impl, index]
+cil_instruction(
+ unique int id: @cil_instruction,
+ int opcode: int ref,
+ int index: int ref,
+ int impl: @cil_method_implementation ref);
+
+cil_jump(
+ unique int instruction: @cil_jump ref,
+ int target: @cil_instruction ref);
+
+cil_access(
+ unique int instruction: @cil_instruction ref,
+ int target: @cil_accessible ref);
+
+cil_value(
+ unique int instruction: @cil_literal ref,
+ string value: string ref);
+
+#keyset[instruction, index]
+cil_switch(
+ int instruction: @cil_switch ref,
+ int index: int ref,
+ int target: @cil_instruction ref);
+
+cil_instruction_location(
+ unique int id: @cil_instruction ref,
+ int loc: @location ref);
+
+cil_type_location(
+ int id: @cil_type ref,
+ int loc: @location ref);
+
+cil_method_location(
+ int id: @cil_method ref,
+ int loc: @location ref);
+
+@cil_namespace = @namespace;
+
+@cil_type_container = @cil_type | @cil_namespace | @cil_method;
+
+case @cil_type.kind of
+ 0 = @cil_valueorreftype
+| 1 = @cil_typeparameter
+| 2 = @cil_array_type
+| 3 = @cil_pointer_type
+| 4 = @cil_function_pointer_type
+;
+
+cil_type(
+ unique int id: @cil_type,
+ string name: string ref,
+ int kind: int ref,
+ int parent: @cil_type_container ref,
+ int sourceDecl: @cil_type ref);
+
+cil_pointer_type(
+ unique int id: @cil_pointer_type ref,
+ int pointee: @cil_type ref);
+
+cil_array_type(
+ unique int id: @cil_array_type ref,
+ int element_type: @cil_type ref,
+ int rank: int ref);
+
+cil_function_pointer_return_type(
+ unique int id: @cil_function_pointer_type ref,
+ int return_type: @cil_type ref);
+
+cil_method(
+ unique int id: @cil_method,
+ string name: string ref,
+ int parent: @cil_type ref,
+ int return_type: @cil_type ref);
+
+cil_method_source_declaration(
+ unique int method: @cil_method ref,
+ int source: @cil_method ref);
+
+cil_method_implementation(
+ unique int id: @cil_method_implementation,
+ int method: @cil_method ref,
+ int location: @assembly ref);
+
+cil_implements(
+ int id: @cil_method ref,
+ int decl: @cil_method ref);
+
+#keyset[parent, name]
+cil_field(
+ unique int id: @cil_field,
+ int parent: @cil_type ref,
+ string name: string ref,
+ int field_type: @cil_type ref);
+
+@cil_element = @cil_instruction | @cil_declaration | @cil_handler | @cil_attribute | @cil_namespace;
+@cil_named_element = @cil_declaration | @cil_namespace;
+@cil_declaration = @cil_variable | @cil_method | @cil_type | @cil_member;
+@cil_accessible = @cil_declaration;
+@cil_variable = @cil_field | @cil_stack_variable;
+@cil_stack_variable = @cil_local_variable | @cil_parameter;
+@cil_member = @cil_method | @cil_type | @cil_field | @cil_property | @cil_event;
+@cil_custom_modifier_receiver = @cil_method | @cil_property | @cil_parameter | @cil_field | @cil_function_pointer_type;
+@cil_parameterizable = @cil_method | @cil_function_pointer_type;
+@cil_has_type_annotation = @cil_stack_variable | @cil_property | @cil_method | @cil_function_pointer_type;
+
+#keyset[parameterizable, index]
+cil_parameter(
+ unique int id: @cil_parameter,
+ int parameterizable: @cil_parameterizable ref,
+ int index: int ref,
+ int param_type: @cil_type ref);
+
+cil_parameter_in(unique int id: @cil_parameter ref);
+cil_parameter_out(unique int id: @cil_parameter ref);
+
+cil_setter(unique int prop: @cil_property ref,
+ int method: @cil_method ref);
+
+#keyset[id, modifier]
+cil_custom_modifiers(
+ int id: @cil_custom_modifier_receiver ref,
+ int modifier: @cil_type ref,
+ int kind: int ref); // modreq: 1, modopt: 0
+
+cil_type_annotation(
+ int id: @cil_has_type_annotation ref,
+ int annotation: int ref);
+
+cil_getter(unique int prop: @cil_property ref,
+ int method: @cil_method ref);
+
+cil_adder(unique int event: @cil_event ref,
+ int method: @cil_method ref);
+
+cil_remover(unique int event: @cil_event ref, int method: @cil_method ref);
+
+cil_raiser(unique int event: @cil_event ref, int method: @cil_method ref);
+
+cil_property(
+ unique int id: @cil_property,
+ int parent: @cil_type ref,
+ string name: string ref,
+ int property_type: @cil_type ref);
+
+#keyset[parent, name]
+cil_event(unique int id: @cil_event,
+ int parent: @cil_type ref,
+ string name: string ref,
+ int event_type: @cil_type ref);
+
+#keyset[impl, index]
+cil_local_variable(
+ unique int id: @cil_local_variable,
+ int impl: @cil_method_implementation ref,
+ int index: int ref,
+ int var_type: @cil_type ref);
+
+cil_function_pointer_calling_conventions(
+ int id: @cil_function_pointer_type ref,
+ int kind: int ref);
+
+// CIL handlers (exception handlers etc).
+
+case @cil_handler.kind of
+ 0 = @cil_catch_handler
+| 1 = @cil_filter_handler
+| 2 = @cil_finally_handler
+| 4 = @cil_fault_handler
+;
+
+#keyset[impl, index]
+cil_handler(
+ unique int id: @cil_handler,
+ int impl: @cil_method_implementation ref,
+ int index: int ref,
+ int kind: int ref,
+ int try_start: @cil_instruction ref,
+ int try_end: @cil_instruction ref,
+ int handler_start: @cil_instruction ref);
+
+cil_handler_filter(
+ unique int id: @cil_handler ref,
+ int filter_start: @cil_instruction ref);
+
+cil_handler_type(
+ unique int id: @cil_handler ref,
+ int catch_type: @cil_type ref);
+
+@cil_controlflow_node = @cil_entry_point | @cil_instruction;
+
+@cil_entry_point = @cil_method_implementation | @cil_handler;
+
+@cil_dataflow_node = @cil_instruction | @cil_variable | @cil_method;
+
+cil_method_stack_size(
+ unique int method: @cil_method_implementation ref,
+ int size: int ref);
+
+// CIL modifiers
+
+cil_public(int id: @cil_member ref);
+cil_private(int id: @cil_member ref);
+cil_protected(int id: @cil_member ref);
+cil_internal(int id: @cil_member ref);
+cil_static(int id: @cil_member ref);
+cil_sealed(int id: @cil_member ref);
+cil_virtual(int id: @cil_method ref);
+cil_abstract(int id: @cil_member ref);
+cil_class(int id: @cil_type ref);
+cil_interface(int id: @cil_type ref);
+cil_security(int id: @cil_member ref);
+cil_requiresecobject(int id: @cil_method ref);
+cil_specialname(int id: @cil_method ref);
+cil_newslot(int id: @cil_method ref);
+
+cil_base_class(unique int id: @cil_type ref, int base: @cil_type ref);
+cil_base_interface(int id: @cil_type ref, int base: @cil_type ref);
+cil_enum_underlying_type(unique int id: @cil_type ref, int underlying: @cil_type ref);
+
+#keyset[unbound, index]
+cil_type_parameter(
+ int unbound: @cil_member ref,
+ int index: int ref,
+ int param: @cil_typeparameter ref);
+
+#keyset[bound, index]
+cil_type_argument(
+ int bound: @cil_member ref,
+ int index: int ref,
+ int t: @cil_type ref);
+
+// CIL type parameter constraints
+
+cil_typeparam_covariant(int tp: @cil_typeparameter ref);
+cil_typeparam_contravariant(int tp: @cil_typeparameter ref);
+cil_typeparam_class(int tp: @cil_typeparameter ref);
+cil_typeparam_struct(int tp: @cil_typeparameter ref);
+cil_typeparam_new(int tp: @cil_typeparameter ref);
+cil_typeparam_constraint(int tp: @cil_typeparameter ref, int supertype: @cil_type ref);
+
+// CIL attributes
+
+cil_attribute(
+ unique int attributeid: @cil_attribute,
+ int element: @cil_declaration ref,
+ int constructor: @cil_method ref);
+
+#keyset[attribute_id, param]
+cil_attribute_named_argument(
+ int attribute_id: @cil_attribute ref,
+ string param: string ref,
+ string value: string ref);
+
+#keyset[attribute_id, index]
+cil_attribute_positional_argument(
+ int attribute_id: @cil_attribute ref,
+ int index: int ref,
+ string value: string ref);
+
+
+// Common .Net data model covering both C# and CIL
+
+// Common elements
+@dotnet_element = @element | @cil_element;
+@dotnet_named_element = @named_element | @cil_named_element;
+@dotnet_callable = @callable | @cil_method;
+@dotnet_variable = @variable | @cil_variable;
+@dotnet_field = @field | @cil_field;
+@dotnet_parameter = @parameter | @cil_parameter;
+@dotnet_declaration = @declaration | @cil_declaration;
+@dotnet_member = @member | @cil_member;
+@dotnet_event = @event | @cil_event;
+@dotnet_property = @property | @cil_property | @indexer;
+@dotnet_parameterizable = @parameterizable | @cil_parameterizable;
+
+// Common types
+@dotnet_type = @type | @cil_type;
+@dotnet_call = @call | @cil_call_any;
+@dotnet_throw = @throw_element | @cil_throw_any;
+@dotnet_valueorreftype = @cil_valueorreftype | @value_or_ref_type | @cil_array_type | @void_type;
+@dotnet_typeparameter = @type_parameter | @cil_typeparameter;
+@dotnet_array_type = @array_type | @cil_array_type;
+@dotnet_pointer_type = @pointer_type | @cil_pointer_type;
+@dotnet_type_parameter = @type_parameter | @cil_typeparameter;
+@dotnet_generic = @dotnet_valueorreftype | @dotnet_callable;
+
+// Attributes
+@dotnet_attribute = @attribute | @cil_attribute;
+
+// Expressions
+@dotnet_expr = @expr | @cil_expr;
+
+// Literals
+@dotnet_literal = @literal_expr | @cil_literal;
+@dotnet_string_literal = @string_literal_expr | @cil_ldstr;
+@dotnet_int_literal = @integer_literal_expr | @cil_ldc_i;
+@dotnet_float_literal = @float_literal_expr | @cil_ldc_r;
+@dotnet_null_literal = @null_literal_expr | @cil_ldnull;
+
+@metadata_entity = @cil_method | @cil_type | @cil_field | @cil_property | @field | @property |
+ @callable | @value_or_ref_type | @void_type;
+
+#keyset[entity, location]
+metadata_handle(int entity : @metadata_entity ref, int location: @assembly ref, int handle: int ref)
diff --git a/csharp/downgrades/d0fba103f7dee477dd7d9f6c038518b3f683b2c7/semmlecode.csharp.dbscheme b/csharp/downgrades/d0fba103f7dee477dd7d9f6c038518b3f683b2c7/semmlecode.csharp.dbscheme
new file mode 100644
index 00000000000..83aca6b3e4f
--- /dev/null
+++ b/csharp/downgrades/d0fba103f7dee477dd7d9f6c038518b3f683b2c7/semmlecode.csharp.dbscheme
@@ -0,0 +1,2067 @@
+/* This is a dummy line to alter the dbscheme, so we can make a database upgrade
+ * without actually changing any of the dbscheme predicates. It contains a date
+ * to allow for such updates in the future as well.
+ *
+ * 2021-07-14
+ *
+ * DO NOT remove this comment carelessly, since it can revert the dbscheme back to a
+ * previously seen state (matching a previously seen SHA), which would make the upgrade
+ * mechanism not work properly.
+ */
+
+/**
+ * An invocation of the compiler. Note that more than one file may be
+ * compiled per invocation. For example, this command compiles three
+ * source files:
+ *
+ * csc f1.cs f2.cs f3.cs
+ *
+ * The `id` simply identifies the invocation, while `cwd` is the working
+ * directory from which the compiler was invoked.
+ */
+compilations(
+ unique int id : @compilation,
+ string cwd : string ref
+);
+
+/**
+ * The arguments that were passed to the extractor for a compiler
+ * invocation. If `id` is for the compiler invocation
+ *
+ * csc f1.cs f2.cs f3.cs
+ *
+ * then typically there will be rows for
+ *
+ * num | arg
+ * --- | ---
+ * 0 | --compiler
+ * 1 | *path to compiler*
+ * 2 | f1.cs
+ * 3 | f2.cs
+ * 4 | f3.cs
+ */
+#keyset[id, num]
+compilation_args(
+ int id : @compilation ref,
+ int num : int ref,
+ string arg : string ref
+);
+
+/**
+ * The source files that are compiled by a compiler invocation.
+ * If `id` is for the compiler invocation
+ *
+ * csc f1.cs f2.cs f3.cs
+ *
+ * then there will be rows for
+ *
+ * num | arg
+ * --- | ---
+ * 0 | f1.cs
+ * 1 | f2.cs
+ * 2 | f3.cs
+ */
+#keyset[id, num]
+compilation_compiling_files(
+ int id : @compilation ref,
+ int num : int ref,
+ int file : @file ref
+);
+
+/**
+ * The references used by a compiler invocation.
+ * If `id` is for the compiler invocation
+ *
+ * csc f1.cs f2.cs f3.cs /r:ref1.dll /r:ref2.dll /r:ref3.dll
+ *
+ * then there will be rows for
+ *
+ * num | arg
+ * --- | ---
+ * 0 | ref1.dll
+ * 1 | ref2.dll
+ * 2 | ref3.dll
+ */
+#keyset[id, num]
+compilation_referencing_files(
+ int id : @compilation ref,
+ int num : int ref,
+ int file : @file ref
+);
+
+/**
+ * The time taken by the extractor for a compiler invocation.
+ *
+ * For each file `num`, there will be rows for
+ *
+ * kind | seconds
+ * ---- | ---
+ * 1 | CPU seconds used by the extractor frontend
+ * 2 | Elapsed seconds during the extractor frontend
+ * 3 | CPU seconds used by the extractor backend
+ * 4 | Elapsed seconds during the extractor backend
+ */
+#keyset[id, num, kind]
+compilation_time(
+ int id : @compilation ref,
+ int num : int ref,
+ /* kind:
+ 1 = frontend_cpu_seconds
+ 2 = frontend_elapsed_seconds
+ 3 = extractor_cpu_seconds
+ 4 = extractor_elapsed_seconds
+ */
+ int kind : int ref,
+ float seconds : float ref
+);
+
+/**
+ * An error or warning generated by the extractor.
+ * The diagnostic message `diagnostic` was generated during compiler
+ * invocation `compilation`, and is the `file_number_diagnostic_number`th
+ * message generated while extracting the `file_number`th file of that
+ * invocation.
+ */
+#keyset[compilation, file_number, file_number_diagnostic_number]
+diagnostic_for(
+ unique int diagnostic : @diagnostic ref,
+ int compilation : @compilation ref,
+ int file_number : int ref,
+ int file_number_diagnostic_number : int ref
+);
+
+diagnostics(
+ unique int id: @diagnostic,
+ int severity: int ref,
+ string error_tag: string ref,
+ string error_message: string ref,
+ string full_error_message: string ref,
+ int location: @location_default ref
+);
+
+extractor_messages(
+ unique int id: @extractor_message,
+ int severity: int ref,
+ string origin : string ref,
+ string text : string ref,
+ string entity : string ref,
+ int location: @location_default ref,
+ string stack_trace : string ref
+);
+
+/**
+ * If extraction was successful, then `cpu_seconds` and
+ * `elapsed_seconds` are the CPU time and elapsed time (respectively)
+ * that extraction took for compiler invocation `id`.
+ */
+compilation_finished(
+ unique int id : @compilation ref,
+ float cpu_seconds : float ref,
+ float elapsed_seconds : float ref
+);
+
+compilation_assembly(
+ unique int id : @compilation ref,
+ int assembly: @assembly ref
+)
+
+// Populated by the CSV extractor
+externalData(
+ int id: @externalDataElement,
+ string path: string ref,
+ int column: int ref,
+ string value: string ref);
+
+sourceLocationPrefix(
+ string prefix: string ref);
+
+/*
+ * C# dbscheme
+ */
+
+/** ELEMENTS **/
+
+@element = @declaration | @stmt | @expr | @modifier | @attribute | @namespace_declaration
+ | @using_directive | @type_parameter_constraints | @externalDataElement
+ | @xmllocatable | @asp_element | @namespace | @preprocessor_directive;
+
+@declaration = @callable | @generic | @assignable | @namespace;
+
+@named_element = @namespace | @declaration;
+
+@declaration_with_accessors = @property | @indexer | @event;
+
+@assignable = @variable | @assignable_with_accessors | @event;
+
+@assignable_with_accessors = @property | @indexer;
+
+@attributable = @assembly | @field | @parameter | @operator | @method | @constructor
+ | @destructor | @callable_accessor | @value_or_ref_type | @declaration_with_accessors
+ | @local_function | @lambda_expr;
+
+/** LOCATIONS, ASEMMBLIES, MODULES, FILES and FOLDERS **/
+
+@location = @location_default | @assembly;
+
+locations_default(
+ unique int id: @location_default,
+ int file: @file ref,
+ int beginLine: int ref,
+ int beginColumn: int ref,
+ int endLine: int ref,
+ int endColumn: int ref);
+
+locations_mapped(
+ unique int id: @location_default ref,
+ int mapped_to: @location_default ref);
+
+@sourceline = @file | @callable | @xmllocatable;
+
+numlines(
+ int element_id: @sourceline ref,
+ int num_lines: int ref,
+ int num_code: int ref,
+ int num_comment: int ref);
+
+assemblies(
+ unique int id: @assembly,
+ int file: @file ref,
+ string fullname: string ref,
+ string name: string ref,
+ string version: string ref);
+
+files(
+ unique int id: @file,
+ string name: string ref);
+
+folders(
+ unique int id: @folder,
+ string name: string ref);
+
+@container = @folder | @file ;
+
+containerparent(
+ int parent: @container ref,
+ unique int child: @container ref);
+
+file_extraction_mode(
+ unique int file: @file ref,
+ int mode: int ref
+ /* 0 = normal, 1 = standalone extractor */
+ );
+
+/** NAMESPACES **/
+
+@type_container = @namespace | @type;
+
+namespaces(
+ unique int id: @namespace,
+ string name: string ref);
+
+namespace_declarations(
+ unique int id: @namespace_declaration,
+ int namespace_id: @namespace ref);
+
+namespace_declaration_location(
+ unique int id: @namespace_declaration ref,
+ int loc: @location ref);
+
+parent_namespace(
+ unique int child_id: @type_container ref,
+ int namespace_id: @namespace ref);
+
+@declaration_or_directive = @namespace_declaration | @type | @using_directive;
+
+parent_namespace_declaration(
+ int child_id: @declaration_or_directive ref, // cannot be unique because of partial classes
+ int namespace_id: @namespace_declaration ref);
+
+@using_directive = @using_namespace_directive | @using_static_directive;
+
+using_global(
+ unique int id: @using_directive ref
+);
+
+using_namespace_directives(
+ unique int id: @using_namespace_directive,
+ int namespace_id: @namespace ref);
+
+using_static_directives(
+ unique int id: @using_static_directive,
+ int type_id: @type_or_ref ref);
+
+using_directive_location(
+ unique int id: @using_directive ref,
+ int loc: @location ref);
+
+@preprocessor_directive = @pragma_warning | @pragma_checksum | @directive_define | @directive_undefine | @directive_warning
+ | @directive_error | @directive_nullable | @directive_line | @directive_region | @directive_endregion | @directive_if
+ | @directive_elif | @directive_else | @directive_endif;
+
+@conditional_directive = @directive_if | @directive_elif;
+@branch_directive = @directive_if | @directive_elif | @directive_else;
+
+directive_ifs(
+ unique int id: @directive_if,
+ int branchTaken: int ref, /* 0: false, 1: true */
+ int conditionValue: int ref); /* 0: false, 1: true */
+
+directive_elifs(
+ unique int id: @directive_elif,
+ int branchTaken: int ref, /* 0: false, 1: true */
+ int conditionValue: int ref, /* 0: false, 1: true */
+ int parent: @directive_if ref,
+ int index: int ref);
+
+directive_elses(
+ unique int id: @directive_else,
+ int branchTaken: int ref, /* 0: false, 1: true */
+ int parent: @directive_if ref,
+ int index: int ref);
+
+#keyset[id, start]
+directive_endifs(
+ unique int id: @directive_endif,
+ unique int start: @directive_if ref);
+
+directive_define_symbols(
+ unique int id: @define_symbol_expr ref,
+ string name: string ref);
+
+directive_regions(
+ unique int id: @directive_region,
+ string name: string ref);
+
+#keyset[id, start]
+directive_endregions(
+ unique int id: @directive_endregion,
+ unique int start: @directive_region ref);
+
+directive_lines(
+ unique int id: @directive_line,
+ int kind: int ref); /* 0: default, 1: hidden, 2: numeric, 3: span */
+
+directive_line_value(
+ unique int id: @directive_line ref,
+ int line: int ref);
+
+directive_line_file(
+ unique int id: @directive_line ref,
+ int file: @file ref);
+
+directive_line_offset(
+ unique int id: @directive_line ref,
+ int offset: int ref);
+
+directive_line_span(
+ unique int id: @directive_line ref,
+ int startLine: int ref,
+ int startColumn: int ref,
+ int endLine: int ref,
+ int endColumn: int ref);
+
+directive_nullables(
+ unique int id: @directive_nullable,
+ int setting: int ref, /* 0: disable, 1: enable, 2: restore */
+ int target: int ref); /* 0: none, 1: annotations, 2: warnings */
+
+directive_warnings(
+ unique int id: @directive_warning,
+ string message: string ref);
+
+directive_errors(
+ unique int id: @directive_error,
+ string message: string ref);
+
+directive_undefines(
+ unique int id: @directive_undefine,
+ string name: string ref);
+
+directive_defines(
+ unique int id: @directive_define,
+ string name: string ref);
+
+pragma_checksums(
+ unique int id: @pragma_checksum,
+ int file: @file ref,
+ string guid: string ref,
+ string bytes: string ref);
+
+pragma_warnings(
+ unique int id: @pragma_warning,
+ int kind: int ref /* 0 = disable, 1 = restore */);
+
+#keyset[id, index]
+pragma_warning_error_codes(
+ int id: @pragma_warning ref,
+ string errorCode: string ref,
+ int index: int ref);
+
+preprocessor_directive_location(
+ unique int id: @preprocessor_directive ref,
+ int loc: @location ref);
+
+preprocessor_directive_compilation(
+ unique int id: @preprocessor_directive ref,
+ int compilation: @compilation ref);
+
+preprocessor_directive_active(
+ unique int id: @preprocessor_directive ref,
+ int active: int ref); /* 0: false, 1: true */
+
+/** TYPES **/
+
+types(
+ unique int id: @type,
+ int kind: int ref,
+ string name: string ref);
+
+case @type.kind of
+ 1 = @bool_type
+| 2 = @char_type
+| 3 = @decimal_type
+| 4 = @sbyte_type
+| 5 = @short_type
+| 6 = @int_type
+| 7 = @long_type
+| 8 = @byte_type
+| 9 = @ushort_type
+| 10 = @uint_type
+| 11 = @ulong_type
+| 12 = @float_type
+| 13 = @double_type
+| 14 = @enum_type
+| 15 = @struct_type
+| 17 = @class_type
+| 19 = @interface_type
+| 20 = @delegate_type
+| 21 = @null_type
+| 22 = @type_parameter
+| 23 = @pointer_type
+| 24 = @nullable_type
+| 25 = @array_type
+| 26 = @void_type
+| 27 = @int_ptr_type
+| 28 = @uint_ptr_type
+| 29 = @dynamic_type
+| 30 = @arglist_type
+| 31 = @unknown_type
+| 32 = @tuple_type
+| 33 = @function_pointer_type
+ ;
+
+@simple_type = @bool_type | @char_type | @integral_type | @floating_point_type | @decimal_type;
+@integral_type = @signed_integral_type | @unsigned_integral_type;
+@signed_integral_type = @sbyte_type | @short_type | @int_type | @long_type;
+@unsigned_integral_type = @byte_type | @ushort_type | @uint_type | @ulong_type;
+@floating_point_type = @float_type | @double_type;
+@value_type = @simple_type | @enum_type | @struct_type | @nullable_type | @int_ptr_type
+ | @uint_ptr_type | @tuple_type;
+@ref_type = @class_type | @interface_type | @array_type | @delegate_type | @null_type
+ | @dynamic_type;
+@value_or_ref_type = @value_type | @ref_type;
+
+typerefs(
+ unique int id: @typeref,
+ string name: string ref);
+
+typeref_type(
+ int id: @typeref ref,
+ unique int typeId: @type ref);
+
+@type_or_ref = @type | @typeref;
+
+array_element_type(
+ unique int array: @array_type ref,
+ int dimension: int ref,
+ int rank: int ref,
+ int element: @type_or_ref ref);
+
+nullable_underlying_type(
+ unique int nullable: @nullable_type ref,
+ int underlying: @type_or_ref ref);
+
+pointer_referent_type(
+ unique int pointer: @pointer_type ref,
+ int referent: @type_or_ref ref);
+
+enum_underlying_type(
+ unique int enum_id: @enum_type ref,
+ int underlying_type_id: @type_or_ref ref);
+
+delegate_return_type(
+ unique int delegate_id: @delegate_type ref,
+ int return_type_id: @type_or_ref ref);
+
+function_pointer_return_type(
+ unique int function_pointer_id: @function_pointer_type ref,
+ int return_type_id: @type_or_ref ref);
+
+extend(
+ int sub: @type ref,
+ int super: @type_or_ref ref);
+
+anonymous_types(
+ unique int id: @type ref);
+
+@interface_or_ref = @interface_type | @typeref;
+
+implement(
+ int sub: @type ref,
+ int super: @type_or_ref ref);
+
+type_location(
+ int id: @type ref,
+ int loc: @location ref);
+
+tuple_underlying_type(
+ unique int tuple: @tuple_type ref,
+ int struct: @type_or_ref ref);
+
+#keyset[tuple, index]
+tuple_element(
+ int tuple: @tuple_type ref,
+ int index: int ref,
+ unique int field: @field ref);
+
+attributes(
+ unique int id: @attribute,
+ int kind: int ref,
+ int type_id: @type_or_ref ref,
+ int target: @attributable ref);
+
+case @attribute.kind of
+ 0 = @attribute_default
+| 1 = @attribute_return
+| 2 = @attribute_assembly
+| 3 = @attribute_module
+;
+
+attribute_location(
+ int id: @attribute ref,
+ int loc: @location ref);
+
+@type_mention_parent = @element | @type_mention;
+
+type_mention(
+ unique int id: @type_mention,
+ int type_id: @type_or_ref ref,
+ int parent: @type_mention_parent ref);
+
+type_mention_location(
+ unique int id: @type_mention ref,
+ int loc: @location ref);
+
+@has_type_annotation = @assignable | @type_parameter | @callable | @expr | @delegate_type | @generic | @function_pointer_type;
+
+/**
+ * A direct annotation on an entity, for example `string? x;`.
+ *
+ * Annotations:
+ * 2 = reftype is not annotated "!"
+ * 3 = reftype is annotated "?"
+ * 4 = readonly ref type / in parameter
+ * 5 = ref type parameter, return or local variable
+ * 6 = out parameter
+ *
+ * Note that the annotation depends on the element it annotates.
+ * @assignable: The annotation is on the type of the assignable, for example the variable type.
+ * @type_parameter: The annotation is on the reftype constraint
+ * @callable: The annotation is on the return type
+ * @array_type: The annotation is on the element type
+ */
+type_annotation(int id: @has_type_annotation ref, int annotation: int ref);
+
+nullability(unique int nullability: @nullability, int kind: int ref);
+
+case @nullability.kind of
+ 0 = @oblivious
+| 1 = @not_annotated
+| 2 = @annotated
+;
+
+#keyset[parent, index]
+nullability_parent(int nullability: @nullability ref, int index: int ref, int parent: @nullability ref)
+
+type_nullability(int id: @has_type_annotation ref, int nullability: @nullability ref);
+
+/**
+ * The nullable flow state of an expression, as determined by Roslyn.
+ * 0 = none (default, not populated)
+ * 1 = not null
+ * 2 = maybe null
+ */
+expr_flowstate(unique int id: @expr ref, int state: int ref);
+
+/** GENERICS **/
+
+@generic = @type | @method | @local_function;
+
+type_parameters(
+ unique int id: @type_parameter ref,
+ int index: int ref,
+ int generic_id: @generic ref,
+ int variance: int ref /* none = 0, out = 1, in = 2 */);
+
+#keyset[constructed_id, index]
+type_arguments(
+ int id: @type_or_ref ref,
+ int index: int ref,
+ int constructed_id: @generic_or_ref ref);
+
+@generic_or_ref = @generic | @typeref;
+
+constructed_generic(
+ unique int constructed: @generic ref,
+ int generic: @generic_or_ref ref);
+
+type_parameter_constraints(
+ unique int id: @type_parameter_constraints,
+ int param_id: @type_parameter ref);
+
+type_parameter_constraints_location(
+ int id: @type_parameter_constraints ref,
+ int loc: @location ref);
+
+general_type_parameter_constraints(
+ int id: @type_parameter_constraints ref,
+ int kind: int ref /* class = 1, struct = 2, new = 3 */);
+
+specific_type_parameter_constraints(
+ int id: @type_parameter_constraints ref,
+ int base_id: @type_or_ref ref);
+
+specific_type_parameter_nullability(
+ int id: @type_parameter_constraints ref,
+ int base_id: @type_or_ref ref,
+ int nullability: @nullability ref);
+
+/** FUNCTION POINTERS */
+
+function_pointer_calling_conventions(
+ int id: @function_pointer_type ref,
+ int kind: int ref);
+
+#keyset[id, index]
+has_unmanaged_calling_conventions(
+ int id: @function_pointer_type ref,
+ int index: int ref,
+ int conv_id: @type_or_ref ref);
+
+/** MODIFIERS */
+
+@modifiable = @modifiable_direct | @event_accessor;
+
+@modifiable_direct = @member | @accessor | @local_function | @anonymous_function_expr;
+
+modifiers(
+ unique int id: @modifier,
+ string name: string ref);
+
+has_modifiers(
+ int id: @modifiable_direct ref,
+ int mod_id: @modifier ref);
+
+compiler_generated(unique int id: @modifiable ref);
+
+/** MEMBERS **/
+
+@member = @method | @constructor | @destructor | @field | @property | @event | @operator | @indexer | @type;
+
+@named_exprorstmt = @goto_stmt | @labeled_stmt | @expr;
+
+@virtualizable = @method | @property | @indexer | @event;
+
+exprorstmt_name(
+ unique int parent_id: @named_exprorstmt ref,
+ string name: string ref);
+
+nested_types(
+ unique int id: @type ref,
+ int declaring_type_id: @type ref,
+ int unbound_id: @type ref);
+
+properties(
+ unique int id: @property,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @property ref);
+
+property_location(
+ int id: @property ref,
+ int loc: @location ref);
+
+indexers(
+ unique int id: @indexer,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @indexer ref);
+
+indexer_location(
+ int id: @indexer ref,
+ int loc: @location ref);
+
+accessors(
+ unique int id: @accessor,
+ int kind: int ref,
+ string name: string ref,
+ int declaring_member_id: @member ref,
+ int unbound_id: @accessor ref);
+
+case @accessor.kind of
+ 1 = @getter
+| 2 = @setter
+ ;
+
+init_only_accessors(
+ unique int id: @accessor ref);
+
+accessor_location(
+ int id: @accessor ref,
+ int loc: @location ref);
+
+events(
+ unique int id: @event,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @event ref);
+
+event_location(
+ int id: @event ref,
+ int loc: @location ref);
+
+event_accessors(
+ unique int id: @event_accessor,
+ int kind: int ref,
+ string name: string ref,
+ int declaring_event_id: @event ref,
+ int unbound_id: @event_accessor ref);
+
+case @event_accessor.kind of
+ 1 = @add_event_accessor
+| 2 = @remove_event_accessor
+ ;
+
+event_accessor_location(
+ int id: @event_accessor ref,
+ int loc: @location ref);
+
+operators(
+ unique int id: @operator,
+ string name: string ref,
+ string symbol: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @operator ref);
+
+operator_location(
+ int id: @operator ref,
+ int loc: @location ref);
+
+constant_value(
+ int id: @variable ref,
+ string value: string ref);
+
+/** CALLABLES **/
+
+@callable = @method | @constructor | @destructor | @operator | @callable_accessor | @anonymous_function_expr | @local_function;
+
+@callable_accessor = @accessor | @event_accessor;
+
+methods(
+ unique int id: @method,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @method ref);
+
+method_location(
+ int id: @method ref,
+ int loc: @location ref);
+
+constructors(
+ unique int id: @constructor,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int unbound_id: @constructor ref);
+
+constructor_location(
+ int id: @constructor ref,
+ int loc: @location ref);
+
+destructors(
+ unique int id: @destructor,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int unbound_id: @destructor ref);
+
+destructor_location(
+ int id: @destructor ref,
+ int loc: @location ref);
+
+overrides(
+ int id: @callable ref,
+ int base_id: @callable ref);
+
+explicitly_implements(
+ int id: @member ref,
+ int interface_id: @interface_or_ref ref);
+
+local_functions(
+ unique int id: @local_function,
+ string name: string ref,
+ int return_type: @type ref,
+ int unbound_id: @local_function ref);
+
+local_function_stmts(
+ unique int fn: @local_function_stmt ref,
+ int stmt: @local_function ref);
+
+/** VARIABLES **/
+
+@variable = @local_scope_variable | @field;
+
+@local_scope_variable = @local_variable | @parameter;
+
+fields(
+ unique int id: @field,
+ int kind: int ref,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @field ref);
+
+case @field.kind of
+ 1 = @addressable_field
+| 2 = @constant
+ ;
+
+field_location(
+ int id: @field ref,
+ int loc: @location ref);
+
+localvars(
+ unique int id: @local_variable,
+ int kind: int ref,
+ string name: string ref,
+ int implicitly_typed: int ref /* 0 = no, 1 = yes */,
+ int type_id: @type_or_ref ref,
+ int parent_id: @local_var_decl_expr ref);
+
+case @local_variable.kind of
+ 1 = @addressable_local_variable
+| 2 = @local_constant
+| 3 = @local_variable_ref
+ ;
+
+localvar_location(
+ unique int id: @local_variable ref,
+ int loc: @location ref);
+
+@parameterizable = @callable | @delegate_type | @indexer | @function_pointer_type;
+
+#keyset[name, parent_id]
+#keyset[index, parent_id]
+params(
+ unique int id: @parameter,
+ string name: string ref,
+ int type_id: @type_or_ref ref,
+ int index: int ref,
+ int mode: int ref, /* value = 0, ref = 1, out = 2, array = 3, this = 4 */
+ int parent_id: @parameterizable ref,
+ int unbound_id: @parameter ref);
+
+param_location(
+ int id: @parameter ref,
+ int loc: @location ref);
+
+/** STATEMENTS **/
+
+@exprorstmt_parent = @control_flow_element | @top_level_exprorstmt_parent;
+
+statements(
+ unique int id: @stmt,
+ int kind: int ref);
+
+#keyset[index, parent]
+stmt_parent(
+ unique int stmt: @stmt ref,
+ int index: int ref,
+ int parent: @control_flow_element ref);
+
+@top_level_stmt_parent = @callable;
+
+// [index, parent] is not a keyset because the same parent may be compiled multiple times
+stmt_parent_top_level(
+ unique int stmt: @stmt ref,
+ int index: int ref,
+ int parent: @top_level_stmt_parent ref);
+
+case @stmt.kind of
+ 1 = @block_stmt
+| 2 = @expr_stmt
+| 3 = @if_stmt
+| 4 = @switch_stmt
+| 5 = @while_stmt
+| 6 = @do_stmt
+| 7 = @for_stmt
+| 8 = @foreach_stmt
+| 9 = @break_stmt
+| 10 = @continue_stmt
+| 11 = @goto_stmt
+| 12 = @goto_case_stmt
+| 13 = @goto_default_stmt
+| 14 = @throw_stmt
+| 15 = @return_stmt
+| 16 = @yield_stmt
+| 17 = @try_stmt
+| 18 = @checked_stmt
+| 19 = @unchecked_stmt
+| 20 = @lock_stmt
+| 21 = @using_block_stmt
+| 22 = @var_decl_stmt
+| 23 = @const_decl_stmt
+| 24 = @empty_stmt
+| 25 = @unsafe_stmt
+| 26 = @fixed_stmt
+| 27 = @label_stmt
+| 28 = @catch
+| 29 = @case_stmt
+| 30 = @local_function_stmt
+| 31 = @using_decl_stmt
+ ;
+
+@using_stmt = @using_block_stmt | @using_decl_stmt;
+
+@labeled_stmt = @label_stmt | @case;
+
+@decl_stmt = @var_decl_stmt | @const_decl_stmt | @using_decl_stmt;
+
+@cond_stmt = @if_stmt | @switch_stmt;
+
+@loop_stmt = @while_stmt | @do_stmt | @for_stmt | @foreach_stmt;
+
+@jump_stmt = @break_stmt | @goto_any_stmt | @continue_stmt | @throw_stmt | @return_stmt
+ | @yield_stmt;
+
+@goto_any_stmt = @goto_default_stmt | @goto_case_stmt | @goto_stmt;
+
+
+stmt_location(
+ unique int id: @stmt ref,
+ int loc: @location ref);
+
+catch_type(
+ unique int catch_id: @catch ref,
+ int type_id: @type_or_ref ref,
+ int kind: int ref /* explicit = 1, implicit = 2 */);
+
+foreach_stmt_info(
+ unique int id: @foreach_stmt ref,
+ int kind: int ref /* non-async = 1, async = 2 */);
+
+@foreach_symbol = @method | @property | @type_or_ref;
+
+#keyset[id, kind]
+foreach_stmt_desugar(
+ int id: @foreach_stmt ref,
+ int symbol: @foreach_symbol ref,
+ int kind: int ref /* GetEnumeratorMethod = 1, CurrentProperty = 2, MoveNextMethod = 3, DisposeMethod = 4, ElementType = 5 */);
+
+/** EXPRESSIONS **/
+
+expressions(
+ unique int id: @expr,
+ int kind: int ref,
+ int type_id: @type_or_ref ref);
+
+#keyset[index, parent]
+expr_parent(
+ unique int expr: @expr ref,
+ int index: int ref,
+ int parent: @control_flow_element ref);
+
+@top_level_expr_parent = @attribute | @field | @property | @indexer | @parameter | @directive_if | @directive_elif;
+
+@top_level_exprorstmt_parent = @top_level_expr_parent | @top_level_stmt_parent;
+
+// [index, parent] is not a keyset because the same parent may be compiled multiple times
+expr_parent_top_level(
+ unique int expr: @expr ref,
+ int index: int ref,
+ int parent: @top_level_exprorstmt_parent ref);
+
+case @expr.kind of
+/* literal */
+ 1 = @bool_literal_expr
+| 2 = @char_literal_expr
+| 3 = @decimal_literal_expr
+| 4 = @int_literal_expr
+| 5 = @long_literal_expr
+| 6 = @uint_literal_expr
+| 7 = @ulong_literal_expr
+| 8 = @float_literal_expr
+| 9 = @double_literal_expr
+| 10 = @string_literal_expr
+| 11 = @null_literal_expr
+/* primary & unary */
+| 12 = @this_access_expr
+| 13 = @base_access_expr
+| 14 = @local_variable_access_expr
+| 15 = @parameter_access_expr
+| 16 = @field_access_expr
+| 17 = @property_access_expr
+| 18 = @method_access_expr
+| 19 = @event_access_expr
+| 20 = @indexer_access_expr
+| 21 = @array_access_expr
+| 22 = @type_access_expr
+| 23 = @typeof_expr
+| 24 = @method_invocation_expr
+| 25 = @delegate_invocation_expr
+| 26 = @operator_invocation_expr
+| 27 = @cast_expr
+| 28 = @object_creation_expr
+| 29 = @explicit_delegate_creation_expr
+| 30 = @implicit_delegate_creation_expr
+| 31 = @array_creation_expr
+| 32 = @default_expr
+| 33 = @plus_expr
+| 34 = @minus_expr
+| 35 = @bit_not_expr
+| 36 = @log_not_expr
+| 37 = @post_incr_expr
+| 38 = @post_decr_expr
+| 39 = @pre_incr_expr
+| 40 = @pre_decr_expr
+/* multiplicative */
+| 41 = @mul_expr
+| 42 = @div_expr
+| 43 = @rem_expr
+/* additive */
+| 44 = @add_expr
+| 45 = @sub_expr
+/* shift */
+| 46 = @lshift_expr
+| 47 = @rshift_expr
+/* relational */
+| 48 = @lt_expr
+| 49 = @gt_expr
+| 50 = @le_expr
+| 51 = @ge_expr
+/* equality */
+| 52 = @eq_expr
+| 53 = @ne_expr
+/* logical */
+| 54 = @bit_and_expr
+| 55 = @bit_xor_expr
+| 56 = @bit_or_expr
+| 57 = @log_and_expr
+| 58 = @log_or_expr
+/* type testing */
+| 59 = @is_expr
+| 60 = @as_expr
+/* null coalescing */
+| 61 = @null_coalescing_expr
+/* conditional */
+| 62 = @conditional_expr
+/* assignment */
+| 63 = @simple_assign_expr
+| 64 = @assign_add_expr
+| 65 = @assign_sub_expr
+| 66 = @assign_mul_expr
+| 67 = @assign_div_expr
+| 68 = @assign_rem_expr
+| 69 = @assign_and_expr
+| 70 = @assign_xor_expr
+| 71 = @assign_or_expr
+| 72 = @assign_lshift_expr
+| 73 = @assign_rshift_expr
+/* more */
+| 74 = @object_init_expr
+| 75 = @collection_init_expr
+| 76 = @array_init_expr
+| 77 = @checked_expr
+| 78 = @unchecked_expr
+| 79 = @constructor_init_expr
+| 80 = @add_event_expr
+| 81 = @remove_event_expr
+| 82 = @par_expr
+| 83 = @local_var_decl_expr
+| 84 = @lambda_expr
+| 85 = @anonymous_method_expr
+| 86 = @namespace_expr
+/* dynamic */
+| 92 = @dynamic_element_access_expr
+| 93 = @dynamic_member_access_expr
+/* unsafe */
+| 100 = @pointer_indirection_expr
+| 101 = @address_of_expr
+| 102 = @sizeof_expr
+/* async */
+| 103 = @await_expr
+/* C# 6.0 */
+| 104 = @nameof_expr
+| 105 = @interpolated_string_expr
+| 106 = @unknown_expr
+/* C# 7.0 */
+| 107 = @throw_expr
+| 108 = @tuple_expr
+| 109 = @local_function_invocation_expr
+| 110 = @ref_expr
+| 111 = @discard_expr
+/* C# 8.0 */
+| 112 = @range_expr
+| 113 = @index_expr
+| 114 = @switch_expr
+| 115 = @recursive_pattern_expr
+| 116 = @property_pattern_expr
+| 117 = @positional_pattern_expr
+| 118 = @switch_case_expr
+| 119 = @assign_coalesce_expr
+| 120 = @suppress_nullable_warning_expr
+| 121 = @namespace_access_expr
+/* C# 9.0 */
+| 122 = @lt_pattern_expr
+| 123 = @gt_pattern_expr
+| 124 = @le_pattern_expr
+| 125 = @ge_pattern_expr
+| 126 = @not_pattern_expr
+| 127 = @and_pattern_expr
+| 128 = @or_pattern_expr
+| 129 = @function_pointer_invocation_expr
+| 130 = @with_expr
+/* C# 11.0 */
+| 131 = @list_pattern_expr
+| 132 = @slice_pattern_expr
+/* Preprocessor */
+| 999 = @define_symbol_expr
+;
+
+@switch = @switch_stmt | @switch_expr;
+@case = @case_stmt | @switch_case_expr;
+@pattern_match = @case | @is_expr;
+@unary_pattern_expr = @not_pattern_expr;
+@relational_pattern_expr = @gt_pattern_expr | @lt_pattern_expr | @ge_pattern_expr | @le_pattern_expr;
+@binary_pattern_expr = @and_pattern_expr | @or_pattern_expr;
+
+@integer_literal_expr = @int_literal_expr | @long_literal_expr | @uint_literal_expr | @ulong_literal_expr;
+@real_literal_expr = @float_literal_expr | @double_literal_expr | @decimal_literal_expr;
+@literal_expr = @bool_literal_expr | @char_literal_expr | @integer_literal_expr | @real_literal_expr
+ | @string_literal_expr | @null_literal_expr;
+
+@assign_expr = @simple_assign_expr | @assign_op_expr | @local_var_decl_expr;
+@assign_op_expr = @assign_arith_expr | @assign_bitwise_expr | @assign_event_expr | @assign_coalesce_expr;
+@assign_event_expr = @add_event_expr | @remove_event_expr;
+
+@assign_arith_expr = @assign_add_expr | @assign_sub_expr | @assign_mul_expr | @assign_div_expr
+ | @assign_rem_expr
+@assign_bitwise_expr = @assign_and_expr | @assign_or_expr | @assign_xor_expr
+ | @assign_lshift_expr | @assign_rshift_expr;
+
+@member_access_expr = @field_access_expr | @property_access_expr | @indexer_access_expr | @event_access_expr
+ | @method_access_expr | @type_access_expr | @dynamic_member_access_expr;
+@access_expr = @member_access_expr | @this_access_expr | @base_access_expr | @assignable_access_expr | @namespace_access_expr;
+@element_access_expr = @indexer_access_expr | @array_access_expr | @dynamic_element_access_expr;
+
+@local_variable_access = @local_variable_access_expr | @local_var_decl_expr;
+@local_scope_variable_access_expr = @parameter_access_expr | @local_variable_access;
+@variable_access_expr = @local_scope_variable_access_expr | @field_access_expr;
+
+@assignable_access_expr = @variable_access_expr | @property_access_expr | @element_access_expr
+ | @event_access_expr | @dynamic_member_access_expr;
+
+@objectorcollection_init_expr = @object_init_expr | @collection_init_expr;
+
+@delegate_creation_expr = @explicit_delegate_creation_expr | @implicit_delegate_creation_expr;
+
+@bin_arith_op_expr = @mul_expr | @div_expr | @rem_expr | @add_expr | @sub_expr;
+@incr_op_expr = @pre_incr_expr | @post_incr_expr;
+@decr_op_expr = @pre_decr_expr | @post_decr_expr;
+@mut_op_expr = @incr_op_expr | @decr_op_expr;
+@un_arith_op_expr = @plus_expr | @minus_expr | @mut_op_expr;
+@arith_op_expr = @bin_arith_op_expr | @un_arith_op_expr;
+
+@ternary_log_op_expr = @conditional_expr;
+@bin_log_op_expr = @log_and_expr | @log_or_expr | @null_coalescing_expr;
+@un_log_op_expr = @log_not_expr;
+@log_expr = @un_log_op_expr | @bin_log_op_expr | @ternary_log_op_expr;
+
+@bin_bit_op_expr = @bit_and_expr | @bit_or_expr | @bit_xor_expr | @lshift_expr
+ | @rshift_expr;
+@un_bit_op_expr = @bit_not_expr;
+@bit_expr = @un_bit_op_expr | @bin_bit_op_expr;
+
+@equality_op_expr = @eq_expr | @ne_expr;
+@rel_op_expr = @gt_expr | @lt_expr| @ge_expr | @le_expr;
+@comp_expr = @equality_op_expr | @rel_op_expr;
+
+@op_expr = @assign_expr | @un_op | @bin_op | @ternary_op;
+
+@ternary_op = @ternary_log_op_expr;
+@bin_op = @bin_arith_op_expr | @bin_log_op_expr | @bin_bit_op_expr | @comp_expr;
+@un_op = @un_arith_op_expr | @un_log_op_expr | @un_bit_op_expr | @sizeof_expr
+ | @pointer_indirection_expr | @address_of_expr;
+
+@anonymous_function_expr = @lambda_expr | @anonymous_method_expr;
+
+@call = @method_invocation_expr | @constructor_init_expr | @operator_invocation_expr
+ | @delegate_invocation_expr | @object_creation_expr | @call_access_expr
+ | @local_function_invocation_expr | @function_pointer_invocation_expr;
+
+@call_access_expr = @property_access_expr | @event_access_expr | @indexer_access_expr;
+
+@late_bindable_expr = @dynamic_element_access_expr | @dynamic_member_access_expr
+ | @object_creation_expr | @method_invocation_expr | @operator_invocation_expr;
+
+@throw_element = @throw_expr | @throw_stmt;
+
+@implicitly_typeable_object_creation_expr = @object_creation_expr | @explicit_delegate_creation_expr;
+
+implicitly_typed_array_creation(
+ unique int id: @array_creation_expr ref);
+
+explicitly_sized_array_creation(
+ unique int id: @array_creation_expr ref);
+
+stackalloc_array_creation(
+ unique int id: @array_creation_expr ref);
+
+implicitly_typed_object_creation(
+ unique int id: @implicitly_typeable_object_creation_expr ref);
+
+mutator_invocation_mode(
+ unique int id: @operator_invocation_expr ref,
+ int mode: int ref /* prefix = 1, postfix = 2*/);
+
+expr_compiler_generated(
+ unique int id: @expr ref);
+
+expr_value(
+ unique int id: @expr ref,
+ string value: string ref);
+
+expr_call(
+ unique int caller_id: @expr ref,
+ int target_id: @callable ref);
+
+expr_access(
+ unique int accesser_id: @access_expr ref,
+ int target_id: @accessible ref);
+
+@accessible = @method | @assignable | @local_function | @namespace;
+
+expr_location(
+ unique int id: @expr ref,
+ int loc: @location ref);
+
+dynamic_member_name(
+ unique int id: @late_bindable_expr ref,
+ string name: string ref);
+
+@qualifiable_expr = @member_access_expr
+ | @method_invocation_expr
+ | @element_access_expr;
+
+conditional_access(
+ unique int id: @qualifiable_expr ref);
+
+expr_argument(
+ unique int id: @expr ref,
+ int mode: int ref);
+ /* mode is the same as params: value = 0, ref = 1, out = 2 */
+
+expr_argument_name(
+ unique int id: @expr ref,
+ string name: string ref);
+
+lambda_expr_return_type(
+ unique int id: @lambda_expr ref,
+ int type_id: @type_or_ref ref);
+
+/** CONTROL/DATA FLOW **/
+
+@control_flow_element = @stmt | @expr;
+
+/* XML Files */
+
+xmlEncoding (
+ unique int id: @file ref,
+ string encoding: string ref);
+
+xmlDTDs(
+ unique int id: @xmldtd,
+ string root: string ref,
+ string publicId: string ref,
+ string systemId: string ref,
+ int fileid: @file ref);
+
+xmlElements(
+ unique int id: @xmlelement,
+ string name: string ref,
+ int parentid: @xmlparent ref,
+ int idx: int ref,
+ int fileid: @file ref);
+
+xmlAttrs(
+ unique int id: @xmlattribute,
+ int elementid: @xmlelement ref,
+ string name: string ref,
+ string value: string ref,
+ int idx: int ref,
+ int fileid: @file ref);
+
+xmlNs(
+ int id: @xmlnamespace,
+ string prefixName: string ref,
+ string URI: string ref,
+ int fileid: @file ref);
+
+xmlHasNs(
+ int elementId: @xmlnamespaceable ref,
+ int nsId: @xmlnamespace ref,
+ int fileid: @file ref);
+
+xmlComments(
+ unique int id: @xmlcomment,
+ string text: string ref,
+ int parentid: @xmlparent ref,
+ int fileid: @file ref);
+
+xmlChars(
+ unique int id: @xmlcharacters,
+ string text: string ref,
+ int parentid: @xmlparent ref,
+ int idx: int ref,
+ int isCDATA: int ref,
+ int fileid: @file ref);
+
+@xmlparent = @file | @xmlelement;
+@xmlnamespaceable = @xmlelement | @xmlattribute;
+
+xmllocations(
+ int xmlElement: @xmllocatable ref,
+ int location: @location_default ref);
+
+@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace;
+
+/* Comments */
+
+commentline(
+ unique int id: @commentline,
+ int kind: int ref,
+ string text: string ref,
+ string rawtext: string ref);
+
+case @commentline.kind of
+ 0 = @singlelinecomment
+| 1 = @xmldoccomment
+| 2 = @multilinecomment;
+
+commentline_location(
+ unique int id: @commentline ref,
+ int loc: @location ref);
+
+commentblock(
+ unique int id : @commentblock);
+
+commentblock_location(
+ unique int id: @commentblock ref,
+ int loc: @location ref);
+
+commentblock_binding(
+ int id: @commentblock ref,
+ int entity: @element ref,
+ int bindtype: int ref); /* 0: Parent, 1: Best, 2: Before, 3: After */
+
+commentblock_child(
+ int id: @commentblock ref,
+ int commentline: @commentline ref,
+ int index: int ref);
+
+/* ASP.NET */
+
+case @asp_element.kind of
+ 0=@asp_close_tag
+| 1=@asp_code
+| 2=@asp_comment
+| 3=@asp_data_binding
+| 4=@asp_directive
+| 5=@asp_open_tag
+| 6=@asp_quoted_string
+| 7=@asp_text
+| 8=@asp_xml_directive;
+
+@asp_attribute = @asp_code | @asp_data_binding | @asp_quoted_string;
+
+asp_elements(
+ unique int id: @asp_element,
+ int kind: int ref,
+ int loc: @location ref);
+
+asp_comment_server(unique int comment: @asp_comment ref);
+asp_code_inline(unique int code: @asp_code ref);
+asp_directive_attribute(
+ int directive: @asp_directive ref,
+ int index: int ref,
+ string name: string ref,
+ int value: @asp_quoted_string ref);
+asp_directive_name(
+ unique int directive: @asp_directive ref,
+ string name: string ref);
+asp_element_body(
+ unique int element: @asp_element ref,
+ string body: string ref);
+asp_tag_attribute(
+ int tag: @asp_open_tag ref,
+ int index: int ref,
+ string name: string ref,
+ int attribute: @asp_attribute ref);
+asp_tag_name(
+ unique int tag: @asp_open_tag ref,
+ string name: string ref);
+asp_tag_isempty(int tag: @asp_open_tag ref);
+
+/* Common Intermediate Language - CIL */
+
+case @cil_instruction.opcode of
+ 0 = @cil_nop
+| 1 = @cil_break
+| 2 = @cil_ldarg_0
+| 3 = @cil_ldarg_1
+| 4 = @cil_ldarg_2
+| 5 = @cil_ldarg_3
+| 6 = @cil_ldloc_0
+| 7 = @cil_ldloc_1
+| 8 = @cil_ldloc_2
+| 9 = @cil_ldloc_3
+| 10 = @cil_stloc_0
+| 11 = @cil_stloc_1
+| 12 = @cil_stloc_2
+| 13 = @cil_stloc_3
+| 14 = @cil_ldarg_s
+| 15 = @cil_ldarga_s
+| 16 = @cil_starg_s
+| 17 = @cil_ldloc_s
+| 18 = @cil_ldloca_s
+| 19 = @cil_stloc_s
+| 20 = @cil_ldnull
+| 21 = @cil_ldc_i4_m1
+| 22 = @cil_ldc_i4_0
+| 23 = @cil_ldc_i4_1
+| 24 = @cil_ldc_i4_2
+| 25 = @cil_ldc_i4_3
+| 26 = @cil_ldc_i4_4
+| 27 = @cil_ldc_i4_5
+| 28 = @cil_ldc_i4_6
+| 29 = @cil_ldc_i4_7
+| 30 = @cil_ldc_i4_8
+| 31 = @cil_ldc_i4_s
+| 32 = @cil_ldc_i4
+| 33 = @cil_ldc_i8
+| 34 = @cil_ldc_r4
+| 35 = @cil_ldc_r8
+| 37 = @cil_dup
+| 38 = @cil_pop
+| 39 = @cil_jmp
+| 40 = @cil_call
+| 41 = @cil_calli
+| 42 = @cil_ret
+| 43 = @cil_br_s
+| 44 = @cil_brfalse_s
+| 45 = @cil_brtrue_s
+| 46 = @cil_beq_s
+| 47 = @cil_bge_s
+| 48 = @cil_bgt_s
+| 49 = @cil_ble_s
+| 50 = @cil_blt_s
+| 51 = @cil_bne_un_s
+| 52 = @cil_bge_un_s
+| 53 = @cil_bgt_un_s
+| 54 = @cil_ble_un_s
+| 55 = @cil_blt_un_s
+| 56 = @cil_br
+| 57 = @cil_brfalse
+| 58 = @cil_brtrue
+| 59 = @cil_beq
+| 60 = @cil_bge
+| 61 = @cil_bgt
+| 62 = @cil_ble
+| 63 = @cil_blt
+| 64 = @cil_bne_un
+| 65 = @cil_bge_un
+| 66 = @cil_bgt_un
+| 67 = @cil_ble_un
+| 68 = @cil_blt_un
+| 69 = @cil_switch
+| 70 = @cil_ldind_i1
+| 71 = @cil_ldind_u1
+| 72 = @cil_ldind_i2
+| 73 = @cil_ldind_u2
+| 74 = @cil_ldind_i4
+| 75 = @cil_ldind_u4
+| 76 = @cil_ldind_i8
+| 77 = @cil_ldind_i
+| 78 = @cil_ldind_r4
+| 79 = @cil_ldind_r8
+| 80 = @cil_ldind_ref
+| 81 = @cil_stind_ref
+| 82 = @cil_stind_i1
+| 83 = @cil_stind_i2
+| 84 = @cil_stind_i4
+| 85 = @cil_stind_i8
+| 86 = @cil_stind_r4
+| 87 = @cil_stind_r8
+| 88 = @cil_add
+| 89 = @cil_sub
+| 90 = @cil_mul
+| 91 = @cil_div
+| 92 = @cil_div_un
+| 93 = @cil_rem
+| 94 = @cil_rem_un
+| 95 = @cil_and
+| 96 = @cil_or
+| 97 = @cil_xor
+| 98 = @cil_shl
+| 99 = @cil_shr
+| 100 = @cil_shr_un
+| 101 = @cil_neg
+| 102 = @cil_not
+| 103 = @cil_conv_i1
+| 104 = @cil_conv_i2
+| 105 = @cil_conv_i4
+| 106 = @cil_conv_i8
+| 107 = @cil_conv_r4
+| 108 = @cil_conv_r8
+| 109 = @cil_conv_u4
+| 110 = @cil_conv_u8
+| 111 = @cil_callvirt
+| 112 = @cil_cpobj
+| 113 = @cil_ldobj
+| 114 = @cil_ldstr
+| 115 = @cil_newobj
+| 116 = @cil_castclass
+| 117 = @cil_isinst
+| 118 = @cil_conv_r_un
+| 121 = @cil_unbox
+| 122 = @cil_throw
+| 123 = @cil_ldfld
+| 124 = @cil_ldflda
+| 125 = @cil_stfld
+| 126 = @cil_ldsfld
+| 127 = @cil_ldsflda
+| 128 = @cil_stsfld
+| 129 = @cil_stobj
+| 130 = @cil_conv_ovf_i1_un
+| 131 = @cil_conv_ovf_i2_un
+| 132 = @cil_conv_ovf_i4_un
+| 133 = @cil_conv_ovf_i8_un
+| 134 = @cil_conv_ovf_u1_un
+| 135 = @cil_conv_ovf_u2_un
+| 136 = @cil_conv_ovf_u4_un
+| 137 = @cil_conv_ovf_u8_un
+| 138 = @cil_conv_ovf_i_un
+| 139 = @cil_conv_ovf_u_un
+| 140 = @cil_box
+| 141 = @cil_newarr
+| 142 = @cil_ldlen
+| 143 = @cil_ldelema
+| 144 = @cil_ldelem_i1
+| 145 = @cil_ldelem_u1
+| 146 = @cil_ldelem_i2
+| 147 = @cil_ldelem_u2
+| 148 = @cil_ldelem_i4
+| 149 = @cil_ldelem_u4
+| 150 = @cil_ldelem_i8
+| 151 = @cil_ldelem_i
+| 152 = @cil_ldelem_r4
+| 153 = @cil_ldelem_r8
+| 154 = @cil_ldelem_ref
+| 155 = @cil_stelem_i
+| 156 = @cil_stelem_i1
+| 157 = @cil_stelem_i2
+| 158 = @cil_stelem_i4
+| 159 = @cil_stelem_i8
+| 160 = @cil_stelem_r4
+| 161 = @cil_stelem_r8
+| 162 = @cil_stelem_ref
+| 163 = @cil_ldelem
+| 164 = @cil_stelem
+| 165 = @cil_unbox_any
+| 179 = @cil_conv_ovf_i1
+| 180 = @cil_conv_ovf_u1
+| 181 = @cil_conv_ovf_i2
+| 182 = @cil_conv_ovf_u2
+| 183 = @cil_conv_ovf_i4
+| 184 = @cil_conv_ovf_u4
+| 185 = @cil_conv_ovf_i8
+| 186 = @cil_conv_ovf_u8
+| 194 = @cil_refanyval
+| 195 = @cil_ckinfinite
+| 198 = @cil_mkrefany
+| 208 = @cil_ldtoken
+| 209 = @cil_conv_u2
+| 210 = @cil_conv_u1
+| 211 = @cil_conv_i
+| 212 = @cil_conv_ovf_i
+| 213 = @cil_conv_ovf_u
+| 214 = @cil_add_ovf
+| 215 = @cil_add_ovf_un
+| 216 = @cil_mul_ovf
+| 217 = @cil_mul_ovf_un
+| 218 = @cil_sub_ovf
+| 219 = @cil_sub_ovf_un
+| 220 = @cil_endfinally
+| 221 = @cil_leave
+| 222 = @cil_leave_s
+| 223 = @cil_stind_i
+| 224 = @cil_conv_u
+| 65024 = @cil_arglist
+| 65025 = @cil_ceq
+| 65026 = @cil_cgt
+| 65027 = @cil_cgt_un
+| 65028 = @cil_clt
+| 65029 = @cil_clt_un
+| 65030 = @cil_ldftn
+| 65031 = @cil_ldvirtftn
+| 65033 = @cil_ldarg
+| 65034 = @cil_ldarga
+| 65035 = @cil_starg
+| 65036 = @cil_ldloc
+| 65037 = @cil_ldloca
+| 65038 = @cil_stloc
+| 65039 = @cil_localloc
+| 65041 = @cil_endfilter
+| 65042 = @cil_unaligned
+| 65043 = @cil_volatile
+| 65044 = @cil_tail
+| 65045 = @cil_initobj
+| 65046 = @cil_constrained
+| 65047 = @cil_cpblk
+| 65048 = @cil_initblk
+| 65050 = @cil_rethrow
+| 65052 = @cil_sizeof
+| 65053 = @cil_refanytype
+| 65054 = @cil_readonly
+;
+
+// CIL ignored instructions
+
+@cil_ignore = @cil_nop | @cil_break | @cil_volatile | @cil_unaligned;
+
+// CIL local/parameter/field access
+
+@cil_ldarg_any = @cil_ldarg_0 | @cil_ldarg_1 | @cil_ldarg_2 | @cil_ldarg_3 | @cil_ldarg_s | @cil_ldarga_s | @cil_ldarg | @cil_ldarga;
+@cil_starg_any = @cil_starg | @cil_starg_s;
+
+@cil_ldloc_any = @cil_ldloc_0 | @cil_ldloc_1 | @cil_ldloc_2 | @cil_ldloc_3 | @cil_ldloc_s | @cil_ldloca_s | @cil_ldloc | @cil_ldloca;
+@cil_stloc_any = @cil_stloc_0 | @cil_stloc_1 | @cil_stloc_2 | @cil_stloc_3 | @cil_stloc_s | @cil_stloc;
+
+@cil_ldfld_any = @cil_ldfld | @cil_ldsfld | @cil_ldsflda | @cil_ldflda;
+@cil_stfld_any = @cil_stfld | @cil_stsfld;
+
+@cil_local_access = @cil_stloc_any | @cil_ldloc_any;
+@cil_arg_access = @cil_starg_any | @cil_ldarg_any;
+@cil_read_access = @cil_ldloc_any | @cil_ldarg_any | @cil_ldfld_any;
+@cil_write_access = @cil_stloc_any | @cil_starg_any | @cil_stfld_any;
+
+@cil_stack_access = @cil_local_access | @cil_arg_access;
+@cil_field_access = @cil_ldfld_any | @cil_stfld_any;
+
+@cil_access = @cil_read_access | @cil_write_access;
+
+// CIL constant/literal instructions
+
+@cil_ldc_i = @cil_ldc_i4_any | @cil_ldc_i8;
+
+@cil_ldc_i4_any = @cil_ldc_i4_m1 | @cil_ldc_i4_0 | @cil_ldc_i4_1 | @cil_ldc_i4_2 | @cil_ldc_i4_3 |
+ @cil_ldc_i4_4 | @cil_ldc_i4_5 | @cil_ldc_i4_6 | @cil_ldc_i4_7 | @cil_ldc_i4_8 | @cil_ldc_i4_s | @cil_ldc_i4;
+
+@cil_ldc_r = @cil_ldc_r4 | @cil_ldc_r8;
+
+@cil_literal = @cil_ldnull | @cil_ldc_i | @cil_ldc_r | @cil_ldstr;
+
+// Control flow
+
+@cil_conditional_jump = @cil_binary_jump | @cil_unary_jump;
+@cil_binary_jump = @cil_beq_s | @cil_bge_s | @cil_bgt_s | @cil_ble_s | @cil_blt_s |
+ @cil_bne_un_s | @cil_bge_un_s | @cil_bgt_un_s | @cil_ble_un_s | @cil_blt_un_s |
+ @cil_beq | @cil_bge | @cil_bgt | @cil_ble | @cil_blt |
+ @cil_bne_un | @cil_bge_un | @cil_bgt_un | @cil_ble_un | @cil_blt_un;
+@cil_unary_jump = @cil_brfalse_s | @cil_brtrue_s | @cil_brfalse | @cil_brtrue | @cil_switch;
+@cil_unconditional_jump = @cil_br | @cil_br_s | @cil_leave_any;
+@cil_leave_any = @cil_leave | @cil_leave_s;
+@cil_jump = @cil_unconditional_jump | @cil_conditional_jump;
+
+// CIL call instructions
+
+@cil_call_any = @cil_jmp | @cil_call | @cil_calli | @cil_tail | @cil_callvirt | @cil_newobj;
+
+// CIL expression instructions
+
+@cil_expr = @cil_literal | @cil_binary_expr | @cil_unary_expr | @cil_call_any | @cil_read_access |
+ @cil_newarr | @cil_ldtoken | @cil_sizeof |
+ @cil_ldftn | @cil_ldvirtftn | @cil_localloc | @cil_mkrefany | @cil_refanytype | @cil_arglist | @cil_dup;
+
+@cil_unary_expr =
+ @cil_conversion_operation | @cil_unary_arithmetic_operation | @cil_unary_bitwise_operation|
+ @cil_ldlen | @cil_isinst | @cil_box | @cil_ldobj | @cil_castclass | @cil_unbox_any |
+ @cil_ldind | @cil_unbox;
+
+@cil_conversion_operation =
+ @cil_conv_i1 | @cil_conv_i2 | @cil_conv_i4 | @cil_conv_i8 |
+ @cil_conv_u1 | @cil_conv_u2 | @cil_conv_u4 | @cil_conv_u8 |
+ @cil_conv_ovf_i | @cil_conv_ovf_i_un | @cil_conv_ovf_i1 | @cil_conv_ovf_i1_un |
+ @cil_conv_ovf_i2 | @cil_conv_ovf_i2_un | @cil_conv_ovf_i4 | @cil_conv_ovf_i4_un |
+ @cil_conv_ovf_i8 | @cil_conv_ovf_i8_un | @cil_conv_ovf_u | @cil_conv_ovf_u_un |
+ @cil_conv_ovf_u1 | @cil_conv_ovf_u1_un | @cil_conv_ovf_u2 | @cil_conv_ovf_u2_un |
+ @cil_conv_ovf_u4 | @cil_conv_ovf_u4_un | @cil_conv_ovf_u8 | @cil_conv_ovf_u8_un |
+ @cil_conv_r4 | @cil_conv_r8 | @cil_conv_ovf_u2 | @cil_conv_ovf_u2_un |
+ @cil_conv_i | @cil_conv_u | @cil_conv_r_un;
+
+@cil_ldind = @cil_ldind_i | @cil_ldind_i1 | @cil_ldind_i2 | @cil_ldind_i4 | @cil_ldind_i8 |
+ @cil_ldind_r4 | @cil_ldind_r8 | @cil_ldind_ref | @cil_ldind_u1 | @cil_ldind_u2 | @cil_ldind_u4;
+
+@cil_stind = @cil_stind_i | @cil_stind_i1 | @cil_stind_i2 | @cil_stind_i4 | @cil_stind_i8 |
+ @cil_stind_r4 | @cil_stind_r8 | @cil_stind_ref;
+
+@cil_bitwise_operation = @cil_binary_bitwise_operation | @cil_unary_bitwise_operation;
+
+@cil_binary_bitwise_operation = @cil_and | @cil_or | @cil_xor | @cil_shr | @cil_shr | @cil_shr_un | @cil_shl;
+
+@cil_binary_arithmetic_operation = @cil_add | @cil_sub | @cil_mul | @cil_div | @cil_div_un |
+ @cil_rem | @cil_rem_un | @cil_add_ovf | @cil_add_ovf_un | @cil_mul_ovf | @cil_mul_ovf_un |
+ @cil_sub_ovf | @cil_sub_ovf_un;
+
+@cil_unary_bitwise_operation = @cil_not;
+
+@cil_binary_expr = @cil_binary_arithmetic_operation | @cil_binary_bitwise_operation | @cil_read_array | @cil_comparison_operation;
+
+@cil_unary_arithmetic_operation = @cil_neg;
+
+@cil_comparison_operation = @cil_cgt_un | @cil_ceq | @cil_cgt | @cil_clt | @cil_clt_un;
+
+// Elements that retrieve an address of something
+@cil_read_ref = @cil_ldloca_s | @cil_ldarga_s | @cil_ldflda | @cil_ldsflda | @cil_ldelema;
+
+// CIL array instructions
+
+@cil_read_array =
+ @cil_ldelem | @cil_ldelema | @cil_ldelem_i1 | @cil_ldelem_ref | @cil_ldelem_i |
+ @cil_ldelem_i1 | @cil_ldelem_i2 | @cil_ldelem_i4 | @cil_ldelem_i8 | @cil_ldelem_r4 |
+ @cil_ldelem_r8 | @cil_ldelem_u1 | @cil_ldelem_u2 | @cil_ldelem_u4;
+
+@cil_write_array = @cil_stelem | @cil_stelem_ref |
+ @cil_stelem_i | @cil_stelem_i1 | @cil_stelem_i2 | @cil_stelem_i4 | @cil_stelem_i8 |
+ @cil_stelem_r4 | @cil_stelem_r8;
+
+@cil_throw_any = @cil_throw | @cil_rethrow;
+
+#keyset[impl, index]
+cil_instruction(
+ unique int id: @cil_instruction,
+ int opcode: int ref,
+ int index: int ref,
+ int impl: @cil_method_implementation ref);
+
+cil_jump(
+ unique int instruction: @cil_jump ref,
+ int target: @cil_instruction ref);
+
+cil_access(
+ unique int instruction: @cil_instruction ref,
+ int target: @cil_accessible ref);
+
+cil_value(
+ unique int instruction: @cil_literal ref,
+ string value: string ref);
+
+#keyset[instruction, index]
+cil_switch(
+ int instruction: @cil_switch ref,
+ int index: int ref,
+ int target: @cil_instruction ref);
+
+cil_instruction_location(
+ unique int id: @cil_instruction ref,
+ int loc: @location ref);
+
+cil_type_location(
+ int id: @cil_type ref,
+ int loc: @location ref);
+
+cil_method_location(
+ int id: @cil_method ref,
+ int loc: @location ref);
+
+@cil_namespace = @namespace;
+
+@cil_type_container = @cil_type | @cil_namespace | @cil_method;
+
+case @cil_type.kind of
+ 0 = @cil_valueorreftype
+| 1 = @cil_typeparameter
+| 2 = @cil_array_type
+| 3 = @cil_pointer_type
+| 4 = @cil_function_pointer_type
+;
+
+cil_type(
+ unique int id: @cil_type,
+ string name: string ref,
+ int kind: int ref,
+ int parent: @cil_type_container ref,
+ int sourceDecl: @cil_type ref);
+
+cil_pointer_type(
+ unique int id: @cil_pointer_type ref,
+ int pointee: @cil_type ref);
+
+cil_array_type(
+ unique int id: @cil_array_type ref,
+ int element_type: @cil_type ref,
+ int rank: int ref);
+
+cil_function_pointer_return_type(
+ unique int id: @cil_function_pointer_type ref,
+ int return_type: @cil_type ref);
+
+cil_method(
+ unique int id: @cil_method,
+ string name: string ref,
+ int parent: @cil_type ref,
+ int return_type: @cil_type ref);
+
+cil_method_source_declaration(
+ unique int method: @cil_method ref,
+ int source: @cil_method ref);
+
+cil_method_implementation(
+ unique int id: @cil_method_implementation,
+ int method: @cil_method ref,
+ int location: @assembly ref);
+
+cil_implements(
+ int id: @cil_method ref,
+ int decl: @cil_method ref);
+
+#keyset[parent, name]
+cil_field(
+ unique int id: @cil_field,
+ int parent: @cil_type ref,
+ string name: string ref,
+ int field_type: @cil_type ref);
+
+@cil_element = @cil_instruction | @cil_declaration | @cil_handler | @cil_attribute | @cil_namespace;
+@cil_named_element = @cil_declaration | @cil_namespace;
+@cil_declaration = @cil_variable | @cil_method | @cil_type | @cil_member;
+@cil_accessible = @cil_declaration;
+@cil_variable = @cil_field | @cil_stack_variable;
+@cil_stack_variable = @cil_local_variable | @cil_parameter;
+@cil_member = @cil_method | @cil_type | @cil_field | @cil_property | @cil_event;
+@cil_custom_modifier_receiver = @cil_method | @cil_property | @cil_parameter | @cil_field | @cil_function_pointer_type;
+@cil_parameterizable = @cil_method | @cil_function_pointer_type;
+@cil_has_type_annotation = @cil_stack_variable | @cil_property | @cil_method | @cil_function_pointer_type;
+
+#keyset[parameterizable, index]
+cil_parameter(
+ unique int id: @cil_parameter,
+ int parameterizable: @cil_parameterizable ref,
+ int index: int ref,
+ int param_type: @cil_type ref);
+
+cil_parameter_in(unique int id: @cil_parameter ref);
+cil_parameter_out(unique int id: @cil_parameter ref);
+
+cil_setter(unique int prop: @cil_property ref,
+ int method: @cil_method ref);
+
+#keyset[id, modifier]
+cil_custom_modifiers(
+ int id: @cil_custom_modifier_receiver ref,
+ int modifier: @cil_type ref,
+ int kind: int ref); // modreq: 1, modopt: 0
+
+cil_type_annotation(
+ int id: @cil_has_type_annotation ref,
+ int annotation: int ref);
+
+cil_getter(unique int prop: @cil_property ref,
+ int method: @cil_method ref);
+
+cil_adder(unique int event: @cil_event ref,
+ int method: @cil_method ref);
+
+cil_remover(unique int event: @cil_event ref, int method: @cil_method ref);
+
+cil_raiser(unique int event: @cil_event ref, int method: @cil_method ref);
+
+cil_property(
+ unique int id: @cil_property,
+ int parent: @cil_type ref,
+ string name: string ref,
+ int property_type: @cil_type ref);
+
+#keyset[parent, name]
+cil_event(unique int id: @cil_event,
+ int parent: @cil_type ref,
+ string name: string ref,
+ int event_type: @cil_type ref);
+
+#keyset[impl, index]
+cil_local_variable(
+ unique int id: @cil_local_variable,
+ int impl: @cil_method_implementation ref,
+ int index: int ref,
+ int var_type: @cil_type ref);
+
+cil_function_pointer_calling_conventions(
+ int id: @cil_function_pointer_type ref,
+ int kind: int ref);
+
+// CIL handlers (exception handlers etc).
+
+case @cil_handler.kind of
+ 0 = @cil_catch_handler
+| 1 = @cil_filter_handler
+| 2 = @cil_finally_handler
+| 4 = @cil_fault_handler
+;
+
+#keyset[impl, index]
+cil_handler(
+ unique int id: @cil_handler,
+ int impl: @cil_method_implementation ref,
+ int index: int ref,
+ int kind: int ref,
+ int try_start: @cil_instruction ref,
+ int try_end: @cil_instruction ref,
+ int handler_start: @cil_instruction ref);
+
+cil_handler_filter(
+ unique int id: @cil_handler ref,
+ int filter_start: @cil_instruction ref);
+
+cil_handler_type(
+ unique int id: @cil_handler ref,
+ int catch_type: @cil_type ref);
+
+@cil_controlflow_node = @cil_entry_point | @cil_instruction;
+
+@cil_entry_point = @cil_method_implementation | @cil_handler;
+
+@cil_dataflow_node = @cil_instruction | @cil_variable | @cil_method;
+
+cil_method_stack_size(
+ unique int method: @cil_method_implementation ref,
+ int size: int ref);
+
+// CIL modifiers
+
+cil_public(int id: @cil_member ref);
+cil_private(int id: @cil_member ref);
+cil_protected(int id: @cil_member ref);
+cil_internal(int id: @cil_member ref);
+cil_static(int id: @cil_member ref);
+cil_sealed(int id: @cil_member ref);
+cil_virtual(int id: @cil_method ref);
+cil_abstract(int id: @cil_member ref);
+cil_class(int id: @cil_type ref);
+cil_interface(int id: @cil_type ref);
+cil_security(int id: @cil_member ref);
+cil_requiresecobject(int id: @cil_method ref);
+cil_specialname(int id: @cil_method ref);
+cil_newslot(int id: @cil_method ref);
+
+cil_base_class(unique int id: @cil_type ref, int base: @cil_type ref);
+cil_base_interface(int id: @cil_type ref, int base: @cil_type ref);
+cil_enum_underlying_type(unique int id: @cil_type ref, int underlying: @cil_type ref);
+
+#keyset[unbound, index]
+cil_type_parameter(
+ int unbound: @cil_member ref,
+ int index: int ref,
+ int param: @cil_typeparameter ref);
+
+#keyset[bound, index]
+cil_type_argument(
+ int bound: @cil_member ref,
+ int index: int ref,
+ int t: @cil_type ref);
+
+// CIL type parameter constraints
+
+cil_typeparam_covariant(int tp: @cil_typeparameter ref);
+cil_typeparam_contravariant(int tp: @cil_typeparameter ref);
+cil_typeparam_class(int tp: @cil_typeparameter ref);
+cil_typeparam_struct(int tp: @cil_typeparameter ref);
+cil_typeparam_new(int tp: @cil_typeparameter ref);
+cil_typeparam_constraint(int tp: @cil_typeparameter ref, int supertype: @cil_type ref);
+
+// CIL attributes
+
+cil_attribute(
+ unique int attributeid: @cil_attribute,
+ int element: @cil_declaration ref,
+ int constructor: @cil_method ref);
+
+#keyset[attribute_id, param]
+cil_attribute_named_argument(
+ int attribute_id: @cil_attribute ref,
+ string param: string ref,
+ string value: string ref);
+
+#keyset[attribute_id, index]
+cil_attribute_positional_argument(
+ int attribute_id: @cil_attribute ref,
+ int index: int ref,
+ string value: string ref);
+
+
+// Common .Net data model covering both C# and CIL
+
+// Common elements
+@dotnet_element = @element | @cil_element;
+@dotnet_named_element = @named_element | @cil_named_element;
+@dotnet_callable = @callable | @cil_method;
+@dotnet_variable = @variable | @cil_variable;
+@dotnet_field = @field | @cil_field;
+@dotnet_parameter = @parameter | @cil_parameter;
+@dotnet_declaration = @declaration | @cil_declaration;
+@dotnet_member = @member | @cil_member;
+@dotnet_event = @event | @cil_event;
+@dotnet_property = @property | @cil_property | @indexer;
+@dotnet_parameterizable = @parameterizable | @cil_parameterizable;
+
+// Common types
+@dotnet_type = @type | @cil_type;
+@dotnet_call = @call | @cil_call_any;
+@dotnet_throw = @throw_element | @cil_throw_any;
+@dotnet_valueorreftype = @cil_valueorreftype | @value_or_ref_type | @cil_array_type | @void_type;
+@dotnet_typeparameter = @type_parameter | @cil_typeparameter;
+@dotnet_array_type = @array_type | @cil_array_type;
+@dotnet_pointer_type = @pointer_type | @cil_pointer_type;
+@dotnet_type_parameter = @type_parameter | @cil_typeparameter;
+@dotnet_generic = @dotnet_valueorreftype | @dotnet_callable;
+
+// Attributes
+@dotnet_attribute = @attribute | @cil_attribute;
+
+// Expressions
+@dotnet_expr = @expr | @cil_expr;
+
+// Literals
+@dotnet_literal = @literal_expr | @cil_literal;
+@dotnet_string_literal = @string_literal_expr | @cil_ldstr;
+@dotnet_int_literal = @integer_literal_expr | @cil_ldc_i;
+@dotnet_float_literal = @float_literal_expr | @cil_ldc_r;
+@dotnet_null_literal = @null_literal_expr | @cil_ldnull;
+
+@metadata_entity = @cil_method | @cil_type | @cil_field | @cil_property | @field | @property |
+ @callable | @value_or_ref_type | @void_type;
+
+#keyset[entity, location]
+metadata_handle(int entity : @metadata_entity ref, int location: @assembly ref, int handle: int ref)
diff --git a/csharp/downgrades/d0fba103f7dee477dd7d9f6c038518b3f683b2c7/upgrade.properties b/csharp/downgrades/d0fba103f7dee477dd7d9f6c038518b3f683b2c7/upgrade.properties
new file mode 100644
index 00000000000..d3e8b5e6318
--- /dev/null
+++ b/csharp/downgrades/d0fba103f7dee477dd7d9f6c038518b3f683b2c7/upgrade.properties
@@ -0,0 +1,3 @@
+description: Remove unsigned right shift and unsigned right shift assignment expression kinds.
+compatibility: backwards
+expressions.rel: run expressions.qlo
\ No newline at end of file
diff --git a/csharp/ql/lib/upgrades/83aca6b3e4fa38dd2b97b9b51dfc199a2ba9c7f2/old.dbscheme b/csharp/ql/lib/upgrades/83aca6b3e4fa38dd2b97b9b51dfc199a2ba9c7f2/old.dbscheme
new file mode 100644
index 00000000000..83aca6b3e4f
--- /dev/null
+++ b/csharp/ql/lib/upgrades/83aca6b3e4fa38dd2b97b9b51dfc199a2ba9c7f2/old.dbscheme
@@ -0,0 +1,2067 @@
+/* This is a dummy line to alter the dbscheme, so we can make a database upgrade
+ * without actually changing any of the dbscheme predicates. It contains a date
+ * to allow for such updates in the future as well.
+ *
+ * 2021-07-14
+ *
+ * DO NOT remove this comment carelessly, since it can revert the dbscheme back to a
+ * previously seen state (matching a previously seen SHA), which would make the upgrade
+ * mechanism not work properly.
+ */
+
+/**
+ * An invocation of the compiler. Note that more than one file may be
+ * compiled per invocation. For example, this command compiles three
+ * source files:
+ *
+ * csc f1.cs f2.cs f3.cs
+ *
+ * The `id` simply identifies the invocation, while `cwd` is the working
+ * directory from which the compiler was invoked.
+ */
+compilations(
+ unique int id : @compilation,
+ string cwd : string ref
+);
+
+/**
+ * The arguments that were passed to the extractor for a compiler
+ * invocation. If `id` is for the compiler invocation
+ *
+ * csc f1.cs f2.cs f3.cs
+ *
+ * then typically there will be rows for
+ *
+ * num | arg
+ * --- | ---
+ * 0 | --compiler
+ * 1 | *path to compiler*
+ * 2 | f1.cs
+ * 3 | f2.cs
+ * 4 | f3.cs
+ */
+#keyset[id, num]
+compilation_args(
+ int id : @compilation ref,
+ int num : int ref,
+ string arg : string ref
+);
+
+/**
+ * The source files that are compiled by a compiler invocation.
+ * If `id` is for the compiler invocation
+ *
+ * csc f1.cs f2.cs f3.cs
+ *
+ * then there will be rows for
+ *
+ * num | arg
+ * --- | ---
+ * 0 | f1.cs
+ * 1 | f2.cs
+ * 2 | f3.cs
+ */
+#keyset[id, num]
+compilation_compiling_files(
+ int id : @compilation ref,
+ int num : int ref,
+ int file : @file ref
+);
+
+/**
+ * The references used by a compiler invocation.
+ * If `id` is for the compiler invocation
+ *
+ * csc f1.cs f2.cs f3.cs /r:ref1.dll /r:ref2.dll /r:ref3.dll
+ *
+ * then there will be rows for
+ *
+ * num | arg
+ * --- | ---
+ * 0 | ref1.dll
+ * 1 | ref2.dll
+ * 2 | ref3.dll
+ */
+#keyset[id, num]
+compilation_referencing_files(
+ int id : @compilation ref,
+ int num : int ref,
+ int file : @file ref
+);
+
+/**
+ * The time taken by the extractor for a compiler invocation.
+ *
+ * For each file `num`, there will be rows for
+ *
+ * kind | seconds
+ * ---- | ---
+ * 1 | CPU seconds used by the extractor frontend
+ * 2 | Elapsed seconds during the extractor frontend
+ * 3 | CPU seconds used by the extractor backend
+ * 4 | Elapsed seconds during the extractor backend
+ */
+#keyset[id, num, kind]
+compilation_time(
+ int id : @compilation ref,
+ int num : int ref,
+ /* kind:
+ 1 = frontend_cpu_seconds
+ 2 = frontend_elapsed_seconds
+ 3 = extractor_cpu_seconds
+ 4 = extractor_elapsed_seconds
+ */
+ int kind : int ref,
+ float seconds : float ref
+);
+
+/**
+ * An error or warning generated by the extractor.
+ * The diagnostic message `diagnostic` was generated during compiler
+ * invocation `compilation`, and is the `file_number_diagnostic_number`th
+ * message generated while extracting the `file_number`th file of that
+ * invocation.
+ */
+#keyset[compilation, file_number, file_number_diagnostic_number]
+diagnostic_for(
+ unique int diagnostic : @diagnostic ref,
+ int compilation : @compilation ref,
+ int file_number : int ref,
+ int file_number_diagnostic_number : int ref
+);
+
+diagnostics(
+ unique int id: @diagnostic,
+ int severity: int ref,
+ string error_tag: string ref,
+ string error_message: string ref,
+ string full_error_message: string ref,
+ int location: @location_default ref
+);
+
+extractor_messages(
+ unique int id: @extractor_message,
+ int severity: int ref,
+ string origin : string ref,
+ string text : string ref,
+ string entity : string ref,
+ int location: @location_default ref,
+ string stack_trace : string ref
+);
+
+/**
+ * If extraction was successful, then `cpu_seconds` and
+ * `elapsed_seconds` are the CPU time and elapsed time (respectively)
+ * that extraction took for compiler invocation `id`.
+ */
+compilation_finished(
+ unique int id : @compilation ref,
+ float cpu_seconds : float ref,
+ float elapsed_seconds : float ref
+);
+
+compilation_assembly(
+ unique int id : @compilation ref,
+ int assembly: @assembly ref
+)
+
+// Populated by the CSV extractor
+externalData(
+ int id: @externalDataElement,
+ string path: string ref,
+ int column: int ref,
+ string value: string ref);
+
+sourceLocationPrefix(
+ string prefix: string ref);
+
+/*
+ * C# dbscheme
+ */
+
+/** ELEMENTS **/
+
+@element = @declaration | @stmt | @expr | @modifier | @attribute | @namespace_declaration
+ | @using_directive | @type_parameter_constraints | @externalDataElement
+ | @xmllocatable | @asp_element | @namespace | @preprocessor_directive;
+
+@declaration = @callable | @generic | @assignable | @namespace;
+
+@named_element = @namespace | @declaration;
+
+@declaration_with_accessors = @property | @indexer | @event;
+
+@assignable = @variable | @assignable_with_accessors | @event;
+
+@assignable_with_accessors = @property | @indexer;
+
+@attributable = @assembly | @field | @parameter | @operator | @method | @constructor
+ | @destructor | @callable_accessor | @value_or_ref_type | @declaration_with_accessors
+ | @local_function | @lambda_expr;
+
+/** LOCATIONS, ASEMMBLIES, MODULES, FILES and FOLDERS **/
+
+@location = @location_default | @assembly;
+
+locations_default(
+ unique int id: @location_default,
+ int file: @file ref,
+ int beginLine: int ref,
+ int beginColumn: int ref,
+ int endLine: int ref,
+ int endColumn: int ref);
+
+locations_mapped(
+ unique int id: @location_default ref,
+ int mapped_to: @location_default ref);
+
+@sourceline = @file | @callable | @xmllocatable;
+
+numlines(
+ int element_id: @sourceline ref,
+ int num_lines: int ref,
+ int num_code: int ref,
+ int num_comment: int ref);
+
+assemblies(
+ unique int id: @assembly,
+ int file: @file ref,
+ string fullname: string ref,
+ string name: string ref,
+ string version: string ref);
+
+files(
+ unique int id: @file,
+ string name: string ref);
+
+folders(
+ unique int id: @folder,
+ string name: string ref);
+
+@container = @folder | @file ;
+
+containerparent(
+ int parent: @container ref,
+ unique int child: @container ref);
+
+file_extraction_mode(
+ unique int file: @file ref,
+ int mode: int ref
+ /* 0 = normal, 1 = standalone extractor */
+ );
+
+/** NAMESPACES **/
+
+@type_container = @namespace | @type;
+
+namespaces(
+ unique int id: @namespace,
+ string name: string ref);
+
+namespace_declarations(
+ unique int id: @namespace_declaration,
+ int namespace_id: @namespace ref);
+
+namespace_declaration_location(
+ unique int id: @namespace_declaration ref,
+ int loc: @location ref);
+
+parent_namespace(
+ unique int child_id: @type_container ref,
+ int namespace_id: @namespace ref);
+
+@declaration_or_directive = @namespace_declaration | @type | @using_directive;
+
+parent_namespace_declaration(
+ int child_id: @declaration_or_directive ref, // cannot be unique because of partial classes
+ int namespace_id: @namespace_declaration ref);
+
+@using_directive = @using_namespace_directive | @using_static_directive;
+
+using_global(
+ unique int id: @using_directive ref
+);
+
+using_namespace_directives(
+ unique int id: @using_namespace_directive,
+ int namespace_id: @namespace ref);
+
+using_static_directives(
+ unique int id: @using_static_directive,
+ int type_id: @type_or_ref ref);
+
+using_directive_location(
+ unique int id: @using_directive ref,
+ int loc: @location ref);
+
+@preprocessor_directive = @pragma_warning | @pragma_checksum | @directive_define | @directive_undefine | @directive_warning
+ | @directive_error | @directive_nullable | @directive_line | @directive_region | @directive_endregion | @directive_if
+ | @directive_elif | @directive_else | @directive_endif;
+
+@conditional_directive = @directive_if | @directive_elif;
+@branch_directive = @directive_if | @directive_elif | @directive_else;
+
+directive_ifs(
+ unique int id: @directive_if,
+ int branchTaken: int ref, /* 0: false, 1: true */
+ int conditionValue: int ref); /* 0: false, 1: true */
+
+directive_elifs(
+ unique int id: @directive_elif,
+ int branchTaken: int ref, /* 0: false, 1: true */
+ int conditionValue: int ref, /* 0: false, 1: true */
+ int parent: @directive_if ref,
+ int index: int ref);
+
+directive_elses(
+ unique int id: @directive_else,
+ int branchTaken: int ref, /* 0: false, 1: true */
+ int parent: @directive_if ref,
+ int index: int ref);
+
+#keyset[id, start]
+directive_endifs(
+ unique int id: @directive_endif,
+ unique int start: @directive_if ref);
+
+directive_define_symbols(
+ unique int id: @define_symbol_expr ref,
+ string name: string ref);
+
+directive_regions(
+ unique int id: @directive_region,
+ string name: string ref);
+
+#keyset[id, start]
+directive_endregions(
+ unique int id: @directive_endregion,
+ unique int start: @directive_region ref);
+
+directive_lines(
+ unique int id: @directive_line,
+ int kind: int ref); /* 0: default, 1: hidden, 2: numeric, 3: span */
+
+directive_line_value(
+ unique int id: @directive_line ref,
+ int line: int ref);
+
+directive_line_file(
+ unique int id: @directive_line ref,
+ int file: @file ref);
+
+directive_line_offset(
+ unique int id: @directive_line ref,
+ int offset: int ref);
+
+directive_line_span(
+ unique int id: @directive_line ref,
+ int startLine: int ref,
+ int startColumn: int ref,
+ int endLine: int ref,
+ int endColumn: int ref);
+
+directive_nullables(
+ unique int id: @directive_nullable,
+ int setting: int ref, /* 0: disable, 1: enable, 2: restore */
+ int target: int ref); /* 0: none, 1: annotations, 2: warnings */
+
+directive_warnings(
+ unique int id: @directive_warning,
+ string message: string ref);
+
+directive_errors(
+ unique int id: @directive_error,
+ string message: string ref);
+
+directive_undefines(
+ unique int id: @directive_undefine,
+ string name: string ref);
+
+directive_defines(
+ unique int id: @directive_define,
+ string name: string ref);
+
+pragma_checksums(
+ unique int id: @pragma_checksum,
+ int file: @file ref,
+ string guid: string ref,
+ string bytes: string ref);
+
+pragma_warnings(
+ unique int id: @pragma_warning,
+ int kind: int ref /* 0 = disable, 1 = restore */);
+
+#keyset[id, index]
+pragma_warning_error_codes(
+ int id: @pragma_warning ref,
+ string errorCode: string ref,
+ int index: int ref);
+
+preprocessor_directive_location(
+ unique int id: @preprocessor_directive ref,
+ int loc: @location ref);
+
+preprocessor_directive_compilation(
+ unique int id: @preprocessor_directive ref,
+ int compilation: @compilation ref);
+
+preprocessor_directive_active(
+ unique int id: @preprocessor_directive ref,
+ int active: int ref); /* 0: false, 1: true */
+
+/** TYPES **/
+
+types(
+ unique int id: @type,
+ int kind: int ref,
+ string name: string ref);
+
+case @type.kind of
+ 1 = @bool_type
+| 2 = @char_type
+| 3 = @decimal_type
+| 4 = @sbyte_type
+| 5 = @short_type
+| 6 = @int_type
+| 7 = @long_type
+| 8 = @byte_type
+| 9 = @ushort_type
+| 10 = @uint_type
+| 11 = @ulong_type
+| 12 = @float_type
+| 13 = @double_type
+| 14 = @enum_type
+| 15 = @struct_type
+| 17 = @class_type
+| 19 = @interface_type
+| 20 = @delegate_type
+| 21 = @null_type
+| 22 = @type_parameter
+| 23 = @pointer_type
+| 24 = @nullable_type
+| 25 = @array_type
+| 26 = @void_type
+| 27 = @int_ptr_type
+| 28 = @uint_ptr_type
+| 29 = @dynamic_type
+| 30 = @arglist_type
+| 31 = @unknown_type
+| 32 = @tuple_type
+| 33 = @function_pointer_type
+ ;
+
+@simple_type = @bool_type | @char_type | @integral_type | @floating_point_type | @decimal_type;
+@integral_type = @signed_integral_type | @unsigned_integral_type;
+@signed_integral_type = @sbyte_type | @short_type | @int_type | @long_type;
+@unsigned_integral_type = @byte_type | @ushort_type | @uint_type | @ulong_type;
+@floating_point_type = @float_type | @double_type;
+@value_type = @simple_type | @enum_type | @struct_type | @nullable_type | @int_ptr_type
+ | @uint_ptr_type | @tuple_type;
+@ref_type = @class_type | @interface_type | @array_type | @delegate_type | @null_type
+ | @dynamic_type;
+@value_or_ref_type = @value_type | @ref_type;
+
+typerefs(
+ unique int id: @typeref,
+ string name: string ref);
+
+typeref_type(
+ int id: @typeref ref,
+ unique int typeId: @type ref);
+
+@type_or_ref = @type | @typeref;
+
+array_element_type(
+ unique int array: @array_type ref,
+ int dimension: int ref,
+ int rank: int ref,
+ int element: @type_or_ref ref);
+
+nullable_underlying_type(
+ unique int nullable: @nullable_type ref,
+ int underlying: @type_or_ref ref);
+
+pointer_referent_type(
+ unique int pointer: @pointer_type ref,
+ int referent: @type_or_ref ref);
+
+enum_underlying_type(
+ unique int enum_id: @enum_type ref,
+ int underlying_type_id: @type_or_ref ref);
+
+delegate_return_type(
+ unique int delegate_id: @delegate_type ref,
+ int return_type_id: @type_or_ref ref);
+
+function_pointer_return_type(
+ unique int function_pointer_id: @function_pointer_type ref,
+ int return_type_id: @type_or_ref ref);
+
+extend(
+ int sub: @type ref,
+ int super: @type_or_ref ref);
+
+anonymous_types(
+ unique int id: @type ref);
+
+@interface_or_ref = @interface_type | @typeref;
+
+implement(
+ int sub: @type ref,
+ int super: @type_or_ref ref);
+
+type_location(
+ int id: @type ref,
+ int loc: @location ref);
+
+tuple_underlying_type(
+ unique int tuple: @tuple_type ref,
+ int struct: @type_or_ref ref);
+
+#keyset[tuple, index]
+tuple_element(
+ int tuple: @tuple_type ref,
+ int index: int ref,
+ unique int field: @field ref);
+
+attributes(
+ unique int id: @attribute,
+ int kind: int ref,
+ int type_id: @type_or_ref ref,
+ int target: @attributable ref);
+
+case @attribute.kind of
+ 0 = @attribute_default
+| 1 = @attribute_return
+| 2 = @attribute_assembly
+| 3 = @attribute_module
+;
+
+attribute_location(
+ int id: @attribute ref,
+ int loc: @location ref);
+
+@type_mention_parent = @element | @type_mention;
+
+type_mention(
+ unique int id: @type_mention,
+ int type_id: @type_or_ref ref,
+ int parent: @type_mention_parent ref);
+
+type_mention_location(
+ unique int id: @type_mention ref,
+ int loc: @location ref);
+
+@has_type_annotation = @assignable | @type_parameter | @callable | @expr | @delegate_type | @generic | @function_pointer_type;
+
+/**
+ * A direct annotation on an entity, for example `string? x;`.
+ *
+ * Annotations:
+ * 2 = reftype is not annotated "!"
+ * 3 = reftype is annotated "?"
+ * 4 = readonly ref type / in parameter
+ * 5 = ref type parameter, return or local variable
+ * 6 = out parameter
+ *
+ * Note that the annotation depends on the element it annotates.
+ * @assignable: The annotation is on the type of the assignable, for example the variable type.
+ * @type_parameter: The annotation is on the reftype constraint
+ * @callable: The annotation is on the return type
+ * @array_type: The annotation is on the element type
+ */
+type_annotation(int id: @has_type_annotation ref, int annotation: int ref);
+
+nullability(unique int nullability: @nullability, int kind: int ref);
+
+case @nullability.kind of
+ 0 = @oblivious
+| 1 = @not_annotated
+| 2 = @annotated
+;
+
+#keyset[parent, index]
+nullability_parent(int nullability: @nullability ref, int index: int ref, int parent: @nullability ref)
+
+type_nullability(int id: @has_type_annotation ref, int nullability: @nullability ref);
+
+/**
+ * The nullable flow state of an expression, as determined by Roslyn.
+ * 0 = none (default, not populated)
+ * 1 = not null
+ * 2 = maybe null
+ */
+expr_flowstate(unique int id: @expr ref, int state: int ref);
+
+/** GENERICS **/
+
+@generic = @type | @method | @local_function;
+
+type_parameters(
+ unique int id: @type_parameter ref,
+ int index: int ref,
+ int generic_id: @generic ref,
+ int variance: int ref /* none = 0, out = 1, in = 2 */);
+
+#keyset[constructed_id, index]
+type_arguments(
+ int id: @type_or_ref ref,
+ int index: int ref,
+ int constructed_id: @generic_or_ref ref);
+
+@generic_or_ref = @generic | @typeref;
+
+constructed_generic(
+ unique int constructed: @generic ref,
+ int generic: @generic_or_ref ref);
+
+type_parameter_constraints(
+ unique int id: @type_parameter_constraints,
+ int param_id: @type_parameter ref);
+
+type_parameter_constraints_location(
+ int id: @type_parameter_constraints ref,
+ int loc: @location ref);
+
+general_type_parameter_constraints(
+ int id: @type_parameter_constraints ref,
+ int kind: int ref /* class = 1, struct = 2, new = 3 */);
+
+specific_type_parameter_constraints(
+ int id: @type_parameter_constraints ref,
+ int base_id: @type_or_ref ref);
+
+specific_type_parameter_nullability(
+ int id: @type_parameter_constraints ref,
+ int base_id: @type_or_ref ref,
+ int nullability: @nullability ref);
+
+/** FUNCTION POINTERS */
+
+function_pointer_calling_conventions(
+ int id: @function_pointer_type ref,
+ int kind: int ref);
+
+#keyset[id, index]
+has_unmanaged_calling_conventions(
+ int id: @function_pointer_type ref,
+ int index: int ref,
+ int conv_id: @type_or_ref ref);
+
+/** MODIFIERS */
+
+@modifiable = @modifiable_direct | @event_accessor;
+
+@modifiable_direct = @member | @accessor | @local_function | @anonymous_function_expr;
+
+modifiers(
+ unique int id: @modifier,
+ string name: string ref);
+
+has_modifiers(
+ int id: @modifiable_direct ref,
+ int mod_id: @modifier ref);
+
+compiler_generated(unique int id: @modifiable ref);
+
+/** MEMBERS **/
+
+@member = @method | @constructor | @destructor | @field | @property | @event | @operator | @indexer | @type;
+
+@named_exprorstmt = @goto_stmt | @labeled_stmt | @expr;
+
+@virtualizable = @method | @property | @indexer | @event;
+
+exprorstmt_name(
+ unique int parent_id: @named_exprorstmt ref,
+ string name: string ref);
+
+nested_types(
+ unique int id: @type ref,
+ int declaring_type_id: @type ref,
+ int unbound_id: @type ref);
+
+properties(
+ unique int id: @property,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @property ref);
+
+property_location(
+ int id: @property ref,
+ int loc: @location ref);
+
+indexers(
+ unique int id: @indexer,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @indexer ref);
+
+indexer_location(
+ int id: @indexer ref,
+ int loc: @location ref);
+
+accessors(
+ unique int id: @accessor,
+ int kind: int ref,
+ string name: string ref,
+ int declaring_member_id: @member ref,
+ int unbound_id: @accessor ref);
+
+case @accessor.kind of
+ 1 = @getter
+| 2 = @setter
+ ;
+
+init_only_accessors(
+ unique int id: @accessor ref);
+
+accessor_location(
+ int id: @accessor ref,
+ int loc: @location ref);
+
+events(
+ unique int id: @event,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @event ref);
+
+event_location(
+ int id: @event ref,
+ int loc: @location ref);
+
+event_accessors(
+ unique int id: @event_accessor,
+ int kind: int ref,
+ string name: string ref,
+ int declaring_event_id: @event ref,
+ int unbound_id: @event_accessor ref);
+
+case @event_accessor.kind of
+ 1 = @add_event_accessor
+| 2 = @remove_event_accessor
+ ;
+
+event_accessor_location(
+ int id: @event_accessor ref,
+ int loc: @location ref);
+
+operators(
+ unique int id: @operator,
+ string name: string ref,
+ string symbol: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @operator ref);
+
+operator_location(
+ int id: @operator ref,
+ int loc: @location ref);
+
+constant_value(
+ int id: @variable ref,
+ string value: string ref);
+
+/** CALLABLES **/
+
+@callable = @method | @constructor | @destructor | @operator | @callable_accessor | @anonymous_function_expr | @local_function;
+
+@callable_accessor = @accessor | @event_accessor;
+
+methods(
+ unique int id: @method,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @method ref);
+
+method_location(
+ int id: @method ref,
+ int loc: @location ref);
+
+constructors(
+ unique int id: @constructor,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int unbound_id: @constructor ref);
+
+constructor_location(
+ int id: @constructor ref,
+ int loc: @location ref);
+
+destructors(
+ unique int id: @destructor,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int unbound_id: @destructor ref);
+
+destructor_location(
+ int id: @destructor ref,
+ int loc: @location ref);
+
+overrides(
+ int id: @callable ref,
+ int base_id: @callable ref);
+
+explicitly_implements(
+ int id: @member ref,
+ int interface_id: @interface_or_ref ref);
+
+local_functions(
+ unique int id: @local_function,
+ string name: string ref,
+ int return_type: @type ref,
+ int unbound_id: @local_function ref);
+
+local_function_stmts(
+ unique int fn: @local_function_stmt ref,
+ int stmt: @local_function ref);
+
+/** VARIABLES **/
+
+@variable = @local_scope_variable | @field;
+
+@local_scope_variable = @local_variable | @parameter;
+
+fields(
+ unique int id: @field,
+ int kind: int ref,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @field ref);
+
+case @field.kind of
+ 1 = @addressable_field
+| 2 = @constant
+ ;
+
+field_location(
+ int id: @field ref,
+ int loc: @location ref);
+
+localvars(
+ unique int id: @local_variable,
+ int kind: int ref,
+ string name: string ref,
+ int implicitly_typed: int ref /* 0 = no, 1 = yes */,
+ int type_id: @type_or_ref ref,
+ int parent_id: @local_var_decl_expr ref);
+
+case @local_variable.kind of
+ 1 = @addressable_local_variable
+| 2 = @local_constant
+| 3 = @local_variable_ref
+ ;
+
+localvar_location(
+ unique int id: @local_variable ref,
+ int loc: @location ref);
+
+@parameterizable = @callable | @delegate_type | @indexer | @function_pointer_type;
+
+#keyset[name, parent_id]
+#keyset[index, parent_id]
+params(
+ unique int id: @parameter,
+ string name: string ref,
+ int type_id: @type_or_ref ref,
+ int index: int ref,
+ int mode: int ref, /* value = 0, ref = 1, out = 2, array = 3, this = 4 */
+ int parent_id: @parameterizable ref,
+ int unbound_id: @parameter ref);
+
+param_location(
+ int id: @parameter ref,
+ int loc: @location ref);
+
+/** STATEMENTS **/
+
+@exprorstmt_parent = @control_flow_element | @top_level_exprorstmt_parent;
+
+statements(
+ unique int id: @stmt,
+ int kind: int ref);
+
+#keyset[index, parent]
+stmt_parent(
+ unique int stmt: @stmt ref,
+ int index: int ref,
+ int parent: @control_flow_element ref);
+
+@top_level_stmt_parent = @callable;
+
+// [index, parent] is not a keyset because the same parent may be compiled multiple times
+stmt_parent_top_level(
+ unique int stmt: @stmt ref,
+ int index: int ref,
+ int parent: @top_level_stmt_parent ref);
+
+case @stmt.kind of
+ 1 = @block_stmt
+| 2 = @expr_stmt
+| 3 = @if_stmt
+| 4 = @switch_stmt
+| 5 = @while_stmt
+| 6 = @do_stmt
+| 7 = @for_stmt
+| 8 = @foreach_stmt
+| 9 = @break_stmt
+| 10 = @continue_stmt
+| 11 = @goto_stmt
+| 12 = @goto_case_stmt
+| 13 = @goto_default_stmt
+| 14 = @throw_stmt
+| 15 = @return_stmt
+| 16 = @yield_stmt
+| 17 = @try_stmt
+| 18 = @checked_stmt
+| 19 = @unchecked_stmt
+| 20 = @lock_stmt
+| 21 = @using_block_stmt
+| 22 = @var_decl_stmt
+| 23 = @const_decl_stmt
+| 24 = @empty_stmt
+| 25 = @unsafe_stmt
+| 26 = @fixed_stmt
+| 27 = @label_stmt
+| 28 = @catch
+| 29 = @case_stmt
+| 30 = @local_function_stmt
+| 31 = @using_decl_stmt
+ ;
+
+@using_stmt = @using_block_stmt | @using_decl_stmt;
+
+@labeled_stmt = @label_stmt | @case;
+
+@decl_stmt = @var_decl_stmt | @const_decl_stmt | @using_decl_stmt;
+
+@cond_stmt = @if_stmt | @switch_stmt;
+
+@loop_stmt = @while_stmt | @do_stmt | @for_stmt | @foreach_stmt;
+
+@jump_stmt = @break_stmt | @goto_any_stmt | @continue_stmt | @throw_stmt | @return_stmt
+ | @yield_stmt;
+
+@goto_any_stmt = @goto_default_stmt | @goto_case_stmt | @goto_stmt;
+
+
+stmt_location(
+ unique int id: @stmt ref,
+ int loc: @location ref);
+
+catch_type(
+ unique int catch_id: @catch ref,
+ int type_id: @type_or_ref ref,
+ int kind: int ref /* explicit = 1, implicit = 2 */);
+
+foreach_stmt_info(
+ unique int id: @foreach_stmt ref,
+ int kind: int ref /* non-async = 1, async = 2 */);
+
+@foreach_symbol = @method | @property | @type_or_ref;
+
+#keyset[id, kind]
+foreach_stmt_desugar(
+ int id: @foreach_stmt ref,
+ int symbol: @foreach_symbol ref,
+ int kind: int ref /* GetEnumeratorMethod = 1, CurrentProperty = 2, MoveNextMethod = 3, DisposeMethod = 4, ElementType = 5 */);
+
+/** EXPRESSIONS **/
+
+expressions(
+ unique int id: @expr,
+ int kind: int ref,
+ int type_id: @type_or_ref ref);
+
+#keyset[index, parent]
+expr_parent(
+ unique int expr: @expr ref,
+ int index: int ref,
+ int parent: @control_flow_element ref);
+
+@top_level_expr_parent = @attribute | @field | @property | @indexer | @parameter | @directive_if | @directive_elif;
+
+@top_level_exprorstmt_parent = @top_level_expr_parent | @top_level_stmt_parent;
+
+// [index, parent] is not a keyset because the same parent may be compiled multiple times
+expr_parent_top_level(
+ unique int expr: @expr ref,
+ int index: int ref,
+ int parent: @top_level_exprorstmt_parent ref);
+
+case @expr.kind of
+/* literal */
+ 1 = @bool_literal_expr
+| 2 = @char_literal_expr
+| 3 = @decimal_literal_expr
+| 4 = @int_literal_expr
+| 5 = @long_literal_expr
+| 6 = @uint_literal_expr
+| 7 = @ulong_literal_expr
+| 8 = @float_literal_expr
+| 9 = @double_literal_expr
+| 10 = @string_literal_expr
+| 11 = @null_literal_expr
+/* primary & unary */
+| 12 = @this_access_expr
+| 13 = @base_access_expr
+| 14 = @local_variable_access_expr
+| 15 = @parameter_access_expr
+| 16 = @field_access_expr
+| 17 = @property_access_expr
+| 18 = @method_access_expr
+| 19 = @event_access_expr
+| 20 = @indexer_access_expr
+| 21 = @array_access_expr
+| 22 = @type_access_expr
+| 23 = @typeof_expr
+| 24 = @method_invocation_expr
+| 25 = @delegate_invocation_expr
+| 26 = @operator_invocation_expr
+| 27 = @cast_expr
+| 28 = @object_creation_expr
+| 29 = @explicit_delegate_creation_expr
+| 30 = @implicit_delegate_creation_expr
+| 31 = @array_creation_expr
+| 32 = @default_expr
+| 33 = @plus_expr
+| 34 = @minus_expr
+| 35 = @bit_not_expr
+| 36 = @log_not_expr
+| 37 = @post_incr_expr
+| 38 = @post_decr_expr
+| 39 = @pre_incr_expr
+| 40 = @pre_decr_expr
+/* multiplicative */
+| 41 = @mul_expr
+| 42 = @div_expr
+| 43 = @rem_expr
+/* additive */
+| 44 = @add_expr
+| 45 = @sub_expr
+/* shift */
+| 46 = @lshift_expr
+| 47 = @rshift_expr
+/* relational */
+| 48 = @lt_expr
+| 49 = @gt_expr
+| 50 = @le_expr
+| 51 = @ge_expr
+/* equality */
+| 52 = @eq_expr
+| 53 = @ne_expr
+/* logical */
+| 54 = @bit_and_expr
+| 55 = @bit_xor_expr
+| 56 = @bit_or_expr
+| 57 = @log_and_expr
+| 58 = @log_or_expr
+/* type testing */
+| 59 = @is_expr
+| 60 = @as_expr
+/* null coalescing */
+| 61 = @null_coalescing_expr
+/* conditional */
+| 62 = @conditional_expr
+/* assignment */
+| 63 = @simple_assign_expr
+| 64 = @assign_add_expr
+| 65 = @assign_sub_expr
+| 66 = @assign_mul_expr
+| 67 = @assign_div_expr
+| 68 = @assign_rem_expr
+| 69 = @assign_and_expr
+| 70 = @assign_xor_expr
+| 71 = @assign_or_expr
+| 72 = @assign_lshift_expr
+| 73 = @assign_rshift_expr
+/* more */
+| 74 = @object_init_expr
+| 75 = @collection_init_expr
+| 76 = @array_init_expr
+| 77 = @checked_expr
+| 78 = @unchecked_expr
+| 79 = @constructor_init_expr
+| 80 = @add_event_expr
+| 81 = @remove_event_expr
+| 82 = @par_expr
+| 83 = @local_var_decl_expr
+| 84 = @lambda_expr
+| 85 = @anonymous_method_expr
+| 86 = @namespace_expr
+/* dynamic */
+| 92 = @dynamic_element_access_expr
+| 93 = @dynamic_member_access_expr
+/* unsafe */
+| 100 = @pointer_indirection_expr
+| 101 = @address_of_expr
+| 102 = @sizeof_expr
+/* async */
+| 103 = @await_expr
+/* C# 6.0 */
+| 104 = @nameof_expr
+| 105 = @interpolated_string_expr
+| 106 = @unknown_expr
+/* C# 7.0 */
+| 107 = @throw_expr
+| 108 = @tuple_expr
+| 109 = @local_function_invocation_expr
+| 110 = @ref_expr
+| 111 = @discard_expr
+/* C# 8.0 */
+| 112 = @range_expr
+| 113 = @index_expr
+| 114 = @switch_expr
+| 115 = @recursive_pattern_expr
+| 116 = @property_pattern_expr
+| 117 = @positional_pattern_expr
+| 118 = @switch_case_expr
+| 119 = @assign_coalesce_expr
+| 120 = @suppress_nullable_warning_expr
+| 121 = @namespace_access_expr
+/* C# 9.0 */
+| 122 = @lt_pattern_expr
+| 123 = @gt_pattern_expr
+| 124 = @le_pattern_expr
+| 125 = @ge_pattern_expr
+| 126 = @not_pattern_expr
+| 127 = @and_pattern_expr
+| 128 = @or_pattern_expr
+| 129 = @function_pointer_invocation_expr
+| 130 = @with_expr
+/* C# 11.0 */
+| 131 = @list_pattern_expr
+| 132 = @slice_pattern_expr
+/* Preprocessor */
+| 999 = @define_symbol_expr
+;
+
+@switch = @switch_stmt | @switch_expr;
+@case = @case_stmt | @switch_case_expr;
+@pattern_match = @case | @is_expr;
+@unary_pattern_expr = @not_pattern_expr;
+@relational_pattern_expr = @gt_pattern_expr | @lt_pattern_expr | @ge_pattern_expr | @le_pattern_expr;
+@binary_pattern_expr = @and_pattern_expr | @or_pattern_expr;
+
+@integer_literal_expr = @int_literal_expr | @long_literal_expr | @uint_literal_expr | @ulong_literal_expr;
+@real_literal_expr = @float_literal_expr | @double_literal_expr | @decimal_literal_expr;
+@literal_expr = @bool_literal_expr | @char_literal_expr | @integer_literal_expr | @real_literal_expr
+ | @string_literal_expr | @null_literal_expr;
+
+@assign_expr = @simple_assign_expr | @assign_op_expr | @local_var_decl_expr;
+@assign_op_expr = @assign_arith_expr | @assign_bitwise_expr | @assign_event_expr | @assign_coalesce_expr;
+@assign_event_expr = @add_event_expr | @remove_event_expr;
+
+@assign_arith_expr = @assign_add_expr | @assign_sub_expr | @assign_mul_expr | @assign_div_expr
+ | @assign_rem_expr
+@assign_bitwise_expr = @assign_and_expr | @assign_or_expr | @assign_xor_expr
+ | @assign_lshift_expr | @assign_rshift_expr;
+
+@member_access_expr = @field_access_expr | @property_access_expr | @indexer_access_expr | @event_access_expr
+ | @method_access_expr | @type_access_expr | @dynamic_member_access_expr;
+@access_expr = @member_access_expr | @this_access_expr | @base_access_expr | @assignable_access_expr | @namespace_access_expr;
+@element_access_expr = @indexer_access_expr | @array_access_expr | @dynamic_element_access_expr;
+
+@local_variable_access = @local_variable_access_expr | @local_var_decl_expr;
+@local_scope_variable_access_expr = @parameter_access_expr | @local_variable_access;
+@variable_access_expr = @local_scope_variable_access_expr | @field_access_expr;
+
+@assignable_access_expr = @variable_access_expr | @property_access_expr | @element_access_expr
+ | @event_access_expr | @dynamic_member_access_expr;
+
+@objectorcollection_init_expr = @object_init_expr | @collection_init_expr;
+
+@delegate_creation_expr = @explicit_delegate_creation_expr | @implicit_delegate_creation_expr;
+
+@bin_arith_op_expr = @mul_expr | @div_expr | @rem_expr | @add_expr | @sub_expr;
+@incr_op_expr = @pre_incr_expr | @post_incr_expr;
+@decr_op_expr = @pre_decr_expr | @post_decr_expr;
+@mut_op_expr = @incr_op_expr | @decr_op_expr;
+@un_arith_op_expr = @plus_expr | @minus_expr | @mut_op_expr;
+@arith_op_expr = @bin_arith_op_expr | @un_arith_op_expr;
+
+@ternary_log_op_expr = @conditional_expr;
+@bin_log_op_expr = @log_and_expr | @log_or_expr | @null_coalescing_expr;
+@un_log_op_expr = @log_not_expr;
+@log_expr = @un_log_op_expr | @bin_log_op_expr | @ternary_log_op_expr;
+
+@bin_bit_op_expr = @bit_and_expr | @bit_or_expr | @bit_xor_expr | @lshift_expr
+ | @rshift_expr;
+@un_bit_op_expr = @bit_not_expr;
+@bit_expr = @un_bit_op_expr | @bin_bit_op_expr;
+
+@equality_op_expr = @eq_expr | @ne_expr;
+@rel_op_expr = @gt_expr | @lt_expr| @ge_expr | @le_expr;
+@comp_expr = @equality_op_expr | @rel_op_expr;
+
+@op_expr = @assign_expr | @un_op | @bin_op | @ternary_op;
+
+@ternary_op = @ternary_log_op_expr;
+@bin_op = @bin_arith_op_expr | @bin_log_op_expr | @bin_bit_op_expr | @comp_expr;
+@un_op = @un_arith_op_expr | @un_log_op_expr | @un_bit_op_expr | @sizeof_expr
+ | @pointer_indirection_expr | @address_of_expr;
+
+@anonymous_function_expr = @lambda_expr | @anonymous_method_expr;
+
+@call = @method_invocation_expr | @constructor_init_expr | @operator_invocation_expr
+ | @delegate_invocation_expr | @object_creation_expr | @call_access_expr
+ | @local_function_invocation_expr | @function_pointer_invocation_expr;
+
+@call_access_expr = @property_access_expr | @event_access_expr | @indexer_access_expr;
+
+@late_bindable_expr = @dynamic_element_access_expr | @dynamic_member_access_expr
+ | @object_creation_expr | @method_invocation_expr | @operator_invocation_expr;
+
+@throw_element = @throw_expr | @throw_stmt;
+
+@implicitly_typeable_object_creation_expr = @object_creation_expr | @explicit_delegate_creation_expr;
+
+implicitly_typed_array_creation(
+ unique int id: @array_creation_expr ref);
+
+explicitly_sized_array_creation(
+ unique int id: @array_creation_expr ref);
+
+stackalloc_array_creation(
+ unique int id: @array_creation_expr ref);
+
+implicitly_typed_object_creation(
+ unique int id: @implicitly_typeable_object_creation_expr ref);
+
+mutator_invocation_mode(
+ unique int id: @operator_invocation_expr ref,
+ int mode: int ref /* prefix = 1, postfix = 2*/);
+
+expr_compiler_generated(
+ unique int id: @expr ref);
+
+expr_value(
+ unique int id: @expr ref,
+ string value: string ref);
+
+expr_call(
+ unique int caller_id: @expr ref,
+ int target_id: @callable ref);
+
+expr_access(
+ unique int accesser_id: @access_expr ref,
+ int target_id: @accessible ref);
+
+@accessible = @method | @assignable | @local_function | @namespace;
+
+expr_location(
+ unique int id: @expr ref,
+ int loc: @location ref);
+
+dynamic_member_name(
+ unique int id: @late_bindable_expr ref,
+ string name: string ref);
+
+@qualifiable_expr = @member_access_expr
+ | @method_invocation_expr
+ | @element_access_expr;
+
+conditional_access(
+ unique int id: @qualifiable_expr ref);
+
+expr_argument(
+ unique int id: @expr ref,
+ int mode: int ref);
+ /* mode is the same as params: value = 0, ref = 1, out = 2 */
+
+expr_argument_name(
+ unique int id: @expr ref,
+ string name: string ref);
+
+lambda_expr_return_type(
+ unique int id: @lambda_expr ref,
+ int type_id: @type_or_ref ref);
+
+/** CONTROL/DATA FLOW **/
+
+@control_flow_element = @stmt | @expr;
+
+/* XML Files */
+
+xmlEncoding (
+ unique int id: @file ref,
+ string encoding: string ref);
+
+xmlDTDs(
+ unique int id: @xmldtd,
+ string root: string ref,
+ string publicId: string ref,
+ string systemId: string ref,
+ int fileid: @file ref);
+
+xmlElements(
+ unique int id: @xmlelement,
+ string name: string ref,
+ int parentid: @xmlparent ref,
+ int idx: int ref,
+ int fileid: @file ref);
+
+xmlAttrs(
+ unique int id: @xmlattribute,
+ int elementid: @xmlelement ref,
+ string name: string ref,
+ string value: string ref,
+ int idx: int ref,
+ int fileid: @file ref);
+
+xmlNs(
+ int id: @xmlnamespace,
+ string prefixName: string ref,
+ string URI: string ref,
+ int fileid: @file ref);
+
+xmlHasNs(
+ int elementId: @xmlnamespaceable ref,
+ int nsId: @xmlnamespace ref,
+ int fileid: @file ref);
+
+xmlComments(
+ unique int id: @xmlcomment,
+ string text: string ref,
+ int parentid: @xmlparent ref,
+ int fileid: @file ref);
+
+xmlChars(
+ unique int id: @xmlcharacters,
+ string text: string ref,
+ int parentid: @xmlparent ref,
+ int idx: int ref,
+ int isCDATA: int ref,
+ int fileid: @file ref);
+
+@xmlparent = @file | @xmlelement;
+@xmlnamespaceable = @xmlelement | @xmlattribute;
+
+xmllocations(
+ int xmlElement: @xmllocatable ref,
+ int location: @location_default ref);
+
+@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace;
+
+/* Comments */
+
+commentline(
+ unique int id: @commentline,
+ int kind: int ref,
+ string text: string ref,
+ string rawtext: string ref);
+
+case @commentline.kind of
+ 0 = @singlelinecomment
+| 1 = @xmldoccomment
+| 2 = @multilinecomment;
+
+commentline_location(
+ unique int id: @commentline ref,
+ int loc: @location ref);
+
+commentblock(
+ unique int id : @commentblock);
+
+commentblock_location(
+ unique int id: @commentblock ref,
+ int loc: @location ref);
+
+commentblock_binding(
+ int id: @commentblock ref,
+ int entity: @element ref,
+ int bindtype: int ref); /* 0: Parent, 1: Best, 2: Before, 3: After */
+
+commentblock_child(
+ int id: @commentblock ref,
+ int commentline: @commentline ref,
+ int index: int ref);
+
+/* ASP.NET */
+
+case @asp_element.kind of
+ 0=@asp_close_tag
+| 1=@asp_code
+| 2=@asp_comment
+| 3=@asp_data_binding
+| 4=@asp_directive
+| 5=@asp_open_tag
+| 6=@asp_quoted_string
+| 7=@asp_text
+| 8=@asp_xml_directive;
+
+@asp_attribute = @asp_code | @asp_data_binding | @asp_quoted_string;
+
+asp_elements(
+ unique int id: @asp_element,
+ int kind: int ref,
+ int loc: @location ref);
+
+asp_comment_server(unique int comment: @asp_comment ref);
+asp_code_inline(unique int code: @asp_code ref);
+asp_directive_attribute(
+ int directive: @asp_directive ref,
+ int index: int ref,
+ string name: string ref,
+ int value: @asp_quoted_string ref);
+asp_directive_name(
+ unique int directive: @asp_directive ref,
+ string name: string ref);
+asp_element_body(
+ unique int element: @asp_element ref,
+ string body: string ref);
+asp_tag_attribute(
+ int tag: @asp_open_tag ref,
+ int index: int ref,
+ string name: string ref,
+ int attribute: @asp_attribute ref);
+asp_tag_name(
+ unique int tag: @asp_open_tag ref,
+ string name: string ref);
+asp_tag_isempty(int tag: @asp_open_tag ref);
+
+/* Common Intermediate Language - CIL */
+
+case @cil_instruction.opcode of
+ 0 = @cil_nop
+| 1 = @cil_break
+| 2 = @cil_ldarg_0
+| 3 = @cil_ldarg_1
+| 4 = @cil_ldarg_2
+| 5 = @cil_ldarg_3
+| 6 = @cil_ldloc_0
+| 7 = @cil_ldloc_1
+| 8 = @cil_ldloc_2
+| 9 = @cil_ldloc_3
+| 10 = @cil_stloc_0
+| 11 = @cil_stloc_1
+| 12 = @cil_stloc_2
+| 13 = @cil_stloc_3
+| 14 = @cil_ldarg_s
+| 15 = @cil_ldarga_s
+| 16 = @cil_starg_s
+| 17 = @cil_ldloc_s
+| 18 = @cil_ldloca_s
+| 19 = @cil_stloc_s
+| 20 = @cil_ldnull
+| 21 = @cil_ldc_i4_m1
+| 22 = @cil_ldc_i4_0
+| 23 = @cil_ldc_i4_1
+| 24 = @cil_ldc_i4_2
+| 25 = @cil_ldc_i4_3
+| 26 = @cil_ldc_i4_4
+| 27 = @cil_ldc_i4_5
+| 28 = @cil_ldc_i4_6
+| 29 = @cil_ldc_i4_7
+| 30 = @cil_ldc_i4_8
+| 31 = @cil_ldc_i4_s
+| 32 = @cil_ldc_i4
+| 33 = @cil_ldc_i8
+| 34 = @cil_ldc_r4
+| 35 = @cil_ldc_r8
+| 37 = @cil_dup
+| 38 = @cil_pop
+| 39 = @cil_jmp
+| 40 = @cil_call
+| 41 = @cil_calli
+| 42 = @cil_ret
+| 43 = @cil_br_s
+| 44 = @cil_brfalse_s
+| 45 = @cil_brtrue_s
+| 46 = @cil_beq_s
+| 47 = @cil_bge_s
+| 48 = @cil_bgt_s
+| 49 = @cil_ble_s
+| 50 = @cil_blt_s
+| 51 = @cil_bne_un_s
+| 52 = @cil_bge_un_s
+| 53 = @cil_bgt_un_s
+| 54 = @cil_ble_un_s
+| 55 = @cil_blt_un_s
+| 56 = @cil_br
+| 57 = @cil_brfalse
+| 58 = @cil_brtrue
+| 59 = @cil_beq
+| 60 = @cil_bge
+| 61 = @cil_bgt
+| 62 = @cil_ble
+| 63 = @cil_blt
+| 64 = @cil_bne_un
+| 65 = @cil_bge_un
+| 66 = @cil_bgt_un
+| 67 = @cil_ble_un
+| 68 = @cil_blt_un
+| 69 = @cil_switch
+| 70 = @cil_ldind_i1
+| 71 = @cil_ldind_u1
+| 72 = @cil_ldind_i2
+| 73 = @cil_ldind_u2
+| 74 = @cil_ldind_i4
+| 75 = @cil_ldind_u4
+| 76 = @cil_ldind_i8
+| 77 = @cil_ldind_i
+| 78 = @cil_ldind_r4
+| 79 = @cil_ldind_r8
+| 80 = @cil_ldind_ref
+| 81 = @cil_stind_ref
+| 82 = @cil_stind_i1
+| 83 = @cil_stind_i2
+| 84 = @cil_stind_i4
+| 85 = @cil_stind_i8
+| 86 = @cil_stind_r4
+| 87 = @cil_stind_r8
+| 88 = @cil_add
+| 89 = @cil_sub
+| 90 = @cil_mul
+| 91 = @cil_div
+| 92 = @cil_div_un
+| 93 = @cil_rem
+| 94 = @cil_rem_un
+| 95 = @cil_and
+| 96 = @cil_or
+| 97 = @cil_xor
+| 98 = @cil_shl
+| 99 = @cil_shr
+| 100 = @cil_shr_un
+| 101 = @cil_neg
+| 102 = @cil_not
+| 103 = @cil_conv_i1
+| 104 = @cil_conv_i2
+| 105 = @cil_conv_i4
+| 106 = @cil_conv_i8
+| 107 = @cil_conv_r4
+| 108 = @cil_conv_r8
+| 109 = @cil_conv_u4
+| 110 = @cil_conv_u8
+| 111 = @cil_callvirt
+| 112 = @cil_cpobj
+| 113 = @cil_ldobj
+| 114 = @cil_ldstr
+| 115 = @cil_newobj
+| 116 = @cil_castclass
+| 117 = @cil_isinst
+| 118 = @cil_conv_r_un
+| 121 = @cil_unbox
+| 122 = @cil_throw
+| 123 = @cil_ldfld
+| 124 = @cil_ldflda
+| 125 = @cil_stfld
+| 126 = @cil_ldsfld
+| 127 = @cil_ldsflda
+| 128 = @cil_stsfld
+| 129 = @cil_stobj
+| 130 = @cil_conv_ovf_i1_un
+| 131 = @cil_conv_ovf_i2_un
+| 132 = @cil_conv_ovf_i4_un
+| 133 = @cil_conv_ovf_i8_un
+| 134 = @cil_conv_ovf_u1_un
+| 135 = @cil_conv_ovf_u2_un
+| 136 = @cil_conv_ovf_u4_un
+| 137 = @cil_conv_ovf_u8_un
+| 138 = @cil_conv_ovf_i_un
+| 139 = @cil_conv_ovf_u_un
+| 140 = @cil_box
+| 141 = @cil_newarr
+| 142 = @cil_ldlen
+| 143 = @cil_ldelema
+| 144 = @cil_ldelem_i1
+| 145 = @cil_ldelem_u1
+| 146 = @cil_ldelem_i2
+| 147 = @cil_ldelem_u2
+| 148 = @cil_ldelem_i4
+| 149 = @cil_ldelem_u4
+| 150 = @cil_ldelem_i8
+| 151 = @cil_ldelem_i
+| 152 = @cil_ldelem_r4
+| 153 = @cil_ldelem_r8
+| 154 = @cil_ldelem_ref
+| 155 = @cil_stelem_i
+| 156 = @cil_stelem_i1
+| 157 = @cil_stelem_i2
+| 158 = @cil_stelem_i4
+| 159 = @cil_stelem_i8
+| 160 = @cil_stelem_r4
+| 161 = @cil_stelem_r8
+| 162 = @cil_stelem_ref
+| 163 = @cil_ldelem
+| 164 = @cil_stelem
+| 165 = @cil_unbox_any
+| 179 = @cil_conv_ovf_i1
+| 180 = @cil_conv_ovf_u1
+| 181 = @cil_conv_ovf_i2
+| 182 = @cil_conv_ovf_u2
+| 183 = @cil_conv_ovf_i4
+| 184 = @cil_conv_ovf_u4
+| 185 = @cil_conv_ovf_i8
+| 186 = @cil_conv_ovf_u8
+| 194 = @cil_refanyval
+| 195 = @cil_ckinfinite
+| 198 = @cil_mkrefany
+| 208 = @cil_ldtoken
+| 209 = @cil_conv_u2
+| 210 = @cil_conv_u1
+| 211 = @cil_conv_i
+| 212 = @cil_conv_ovf_i
+| 213 = @cil_conv_ovf_u
+| 214 = @cil_add_ovf
+| 215 = @cil_add_ovf_un
+| 216 = @cil_mul_ovf
+| 217 = @cil_mul_ovf_un
+| 218 = @cil_sub_ovf
+| 219 = @cil_sub_ovf_un
+| 220 = @cil_endfinally
+| 221 = @cil_leave
+| 222 = @cil_leave_s
+| 223 = @cil_stind_i
+| 224 = @cil_conv_u
+| 65024 = @cil_arglist
+| 65025 = @cil_ceq
+| 65026 = @cil_cgt
+| 65027 = @cil_cgt_un
+| 65028 = @cil_clt
+| 65029 = @cil_clt_un
+| 65030 = @cil_ldftn
+| 65031 = @cil_ldvirtftn
+| 65033 = @cil_ldarg
+| 65034 = @cil_ldarga
+| 65035 = @cil_starg
+| 65036 = @cil_ldloc
+| 65037 = @cil_ldloca
+| 65038 = @cil_stloc
+| 65039 = @cil_localloc
+| 65041 = @cil_endfilter
+| 65042 = @cil_unaligned
+| 65043 = @cil_volatile
+| 65044 = @cil_tail
+| 65045 = @cil_initobj
+| 65046 = @cil_constrained
+| 65047 = @cil_cpblk
+| 65048 = @cil_initblk
+| 65050 = @cil_rethrow
+| 65052 = @cil_sizeof
+| 65053 = @cil_refanytype
+| 65054 = @cil_readonly
+;
+
+// CIL ignored instructions
+
+@cil_ignore = @cil_nop | @cil_break | @cil_volatile | @cil_unaligned;
+
+// CIL local/parameter/field access
+
+@cil_ldarg_any = @cil_ldarg_0 | @cil_ldarg_1 | @cil_ldarg_2 | @cil_ldarg_3 | @cil_ldarg_s | @cil_ldarga_s | @cil_ldarg | @cil_ldarga;
+@cil_starg_any = @cil_starg | @cil_starg_s;
+
+@cil_ldloc_any = @cil_ldloc_0 | @cil_ldloc_1 | @cil_ldloc_2 | @cil_ldloc_3 | @cil_ldloc_s | @cil_ldloca_s | @cil_ldloc | @cil_ldloca;
+@cil_stloc_any = @cil_stloc_0 | @cil_stloc_1 | @cil_stloc_2 | @cil_stloc_3 | @cil_stloc_s | @cil_stloc;
+
+@cil_ldfld_any = @cil_ldfld | @cil_ldsfld | @cil_ldsflda | @cil_ldflda;
+@cil_stfld_any = @cil_stfld | @cil_stsfld;
+
+@cil_local_access = @cil_stloc_any | @cil_ldloc_any;
+@cil_arg_access = @cil_starg_any | @cil_ldarg_any;
+@cil_read_access = @cil_ldloc_any | @cil_ldarg_any | @cil_ldfld_any;
+@cil_write_access = @cil_stloc_any | @cil_starg_any | @cil_stfld_any;
+
+@cil_stack_access = @cil_local_access | @cil_arg_access;
+@cil_field_access = @cil_ldfld_any | @cil_stfld_any;
+
+@cil_access = @cil_read_access | @cil_write_access;
+
+// CIL constant/literal instructions
+
+@cil_ldc_i = @cil_ldc_i4_any | @cil_ldc_i8;
+
+@cil_ldc_i4_any = @cil_ldc_i4_m1 | @cil_ldc_i4_0 | @cil_ldc_i4_1 | @cil_ldc_i4_2 | @cil_ldc_i4_3 |
+ @cil_ldc_i4_4 | @cil_ldc_i4_5 | @cil_ldc_i4_6 | @cil_ldc_i4_7 | @cil_ldc_i4_8 | @cil_ldc_i4_s | @cil_ldc_i4;
+
+@cil_ldc_r = @cil_ldc_r4 | @cil_ldc_r8;
+
+@cil_literal = @cil_ldnull | @cil_ldc_i | @cil_ldc_r | @cil_ldstr;
+
+// Control flow
+
+@cil_conditional_jump = @cil_binary_jump | @cil_unary_jump;
+@cil_binary_jump = @cil_beq_s | @cil_bge_s | @cil_bgt_s | @cil_ble_s | @cil_blt_s |
+ @cil_bne_un_s | @cil_bge_un_s | @cil_bgt_un_s | @cil_ble_un_s | @cil_blt_un_s |
+ @cil_beq | @cil_bge | @cil_bgt | @cil_ble | @cil_blt |
+ @cil_bne_un | @cil_bge_un | @cil_bgt_un | @cil_ble_un | @cil_blt_un;
+@cil_unary_jump = @cil_brfalse_s | @cil_brtrue_s | @cil_brfalse | @cil_brtrue | @cil_switch;
+@cil_unconditional_jump = @cil_br | @cil_br_s | @cil_leave_any;
+@cil_leave_any = @cil_leave | @cil_leave_s;
+@cil_jump = @cil_unconditional_jump | @cil_conditional_jump;
+
+// CIL call instructions
+
+@cil_call_any = @cil_jmp | @cil_call | @cil_calli | @cil_tail | @cil_callvirt | @cil_newobj;
+
+// CIL expression instructions
+
+@cil_expr = @cil_literal | @cil_binary_expr | @cil_unary_expr | @cil_call_any | @cil_read_access |
+ @cil_newarr | @cil_ldtoken | @cil_sizeof |
+ @cil_ldftn | @cil_ldvirtftn | @cil_localloc | @cil_mkrefany | @cil_refanytype | @cil_arglist | @cil_dup;
+
+@cil_unary_expr =
+ @cil_conversion_operation | @cil_unary_arithmetic_operation | @cil_unary_bitwise_operation|
+ @cil_ldlen | @cil_isinst | @cil_box | @cil_ldobj | @cil_castclass | @cil_unbox_any |
+ @cil_ldind | @cil_unbox;
+
+@cil_conversion_operation =
+ @cil_conv_i1 | @cil_conv_i2 | @cil_conv_i4 | @cil_conv_i8 |
+ @cil_conv_u1 | @cil_conv_u2 | @cil_conv_u4 | @cil_conv_u8 |
+ @cil_conv_ovf_i | @cil_conv_ovf_i_un | @cil_conv_ovf_i1 | @cil_conv_ovf_i1_un |
+ @cil_conv_ovf_i2 | @cil_conv_ovf_i2_un | @cil_conv_ovf_i4 | @cil_conv_ovf_i4_un |
+ @cil_conv_ovf_i8 | @cil_conv_ovf_i8_un | @cil_conv_ovf_u | @cil_conv_ovf_u_un |
+ @cil_conv_ovf_u1 | @cil_conv_ovf_u1_un | @cil_conv_ovf_u2 | @cil_conv_ovf_u2_un |
+ @cil_conv_ovf_u4 | @cil_conv_ovf_u4_un | @cil_conv_ovf_u8 | @cil_conv_ovf_u8_un |
+ @cil_conv_r4 | @cil_conv_r8 | @cil_conv_ovf_u2 | @cil_conv_ovf_u2_un |
+ @cil_conv_i | @cil_conv_u | @cil_conv_r_un;
+
+@cil_ldind = @cil_ldind_i | @cil_ldind_i1 | @cil_ldind_i2 | @cil_ldind_i4 | @cil_ldind_i8 |
+ @cil_ldind_r4 | @cil_ldind_r8 | @cil_ldind_ref | @cil_ldind_u1 | @cil_ldind_u2 | @cil_ldind_u4;
+
+@cil_stind = @cil_stind_i | @cil_stind_i1 | @cil_stind_i2 | @cil_stind_i4 | @cil_stind_i8 |
+ @cil_stind_r4 | @cil_stind_r8 | @cil_stind_ref;
+
+@cil_bitwise_operation = @cil_binary_bitwise_operation | @cil_unary_bitwise_operation;
+
+@cil_binary_bitwise_operation = @cil_and | @cil_or | @cil_xor | @cil_shr | @cil_shr | @cil_shr_un | @cil_shl;
+
+@cil_binary_arithmetic_operation = @cil_add | @cil_sub | @cil_mul | @cil_div | @cil_div_un |
+ @cil_rem | @cil_rem_un | @cil_add_ovf | @cil_add_ovf_un | @cil_mul_ovf | @cil_mul_ovf_un |
+ @cil_sub_ovf | @cil_sub_ovf_un;
+
+@cil_unary_bitwise_operation = @cil_not;
+
+@cil_binary_expr = @cil_binary_arithmetic_operation | @cil_binary_bitwise_operation | @cil_read_array | @cil_comparison_operation;
+
+@cil_unary_arithmetic_operation = @cil_neg;
+
+@cil_comparison_operation = @cil_cgt_un | @cil_ceq | @cil_cgt | @cil_clt | @cil_clt_un;
+
+// Elements that retrieve an address of something
+@cil_read_ref = @cil_ldloca_s | @cil_ldarga_s | @cil_ldflda | @cil_ldsflda | @cil_ldelema;
+
+// CIL array instructions
+
+@cil_read_array =
+ @cil_ldelem | @cil_ldelema | @cil_ldelem_i1 | @cil_ldelem_ref | @cil_ldelem_i |
+ @cil_ldelem_i1 | @cil_ldelem_i2 | @cil_ldelem_i4 | @cil_ldelem_i8 | @cil_ldelem_r4 |
+ @cil_ldelem_r8 | @cil_ldelem_u1 | @cil_ldelem_u2 | @cil_ldelem_u4;
+
+@cil_write_array = @cil_stelem | @cil_stelem_ref |
+ @cil_stelem_i | @cil_stelem_i1 | @cil_stelem_i2 | @cil_stelem_i4 | @cil_stelem_i8 |
+ @cil_stelem_r4 | @cil_stelem_r8;
+
+@cil_throw_any = @cil_throw | @cil_rethrow;
+
+#keyset[impl, index]
+cil_instruction(
+ unique int id: @cil_instruction,
+ int opcode: int ref,
+ int index: int ref,
+ int impl: @cil_method_implementation ref);
+
+cil_jump(
+ unique int instruction: @cil_jump ref,
+ int target: @cil_instruction ref);
+
+cil_access(
+ unique int instruction: @cil_instruction ref,
+ int target: @cil_accessible ref);
+
+cil_value(
+ unique int instruction: @cil_literal ref,
+ string value: string ref);
+
+#keyset[instruction, index]
+cil_switch(
+ int instruction: @cil_switch ref,
+ int index: int ref,
+ int target: @cil_instruction ref);
+
+cil_instruction_location(
+ unique int id: @cil_instruction ref,
+ int loc: @location ref);
+
+cil_type_location(
+ int id: @cil_type ref,
+ int loc: @location ref);
+
+cil_method_location(
+ int id: @cil_method ref,
+ int loc: @location ref);
+
+@cil_namespace = @namespace;
+
+@cil_type_container = @cil_type | @cil_namespace | @cil_method;
+
+case @cil_type.kind of
+ 0 = @cil_valueorreftype
+| 1 = @cil_typeparameter
+| 2 = @cil_array_type
+| 3 = @cil_pointer_type
+| 4 = @cil_function_pointer_type
+;
+
+cil_type(
+ unique int id: @cil_type,
+ string name: string ref,
+ int kind: int ref,
+ int parent: @cil_type_container ref,
+ int sourceDecl: @cil_type ref);
+
+cil_pointer_type(
+ unique int id: @cil_pointer_type ref,
+ int pointee: @cil_type ref);
+
+cil_array_type(
+ unique int id: @cil_array_type ref,
+ int element_type: @cil_type ref,
+ int rank: int ref);
+
+cil_function_pointer_return_type(
+ unique int id: @cil_function_pointer_type ref,
+ int return_type: @cil_type ref);
+
+cil_method(
+ unique int id: @cil_method,
+ string name: string ref,
+ int parent: @cil_type ref,
+ int return_type: @cil_type ref);
+
+cil_method_source_declaration(
+ unique int method: @cil_method ref,
+ int source: @cil_method ref);
+
+cil_method_implementation(
+ unique int id: @cil_method_implementation,
+ int method: @cil_method ref,
+ int location: @assembly ref);
+
+cil_implements(
+ int id: @cil_method ref,
+ int decl: @cil_method ref);
+
+#keyset[parent, name]
+cil_field(
+ unique int id: @cil_field,
+ int parent: @cil_type ref,
+ string name: string ref,
+ int field_type: @cil_type ref);
+
+@cil_element = @cil_instruction | @cil_declaration | @cil_handler | @cil_attribute | @cil_namespace;
+@cil_named_element = @cil_declaration | @cil_namespace;
+@cil_declaration = @cil_variable | @cil_method | @cil_type | @cil_member;
+@cil_accessible = @cil_declaration;
+@cil_variable = @cil_field | @cil_stack_variable;
+@cil_stack_variable = @cil_local_variable | @cil_parameter;
+@cil_member = @cil_method | @cil_type | @cil_field | @cil_property | @cil_event;
+@cil_custom_modifier_receiver = @cil_method | @cil_property | @cil_parameter | @cil_field | @cil_function_pointer_type;
+@cil_parameterizable = @cil_method | @cil_function_pointer_type;
+@cil_has_type_annotation = @cil_stack_variable | @cil_property | @cil_method | @cil_function_pointer_type;
+
+#keyset[parameterizable, index]
+cil_parameter(
+ unique int id: @cil_parameter,
+ int parameterizable: @cil_parameterizable ref,
+ int index: int ref,
+ int param_type: @cil_type ref);
+
+cil_parameter_in(unique int id: @cil_parameter ref);
+cil_parameter_out(unique int id: @cil_parameter ref);
+
+cil_setter(unique int prop: @cil_property ref,
+ int method: @cil_method ref);
+
+#keyset[id, modifier]
+cil_custom_modifiers(
+ int id: @cil_custom_modifier_receiver ref,
+ int modifier: @cil_type ref,
+ int kind: int ref); // modreq: 1, modopt: 0
+
+cil_type_annotation(
+ int id: @cil_has_type_annotation ref,
+ int annotation: int ref);
+
+cil_getter(unique int prop: @cil_property ref,
+ int method: @cil_method ref);
+
+cil_adder(unique int event: @cil_event ref,
+ int method: @cil_method ref);
+
+cil_remover(unique int event: @cil_event ref, int method: @cil_method ref);
+
+cil_raiser(unique int event: @cil_event ref, int method: @cil_method ref);
+
+cil_property(
+ unique int id: @cil_property,
+ int parent: @cil_type ref,
+ string name: string ref,
+ int property_type: @cil_type ref);
+
+#keyset[parent, name]
+cil_event(unique int id: @cil_event,
+ int parent: @cil_type ref,
+ string name: string ref,
+ int event_type: @cil_type ref);
+
+#keyset[impl, index]
+cil_local_variable(
+ unique int id: @cil_local_variable,
+ int impl: @cil_method_implementation ref,
+ int index: int ref,
+ int var_type: @cil_type ref);
+
+cil_function_pointer_calling_conventions(
+ int id: @cil_function_pointer_type ref,
+ int kind: int ref);
+
+// CIL handlers (exception handlers etc).
+
+case @cil_handler.kind of
+ 0 = @cil_catch_handler
+| 1 = @cil_filter_handler
+| 2 = @cil_finally_handler
+| 4 = @cil_fault_handler
+;
+
+#keyset[impl, index]
+cil_handler(
+ unique int id: @cil_handler,
+ int impl: @cil_method_implementation ref,
+ int index: int ref,
+ int kind: int ref,
+ int try_start: @cil_instruction ref,
+ int try_end: @cil_instruction ref,
+ int handler_start: @cil_instruction ref);
+
+cil_handler_filter(
+ unique int id: @cil_handler ref,
+ int filter_start: @cil_instruction ref);
+
+cil_handler_type(
+ unique int id: @cil_handler ref,
+ int catch_type: @cil_type ref);
+
+@cil_controlflow_node = @cil_entry_point | @cil_instruction;
+
+@cil_entry_point = @cil_method_implementation | @cil_handler;
+
+@cil_dataflow_node = @cil_instruction | @cil_variable | @cil_method;
+
+cil_method_stack_size(
+ unique int method: @cil_method_implementation ref,
+ int size: int ref);
+
+// CIL modifiers
+
+cil_public(int id: @cil_member ref);
+cil_private(int id: @cil_member ref);
+cil_protected(int id: @cil_member ref);
+cil_internal(int id: @cil_member ref);
+cil_static(int id: @cil_member ref);
+cil_sealed(int id: @cil_member ref);
+cil_virtual(int id: @cil_method ref);
+cil_abstract(int id: @cil_member ref);
+cil_class(int id: @cil_type ref);
+cil_interface(int id: @cil_type ref);
+cil_security(int id: @cil_member ref);
+cil_requiresecobject(int id: @cil_method ref);
+cil_specialname(int id: @cil_method ref);
+cil_newslot(int id: @cil_method ref);
+
+cil_base_class(unique int id: @cil_type ref, int base: @cil_type ref);
+cil_base_interface(int id: @cil_type ref, int base: @cil_type ref);
+cil_enum_underlying_type(unique int id: @cil_type ref, int underlying: @cil_type ref);
+
+#keyset[unbound, index]
+cil_type_parameter(
+ int unbound: @cil_member ref,
+ int index: int ref,
+ int param: @cil_typeparameter ref);
+
+#keyset[bound, index]
+cil_type_argument(
+ int bound: @cil_member ref,
+ int index: int ref,
+ int t: @cil_type ref);
+
+// CIL type parameter constraints
+
+cil_typeparam_covariant(int tp: @cil_typeparameter ref);
+cil_typeparam_contravariant(int tp: @cil_typeparameter ref);
+cil_typeparam_class(int tp: @cil_typeparameter ref);
+cil_typeparam_struct(int tp: @cil_typeparameter ref);
+cil_typeparam_new(int tp: @cil_typeparameter ref);
+cil_typeparam_constraint(int tp: @cil_typeparameter ref, int supertype: @cil_type ref);
+
+// CIL attributes
+
+cil_attribute(
+ unique int attributeid: @cil_attribute,
+ int element: @cil_declaration ref,
+ int constructor: @cil_method ref);
+
+#keyset[attribute_id, param]
+cil_attribute_named_argument(
+ int attribute_id: @cil_attribute ref,
+ string param: string ref,
+ string value: string ref);
+
+#keyset[attribute_id, index]
+cil_attribute_positional_argument(
+ int attribute_id: @cil_attribute ref,
+ int index: int ref,
+ string value: string ref);
+
+
+// Common .Net data model covering both C# and CIL
+
+// Common elements
+@dotnet_element = @element | @cil_element;
+@dotnet_named_element = @named_element | @cil_named_element;
+@dotnet_callable = @callable | @cil_method;
+@dotnet_variable = @variable | @cil_variable;
+@dotnet_field = @field | @cil_field;
+@dotnet_parameter = @parameter | @cil_parameter;
+@dotnet_declaration = @declaration | @cil_declaration;
+@dotnet_member = @member | @cil_member;
+@dotnet_event = @event | @cil_event;
+@dotnet_property = @property | @cil_property | @indexer;
+@dotnet_parameterizable = @parameterizable | @cil_parameterizable;
+
+// Common types
+@dotnet_type = @type | @cil_type;
+@dotnet_call = @call | @cil_call_any;
+@dotnet_throw = @throw_element | @cil_throw_any;
+@dotnet_valueorreftype = @cil_valueorreftype | @value_or_ref_type | @cil_array_type | @void_type;
+@dotnet_typeparameter = @type_parameter | @cil_typeparameter;
+@dotnet_array_type = @array_type | @cil_array_type;
+@dotnet_pointer_type = @pointer_type | @cil_pointer_type;
+@dotnet_type_parameter = @type_parameter | @cil_typeparameter;
+@dotnet_generic = @dotnet_valueorreftype | @dotnet_callable;
+
+// Attributes
+@dotnet_attribute = @attribute | @cil_attribute;
+
+// Expressions
+@dotnet_expr = @expr | @cil_expr;
+
+// Literals
+@dotnet_literal = @literal_expr | @cil_literal;
+@dotnet_string_literal = @string_literal_expr | @cil_ldstr;
+@dotnet_int_literal = @integer_literal_expr | @cil_ldc_i;
+@dotnet_float_literal = @float_literal_expr | @cil_ldc_r;
+@dotnet_null_literal = @null_literal_expr | @cil_ldnull;
+
+@metadata_entity = @cil_method | @cil_type | @cil_field | @cil_property | @field | @property |
+ @callable | @value_or_ref_type | @void_type;
+
+#keyset[entity, location]
+metadata_handle(int entity : @metadata_entity ref, int location: @assembly ref, int handle: int ref)
diff --git a/csharp/ql/lib/upgrades/83aca6b3e4fa38dd2b97b9b51dfc199a2ba9c7f2/semmlecode.csharp.dbscheme b/csharp/ql/lib/upgrades/83aca6b3e4fa38dd2b97b9b51dfc199a2ba9c7f2/semmlecode.csharp.dbscheme
new file mode 100644
index 00000000000..d0fba103f7d
--- /dev/null
+++ b/csharp/ql/lib/upgrades/83aca6b3e4fa38dd2b97b9b51dfc199a2ba9c7f2/semmlecode.csharp.dbscheme
@@ -0,0 +1,2069 @@
+/* This is a dummy line to alter the dbscheme, so we can make a database upgrade
+ * without actually changing any of the dbscheme predicates. It contains a date
+ * to allow for such updates in the future as well.
+ *
+ * 2021-07-14
+ *
+ * DO NOT remove this comment carelessly, since it can revert the dbscheme back to a
+ * previously seen state (matching a previously seen SHA), which would make the upgrade
+ * mechanism not work properly.
+ */
+
+/**
+ * An invocation of the compiler. Note that more than one file may be
+ * compiled per invocation. For example, this command compiles three
+ * source files:
+ *
+ * csc f1.cs f2.cs f3.cs
+ *
+ * The `id` simply identifies the invocation, while `cwd` is the working
+ * directory from which the compiler was invoked.
+ */
+compilations(
+ unique int id : @compilation,
+ string cwd : string ref
+);
+
+/**
+ * The arguments that were passed to the extractor for a compiler
+ * invocation. If `id` is for the compiler invocation
+ *
+ * csc f1.cs f2.cs f3.cs
+ *
+ * then typically there will be rows for
+ *
+ * num | arg
+ * --- | ---
+ * 0 | --compiler
+ * 1 | *path to compiler*
+ * 2 | f1.cs
+ * 3 | f2.cs
+ * 4 | f3.cs
+ */
+#keyset[id, num]
+compilation_args(
+ int id : @compilation ref,
+ int num : int ref,
+ string arg : string ref
+);
+
+/**
+ * The source files that are compiled by a compiler invocation.
+ * If `id` is for the compiler invocation
+ *
+ * csc f1.cs f2.cs f3.cs
+ *
+ * then there will be rows for
+ *
+ * num | arg
+ * --- | ---
+ * 0 | f1.cs
+ * 1 | f2.cs
+ * 2 | f3.cs
+ */
+#keyset[id, num]
+compilation_compiling_files(
+ int id : @compilation ref,
+ int num : int ref,
+ int file : @file ref
+);
+
+/**
+ * The references used by a compiler invocation.
+ * If `id` is for the compiler invocation
+ *
+ * csc f1.cs f2.cs f3.cs /r:ref1.dll /r:ref2.dll /r:ref3.dll
+ *
+ * then there will be rows for
+ *
+ * num | arg
+ * --- | ---
+ * 0 | ref1.dll
+ * 1 | ref2.dll
+ * 2 | ref3.dll
+ */
+#keyset[id, num]
+compilation_referencing_files(
+ int id : @compilation ref,
+ int num : int ref,
+ int file : @file ref
+);
+
+/**
+ * The time taken by the extractor for a compiler invocation.
+ *
+ * For each file `num`, there will be rows for
+ *
+ * kind | seconds
+ * ---- | ---
+ * 1 | CPU seconds used by the extractor frontend
+ * 2 | Elapsed seconds during the extractor frontend
+ * 3 | CPU seconds used by the extractor backend
+ * 4 | Elapsed seconds during the extractor backend
+ */
+#keyset[id, num, kind]
+compilation_time(
+ int id : @compilation ref,
+ int num : int ref,
+ /* kind:
+ 1 = frontend_cpu_seconds
+ 2 = frontend_elapsed_seconds
+ 3 = extractor_cpu_seconds
+ 4 = extractor_elapsed_seconds
+ */
+ int kind : int ref,
+ float seconds : float ref
+);
+
+/**
+ * An error or warning generated by the extractor.
+ * The diagnostic message `diagnostic` was generated during compiler
+ * invocation `compilation`, and is the `file_number_diagnostic_number`th
+ * message generated while extracting the `file_number`th file of that
+ * invocation.
+ */
+#keyset[compilation, file_number, file_number_diagnostic_number]
+diagnostic_for(
+ unique int diagnostic : @diagnostic ref,
+ int compilation : @compilation ref,
+ int file_number : int ref,
+ int file_number_diagnostic_number : int ref
+);
+
+diagnostics(
+ unique int id: @diagnostic,
+ int severity: int ref,
+ string error_tag: string ref,
+ string error_message: string ref,
+ string full_error_message: string ref,
+ int location: @location_default ref
+);
+
+extractor_messages(
+ unique int id: @extractor_message,
+ int severity: int ref,
+ string origin : string ref,
+ string text : string ref,
+ string entity : string ref,
+ int location: @location_default ref,
+ string stack_trace : string ref
+);
+
+/**
+ * If extraction was successful, then `cpu_seconds` and
+ * `elapsed_seconds` are the CPU time and elapsed time (respectively)
+ * that extraction took for compiler invocation `id`.
+ */
+compilation_finished(
+ unique int id : @compilation ref,
+ float cpu_seconds : float ref,
+ float elapsed_seconds : float ref
+);
+
+compilation_assembly(
+ unique int id : @compilation ref,
+ int assembly: @assembly ref
+)
+
+// Populated by the CSV extractor
+externalData(
+ int id: @externalDataElement,
+ string path: string ref,
+ int column: int ref,
+ string value: string ref);
+
+sourceLocationPrefix(
+ string prefix: string ref);
+
+/*
+ * C# dbscheme
+ */
+
+/** ELEMENTS **/
+
+@element = @declaration | @stmt | @expr | @modifier | @attribute | @namespace_declaration
+ | @using_directive | @type_parameter_constraints | @externalDataElement
+ | @xmllocatable | @asp_element | @namespace | @preprocessor_directive;
+
+@declaration = @callable | @generic | @assignable | @namespace;
+
+@named_element = @namespace | @declaration;
+
+@declaration_with_accessors = @property | @indexer | @event;
+
+@assignable = @variable | @assignable_with_accessors | @event;
+
+@assignable_with_accessors = @property | @indexer;
+
+@attributable = @assembly | @field | @parameter | @operator | @method | @constructor
+ | @destructor | @callable_accessor | @value_or_ref_type | @declaration_with_accessors
+ | @local_function | @lambda_expr;
+
+/** LOCATIONS, ASEMMBLIES, MODULES, FILES and FOLDERS **/
+
+@location = @location_default | @assembly;
+
+locations_default(
+ unique int id: @location_default,
+ int file: @file ref,
+ int beginLine: int ref,
+ int beginColumn: int ref,
+ int endLine: int ref,
+ int endColumn: int ref);
+
+locations_mapped(
+ unique int id: @location_default ref,
+ int mapped_to: @location_default ref);
+
+@sourceline = @file | @callable | @xmllocatable;
+
+numlines(
+ int element_id: @sourceline ref,
+ int num_lines: int ref,
+ int num_code: int ref,
+ int num_comment: int ref);
+
+assemblies(
+ unique int id: @assembly,
+ int file: @file ref,
+ string fullname: string ref,
+ string name: string ref,
+ string version: string ref);
+
+files(
+ unique int id: @file,
+ string name: string ref);
+
+folders(
+ unique int id: @folder,
+ string name: string ref);
+
+@container = @folder | @file ;
+
+containerparent(
+ int parent: @container ref,
+ unique int child: @container ref);
+
+file_extraction_mode(
+ unique int file: @file ref,
+ int mode: int ref
+ /* 0 = normal, 1 = standalone extractor */
+ );
+
+/** NAMESPACES **/
+
+@type_container = @namespace | @type;
+
+namespaces(
+ unique int id: @namespace,
+ string name: string ref);
+
+namespace_declarations(
+ unique int id: @namespace_declaration,
+ int namespace_id: @namespace ref);
+
+namespace_declaration_location(
+ unique int id: @namespace_declaration ref,
+ int loc: @location ref);
+
+parent_namespace(
+ unique int child_id: @type_container ref,
+ int namespace_id: @namespace ref);
+
+@declaration_or_directive = @namespace_declaration | @type | @using_directive;
+
+parent_namespace_declaration(
+ int child_id: @declaration_or_directive ref, // cannot be unique because of partial classes
+ int namespace_id: @namespace_declaration ref);
+
+@using_directive = @using_namespace_directive | @using_static_directive;
+
+using_global(
+ unique int id: @using_directive ref
+);
+
+using_namespace_directives(
+ unique int id: @using_namespace_directive,
+ int namespace_id: @namespace ref);
+
+using_static_directives(
+ unique int id: @using_static_directive,
+ int type_id: @type_or_ref ref);
+
+using_directive_location(
+ unique int id: @using_directive ref,
+ int loc: @location ref);
+
+@preprocessor_directive = @pragma_warning | @pragma_checksum | @directive_define | @directive_undefine | @directive_warning
+ | @directive_error | @directive_nullable | @directive_line | @directive_region | @directive_endregion | @directive_if
+ | @directive_elif | @directive_else | @directive_endif;
+
+@conditional_directive = @directive_if | @directive_elif;
+@branch_directive = @directive_if | @directive_elif | @directive_else;
+
+directive_ifs(
+ unique int id: @directive_if,
+ int branchTaken: int ref, /* 0: false, 1: true */
+ int conditionValue: int ref); /* 0: false, 1: true */
+
+directive_elifs(
+ unique int id: @directive_elif,
+ int branchTaken: int ref, /* 0: false, 1: true */
+ int conditionValue: int ref, /* 0: false, 1: true */
+ int parent: @directive_if ref,
+ int index: int ref);
+
+directive_elses(
+ unique int id: @directive_else,
+ int branchTaken: int ref, /* 0: false, 1: true */
+ int parent: @directive_if ref,
+ int index: int ref);
+
+#keyset[id, start]
+directive_endifs(
+ unique int id: @directive_endif,
+ unique int start: @directive_if ref);
+
+directive_define_symbols(
+ unique int id: @define_symbol_expr ref,
+ string name: string ref);
+
+directive_regions(
+ unique int id: @directive_region,
+ string name: string ref);
+
+#keyset[id, start]
+directive_endregions(
+ unique int id: @directive_endregion,
+ unique int start: @directive_region ref);
+
+directive_lines(
+ unique int id: @directive_line,
+ int kind: int ref); /* 0: default, 1: hidden, 2: numeric, 3: span */
+
+directive_line_value(
+ unique int id: @directive_line ref,
+ int line: int ref);
+
+directive_line_file(
+ unique int id: @directive_line ref,
+ int file: @file ref);
+
+directive_line_offset(
+ unique int id: @directive_line ref,
+ int offset: int ref);
+
+directive_line_span(
+ unique int id: @directive_line ref,
+ int startLine: int ref,
+ int startColumn: int ref,
+ int endLine: int ref,
+ int endColumn: int ref);
+
+directive_nullables(
+ unique int id: @directive_nullable,
+ int setting: int ref, /* 0: disable, 1: enable, 2: restore */
+ int target: int ref); /* 0: none, 1: annotations, 2: warnings */
+
+directive_warnings(
+ unique int id: @directive_warning,
+ string message: string ref);
+
+directive_errors(
+ unique int id: @directive_error,
+ string message: string ref);
+
+directive_undefines(
+ unique int id: @directive_undefine,
+ string name: string ref);
+
+directive_defines(
+ unique int id: @directive_define,
+ string name: string ref);
+
+pragma_checksums(
+ unique int id: @pragma_checksum,
+ int file: @file ref,
+ string guid: string ref,
+ string bytes: string ref);
+
+pragma_warnings(
+ unique int id: @pragma_warning,
+ int kind: int ref /* 0 = disable, 1 = restore */);
+
+#keyset[id, index]
+pragma_warning_error_codes(
+ int id: @pragma_warning ref,
+ string errorCode: string ref,
+ int index: int ref);
+
+preprocessor_directive_location(
+ unique int id: @preprocessor_directive ref,
+ int loc: @location ref);
+
+preprocessor_directive_compilation(
+ unique int id: @preprocessor_directive ref,
+ int compilation: @compilation ref);
+
+preprocessor_directive_active(
+ unique int id: @preprocessor_directive ref,
+ int active: int ref); /* 0: false, 1: true */
+
+/** TYPES **/
+
+types(
+ unique int id: @type,
+ int kind: int ref,
+ string name: string ref);
+
+case @type.kind of
+ 1 = @bool_type
+| 2 = @char_type
+| 3 = @decimal_type
+| 4 = @sbyte_type
+| 5 = @short_type
+| 6 = @int_type
+| 7 = @long_type
+| 8 = @byte_type
+| 9 = @ushort_type
+| 10 = @uint_type
+| 11 = @ulong_type
+| 12 = @float_type
+| 13 = @double_type
+| 14 = @enum_type
+| 15 = @struct_type
+| 17 = @class_type
+| 19 = @interface_type
+| 20 = @delegate_type
+| 21 = @null_type
+| 22 = @type_parameter
+| 23 = @pointer_type
+| 24 = @nullable_type
+| 25 = @array_type
+| 26 = @void_type
+| 27 = @int_ptr_type
+| 28 = @uint_ptr_type
+| 29 = @dynamic_type
+| 30 = @arglist_type
+| 31 = @unknown_type
+| 32 = @tuple_type
+| 33 = @function_pointer_type
+ ;
+
+@simple_type = @bool_type | @char_type | @integral_type | @floating_point_type | @decimal_type;
+@integral_type = @signed_integral_type | @unsigned_integral_type;
+@signed_integral_type = @sbyte_type | @short_type | @int_type | @long_type;
+@unsigned_integral_type = @byte_type | @ushort_type | @uint_type | @ulong_type;
+@floating_point_type = @float_type | @double_type;
+@value_type = @simple_type | @enum_type | @struct_type | @nullable_type | @int_ptr_type
+ | @uint_ptr_type | @tuple_type;
+@ref_type = @class_type | @interface_type | @array_type | @delegate_type | @null_type
+ | @dynamic_type;
+@value_or_ref_type = @value_type | @ref_type;
+
+typerefs(
+ unique int id: @typeref,
+ string name: string ref);
+
+typeref_type(
+ int id: @typeref ref,
+ unique int typeId: @type ref);
+
+@type_or_ref = @type | @typeref;
+
+array_element_type(
+ unique int array: @array_type ref,
+ int dimension: int ref,
+ int rank: int ref,
+ int element: @type_or_ref ref);
+
+nullable_underlying_type(
+ unique int nullable: @nullable_type ref,
+ int underlying: @type_or_ref ref);
+
+pointer_referent_type(
+ unique int pointer: @pointer_type ref,
+ int referent: @type_or_ref ref);
+
+enum_underlying_type(
+ unique int enum_id: @enum_type ref,
+ int underlying_type_id: @type_or_ref ref);
+
+delegate_return_type(
+ unique int delegate_id: @delegate_type ref,
+ int return_type_id: @type_or_ref ref);
+
+function_pointer_return_type(
+ unique int function_pointer_id: @function_pointer_type ref,
+ int return_type_id: @type_or_ref ref);
+
+extend(
+ int sub: @type ref,
+ int super: @type_or_ref ref);
+
+anonymous_types(
+ unique int id: @type ref);
+
+@interface_or_ref = @interface_type | @typeref;
+
+implement(
+ int sub: @type ref,
+ int super: @type_or_ref ref);
+
+type_location(
+ int id: @type ref,
+ int loc: @location ref);
+
+tuple_underlying_type(
+ unique int tuple: @tuple_type ref,
+ int struct: @type_or_ref ref);
+
+#keyset[tuple, index]
+tuple_element(
+ int tuple: @tuple_type ref,
+ int index: int ref,
+ unique int field: @field ref);
+
+attributes(
+ unique int id: @attribute,
+ int kind: int ref,
+ int type_id: @type_or_ref ref,
+ int target: @attributable ref);
+
+case @attribute.kind of
+ 0 = @attribute_default
+| 1 = @attribute_return
+| 2 = @attribute_assembly
+| 3 = @attribute_module
+;
+
+attribute_location(
+ int id: @attribute ref,
+ int loc: @location ref);
+
+@type_mention_parent = @element | @type_mention;
+
+type_mention(
+ unique int id: @type_mention,
+ int type_id: @type_or_ref ref,
+ int parent: @type_mention_parent ref);
+
+type_mention_location(
+ unique int id: @type_mention ref,
+ int loc: @location ref);
+
+@has_type_annotation = @assignable | @type_parameter | @callable | @expr | @delegate_type | @generic | @function_pointer_type;
+
+/**
+ * A direct annotation on an entity, for example `string? x;`.
+ *
+ * Annotations:
+ * 2 = reftype is not annotated "!"
+ * 3 = reftype is annotated "?"
+ * 4 = readonly ref type / in parameter
+ * 5 = ref type parameter, return or local variable
+ * 6 = out parameter
+ *
+ * Note that the annotation depends on the element it annotates.
+ * @assignable: The annotation is on the type of the assignable, for example the variable type.
+ * @type_parameter: The annotation is on the reftype constraint
+ * @callable: The annotation is on the return type
+ * @array_type: The annotation is on the element type
+ */
+type_annotation(int id: @has_type_annotation ref, int annotation: int ref);
+
+nullability(unique int nullability: @nullability, int kind: int ref);
+
+case @nullability.kind of
+ 0 = @oblivious
+| 1 = @not_annotated
+| 2 = @annotated
+;
+
+#keyset[parent, index]
+nullability_parent(int nullability: @nullability ref, int index: int ref, int parent: @nullability ref)
+
+type_nullability(int id: @has_type_annotation ref, int nullability: @nullability ref);
+
+/**
+ * The nullable flow state of an expression, as determined by Roslyn.
+ * 0 = none (default, not populated)
+ * 1 = not null
+ * 2 = maybe null
+ */
+expr_flowstate(unique int id: @expr ref, int state: int ref);
+
+/** GENERICS **/
+
+@generic = @type | @method | @local_function;
+
+type_parameters(
+ unique int id: @type_parameter ref,
+ int index: int ref,
+ int generic_id: @generic ref,
+ int variance: int ref /* none = 0, out = 1, in = 2 */);
+
+#keyset[constructed_id, index]
+type_arguments(
+ int id: @type_or_ref ref,
+ int index: int ref,
+ int constructed_id: @generic_or_ref ref);
+
+@generic_or_ref = @generic | @typeref;
+
+constructed_generic(
+ unique int constructed: @generic ref,
+ int generic: @generic_or_ref ref);
+
+type_parameter_constraints(
+ unique int id: @type_parameter_constraints,
+ int param_id: @type_parameter ref);
+
+type_parameter_constraints_location(
+ int id: @type_parameter_constraints ref,
+ int loc: @location ref);
+
+general_type_parameter_constraints(
+ int id: @type_parameter_constraints ref,
+ int kind: int ref /* class = 1, struct = 2, new = 3 */);
+
+specific_type_parameter_constraints(
+ int id: @type_parameter_constraints ref,
+ int base_id: @type_or_ref ref);
+
+specific_type_parameter_nullability(
+ int id: @type_parameter_constraints ref,
+ int base_id: @type_or_ref ref,
+ int nullability: @nullability ref);
+
+/** FUNCTION POINTERS */
+
+function_pointer_calling_conventions(
+ int id: @function_pointer_type ref,
+ int kind: int ref);
+
+#keyset[id, index]
+has_unmanaged_calling_conventions(
+ int id: @function_pointer_type ref,
+ int index: int ref,
+ int conv_id: @type_or_ref ref);
+
+/** MODIFIERS */
+
+@modifiable = @modifiable_direct | @event_accessor;
+
+@modifiable_direct = @member | @accessor | @local_function | @anonymous_function_expr;
+
+modifiers(
+ unique int id: @modifier,
+ string name: string ref);
+
+has_modifiers(
+ int id: @modifiable_direct ref,
+ int mod_id: @modifier ref);
+
+compiler_generated(unique int id: @modifiable ref);
+
+/** MEMBERS **/
+
+@member = @method | @constructor | @destructor | @field | @property | @event | @operator | @indexer | @type;
+
+@named_exprorstmt = @goto_stmt | @labeled_stmt | @expr;
+
+@virtualizable = @method | @property | @indexer | @event;
+
+exprorstmt_name(
+ unique int parent_id: @named_exprorstmt ref,
+ string name: string ref);
+
+nested_types(
+ unique int id: @type ref,
+ int declaring_type_id: @type ref,
+ int unbound_id: @type ref);
+
+properties(
+ unique int id: @property,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @property ref);
+
+property_location(
+ int id: @property ref,
+ int loc: @location ref);
+
+indexers(
+ unique int id: @indexer,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @indexer ref);
+
+indexer_location(
+ int id: @indexer ref,
+ int loc: @location ref);
+
+accessors(
+ unique int id: @accessor,
+ int kind: int ref,
+ string name: string ref,
+ int declaring_member_id: @member ref,
+ int unbound_id: @accessor ref);
+
+case @accessor.kind of
+ 1 = @getter
+| 2 = @setter
+ ;
+
+init_only_accessors(
+ unique int id: @accessor ref);
+
+accessor_location(
+ int id: @accessor ref,
+ int loc: @location ref);
+
+events(
+ unique int id: @event,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @event ref);
+
+event_location(
+ int id: @event ref,
+ int loc: @location ref);
+
+event_accessors(
+ unique int id: @event_accessor,
+ int kind: int ref,
+ string name: string ref,
+ int declaring_event_id: @event ref,
+ int unbound_id: @event_accessor ref);
+
+case @event_accessor.kind of
+ 1 = @add_event_accessor
+| 2 = @remove_event_accessor
+ ;
+
+event_accessor_location(
+ int id: @event_accessor ref,
+ int loc: @location ref);
+
+operators(
+ unique int id: @operator,
+ string name: string ref,
+ string symbol: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @operator ref);
+
+operator_location(
+ int id: @operator ref,
+ int loc: @location ref);
+
+constant_value(
+ int id: @variable ref,
+ string value: string ref);
+
+/** CALLABLES **/
+
+@callable = @method | @constructor | @destructor | @operator | @callable_accessor | @anonymous_function_expr | @local_function;
+
+@callable_accessor = @accessor | @event_accessor;
+
+methods(
+ unique int id: @method,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @method ref);
+
+method_location(
+ int id: @method ref,
+ int loc: @location ref);
+
+constructors(
+ unique int id: @constructor,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int unbound_id: @constructor ref);
+
+constructor_location(
+ int id: @constructor ref,
+ int loc: @location ref);
+
+destructors(
+ unique int id: @destructor,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int unbound_id: @destructor ref);
+
+destructor_location(
+ int id: @destructor ref,
+ int loc: @location ref);
+
+overrides(
+ int id: @callable ref,
+ int base_id: @callable ref);
+
+explicitly_implements(
+ int id: @member ref,
+ int interface_id: @interface_or_ref ref);
+
+local_functions(
+ unique int id: @local_function,
+ string name: string ref,
+ int return_type: @type ref,
+ int unbound_id: @local_function ref);
+
+local_function_stmts(
+ unique int fn: @local_function_stmt ref,
+ int stmt: @local_function ref);
+
+/** VARIABLES **/
+
+@variable = @local_scope_variable | @field;
+
+@local_scope_variable = @local_variable | @parameter;
+
+fields(
+ unique int id: @field,
+ int kind: int ref,
+ string name: string ref,
+ int declaring_type_id: @type ref,
+ int type_id: @type_or_ref ref,
+ int unbound_id: @field ref);
+
+case @field.kind of
+ 1 = @addressable_field
+| 2 = @constant
+ ;
+
+field_location(
+ int id: @field ref,
+ int loc: @location ref);
+
+localvars(
+ unique int id: @local_variable,
+ int kind: int ref,
+ string name: string ref,
+ int implicitly_typed: int ref /* 0 = no, 1 = yes */,
+ int type_id: @type_or_ref ref,
+ int parent_id: @local_var_decl_expr ref);
+
+case @local_variable.kind of
+ 1 = @addressable_local_variable
+| 2 = @local_constant
+| 3 = @local_variable_ref
+ ;
+
+localvar_location(
+ unique int id: @local_variable ref,
+ int loc: @location ref);
+
+@parameterizable = @callable | @delegate_type | @indexer | @function_pointer_type;
+
+#keyset[name, parent_id]
+#keyset[index, parent_id]
+params(
+ unique int id: @parameter,
+ string name: string ref,
+ int type_id: @type_or_ref ref,
+ int index: int ref,
+ int mode: int ref, /* value = 0, ref = 1, out = 2, array = 3, this = 4 */
+ int parent_id: @parameterizable ref,
+ int unbound_id: @parameter ref);
+
+param_location(
+ int id: @parameter ref,
+ int loc: @location ref);
+
+/** STATEMENTS **/
+
+@exprorstmt_parent = @control_flow_element | @top_level_exprorstmt_parent;
+
+statements(
+ unique int id: @stmt,
+ int kind: int ref);
+
+#keyset[index, parent]
+stmt_parent(
+ unique int stmt: @stmt ref,
+ int index: int ref,
+ int parent: @control_flow_element ref);
+
+@top_level_stmt_parent = @callable;
+
+// [index, parent] is not a keyset because the same parent may be compiled multiple times
+stmt_parent_top_level(
+ unique int stmt: @stmt ref,
+ int index: int ref,
+ int parent: @top_level_stmt_parent ref);
+
+case @stmt.kind of
+ 1 = @block_stmt
+| 2 = @expr_stmt
+| 3 = @if_stmt
+| 4 = @switch_stmt
+| 5 = @while_stmt
+| 6 = @do_stmt
+| 7 = @for_stmt
+| 8 = @foreach_stmt
+| 9 = @break_stmt
+| 10 = @continue_stmt
+| 11 = @goto_stmt
+| 12 = @goto_case_stmt
+| 13 = @goto_default_stmt
+| 14 = @throw_stmt
+| 15 = @return_stmt
+| 16 = @yield_stmt
+| 17 = @try_stmt
+| 18 = @checked_stmt
+| 19 = @unchecked_stmt
+| 20 = @lock_stmt
+| 21 = @using_block_stmt
+| 22 = @var_decl_stmt
+| 23 = @const_decl_stmt
+| 24 = @empty_stmt
+| 25 = @unsafe_stmt
+| 26 = @fixed_stmt
+| 27 = @label_stmt
+| 28 = @catch
+| 29 = @case_stmt
+| 30 = @local_function_stmt
+| 31 = @using_decl_stmt
+ ;
+
+@using_stmt = @using_block_stmt | @using_decl_stmt;
+
+@labeled_stmt = @label_stmt | @case;
+
+@decl_stmt = @var_decl_stmt | @const_decl_stmt | @using_decl_stmt;
+
+@cond_stmt = @if_stmt | @switch_stmt;
+
+@loop_stmt = @while_stmt | @do_stmt | @for_stmt | @foreach_stmt;
+
+@jump_stmt = @break_stmt | @goto_any_stmt | @continue_stmt | @throw_stmt | @return_stmt
+ | @yield_stmt;
+
+@goto_any_stmt = @goto_default_stmt | @goto_case_stmt | @goto_stmt;
+
+
+stmt_location(
+ unique int id: @stmt ref,
+ int loc: @location ref);
+
+catch_type(
+ unique int catch_id: @catch ref,
+ int type_id: @type_or_ref ref,
+ int kind: int ref /* explicit = 1, implicit = 2 */);
+
+foreach_stmt_info(
+ unique int id: @foreach_stmt ref,
+ int kind: int ref /* non-async = 1, async = 2 */);
+
+@foreach_symbol = @method | @property | @type_or_ref;
+
+#keyset[id, kind]
+foreach_stmt_desugar(
+ int id: @foreach_stmt ref,
+ int symbol: @foreach_symbol ref,
+ int kind: int ref /* GetEnumeratorMethod = 1, CurrentProperty = 2, MoveNextMethod = 3, DisposeMethod = 4, ElementType = 5 */);
+
+/** EXPRESSIONS **/
+
+expressions(
+ unique int id: @expr,
+ int kind: int ref,
+ int type_id: @type_or_ref ref);
+
+#keyset[index, parent]
+expr_parent(
+ unique int expr: @expr ref,
+ int index: int ref,
+ int parent: @control_flow_element ref);
+
+@top_level_expr_parent = @attribute | @field | @property | @indexer | @parameter | @directive_if | @directive_elif;
+
+@top_level_exprorstmt_parent = @top_level_expr_parent | @top_level_stmt_parent;
+
+// [index, parent] is not a keyset because the same parent may be compiled multiple times
+expr_parent_top_level(
+ unique int expr: @expr ref,
+ int index: int ref,
+ int parent: @top_level_exprorstmt_parent ref);
+
+case @expr.kind of
+/* literal */
+ 1 = @bool_literal_expr
+| 2 = @char_literal_expr
+| 3 = @decimal_literal_expr
+| 4 = @int_literal_expr
+| 5 = @long_literal_expr
+| 6 = @uint_literal_expr
+| 7 = @ulong_literal_expr
+| 8 = @float_literal_expr
+| 9 = @double_literal_expr
+| 10 = @string_literal_expr
+| 11 = @null_literal_expr
+/* primary & unary */
+| 12 = @this_access_expr
+| 13 = @base_access_expr
+| 14 = @local_variable_access_expr
+| 15 = @parameter_access_expr
+| 16 = @field_access_expr
+| 17 = @property_access_expr
+| 18 = @method_access_expr
+| 19 = @event_access_expr
+| 20 = @indexer_access_expr
+| 21 = @array_access_expr
+| 22 = @type_access_expr
+| 23 = @typeof_expr
+| 24 = @method_invocation_expr
+| 25 = @delegate_invocation_expr
+| 26 = @operator_invocation_expr
+| 27 = @cast_expr
+| 28 = @object_creation_expr
+| 29 = @explicit_delegate_creation_expr
+| 30 = @implicit_delegate_creation_expr
+| 31 = @array_creation_expr
+| 32 = @default_expr
+| 33 = @plus_expr
+| 34 = @minus_expr
+| 35 = @bit_not_expr
+| 36 = @log_not_expr
+| 37 = @post_incr_expr
+| 38 = @post_decr_expr
+| 39 = @pre_incr_expr
+| 40 = @pre_decr_expr
+/* multiplicative */
+| 41 = @mul_expr
+| 42 = @div_expr
+| 43 = @rem_expr
+/* additive */
+| 44 = @add_expr
+| 45 = @sub_expr
+/* shift */
+| 46 = @lshift_expr
+| 47 = @rshift_expr
+/* relational */
+| 48 = @lt_expr
+| 49 = @gt_expr
+| 50 = @le_expr
+| 51 = @ge_expr
+/* equality */
+| 52 = @eq_expr
+| 53 = @ne_expr
+/* logical */
+| 54 = @bit_and_expr
+| 55 = @bit_xor_expr
+| 56 = @bit_or_expr
+| 57 = @log_and_expr
+| 58 = @log_or_expr
+/* type testing */
+| 59 = @is_expr
+| 60 = @as_expr
+/* null coalescing */
+| 61 = @null_coalescing_expr
+/* conditional */
+| 62 = @conditional_expr
+/* assignment */
+| 63 = @simple_assign_expr
+| 64 = @assign_add_expr
+| 65 = @assign_sub_expr
+| 66 = @assign_mul_expr
+| 67 = @assign_div_expr
+| 68 = @assign_rem_expr
+| 69 = @assign_and_expr
+| 70 = @assign_xor_expr
+| 71 = @assign_or_expr
+| 72 = @assign_lshift_expr
+| 73 = @assign_rshift_expr
+/* more */
+| 74 = @object_init_expr
+| 75 = @collection_init_expr
+| 76 = @array_init_expr
+| 77 = @checked_expr
+| 78 = @unchecked_expr
+| 79 = @constructor_init_expr
+| 80 = @add_event_expr
+| 81 = @remove_event_expr
+| 82 = @par_expr
+| 83 = @local_var_decl_expr
+| 84 = @lambda_expr
+| 85 = @anonymous_method_expr
+| 86 = @namespace_expr
+/* dynamic */
+| 92 = @dynamic_element_access_expr
+| 93 = @dynamic_member_access_expr
+/* unsafe */
+| 100 = @pointer_indirection_expr
+| 101 = @address_of_expr
+| 102 = @sizeof_expr
+/* async */
+| 103 = @await_expr
+/* C# 6.0 */
+| 104 = @nameof_expr
+| 105 = @interpolated_string_expr
+| 106 = @unknown_expr
+/* C# 7.0 */
+| 107 = @throw_expr
+| 108 = @tuple_expr
+| 109 = @local_function_invocation_expr
+| 110 = @ref_expr
+| 111 = @discard_expr
+/* C# 8.0 */
+| 112 = @range_expr
+| 113 = @index_expr
+| 114 = @switch_expr
+| 115 = @recursive_pattern_expr
+| 116 = @property_pattern_expr
+| 117 = @positional_pattern_expr
+| 118 = @switch_case_expr
+| 119 = @assign_coalesce_expr
+| 120 = @suppress_nullable_warning_expr
+| 121 = @namespace_access_expr
+/* C# 9.0 */
+| 122 = @lt_pattern_expr
+| 123 = @gt_pattern_expr
+| 124 = @le_pattern_expr
+| 125 = @ge_pattern_expr
+| 126 = @not_pattern_expr
+| 127 = @and_pattern_expr
+| 128 = @or_pattern_expr
+| 129 = @function_pointer_invocation_expr
+| 130 = @with_expr
+/* C# 11.0 */
+| 131 = @list_pattern_expr
+| 132 = @slice_pattern_expr
+| 133 = @urshift_expr
+| 134 = @assign_urshift_expr
+/* Preprocessor */
+| 999 = @define_symbol_expr
+;
+
+@switch = @switch_stmt | @switch_expr;
+@case = @case_stmt | @switch_case_expr;
+@pattern_match = @case | @is_expr;
+@unary_pattern_expr = @not_pattern_expr;
+@relational_pattern_expr = @gt_pattern_expr | @lt_pattern_expr | @ge_pattern_expr | @le_pattern_expr;
+@binary_pattern_expr = @and_pattern_expr | @or_pattern_expr;
+
+@integer_literal_expr = @int_literal_expr | @long_literal_expr | @uint_literal_expr | @ulong_literal_expr;
+@real_literal_expr = @float_literal_expr | @double_literal_expr | @decimal_literal_expr;
+@literal_expr = @bool_literal_expr | @char_literal_expr | @integer_literal_expr | @real_literal_expr
+ | @string_literal_expr | @null_literal_expr;
+
+@assign_expr = @simple_assign_expr | @assign_op_expr | @local_var_decl_expr;
+@assign_op_expr = @assign_arith_expr | @assign_bitwise_expr | @assign_event_expr | @assign_coalesce_expr;
+@assign_event_expr = @add_event_expr | @remove_event_expr;
+
+@assign_arith_expr = @assign_add_expr | @assign_sub_expr | @assign_mul_expr | @assign_div_expr
+ | @assign_rem_expr
+@assign_bitwise_expr = @assign_and_expr | @assign_or_expr | @assign_xor_expr
+ | @assign_lshift_expr | @assign_rshift_expr | @assign_urshift_expr;
+
+@member_access_expr = @field_access_expr | @property_access_expr | @indexer_access_expr | @event_access_expr
+ | @method_access_expr | @type_access_expr | @dynamic_member_access_expr;
+@access_expr = @member_access_expr | @this_access_expr | @base_access_expr | @assignable_access_expr | @namespace_access_expr;
+@element_access_expr = @indexer_access_expr | @array_access_expr | @dynamic_element_access_expr;
+
+@local_variable_access = @local_variable_access_expr | @local_var_decl_expr;
+@local_scope_variable_access_expr = @parameter_access_expr | @local_variable_access;
+@variable_access_expr = @local_scope_variable_access_expr | @field_access_expr;
+
+@assignable_access_expr = @variable_access_expr | @property_access_expr | @element_access_expr
+ | @event_access_expr | @dynamic_member_access_expr;
+
+@objectorcollection_init_expr = @object_init_expr | @collection_init_expr;
+
+@delegate_creation_expr = @explicit_delegate_creation_expr | @implicit_delegate_creation_expr;
+
+@bin_arith_op_expr = @mul_expr | @div_expr | @rem_expr | @add_expr | @sub_expr;
+@incr_op_expr = @pre_incr_expr | @post_incr_expr;
+@decr_op_expr = @pre_decr_expr | @post_decr_expr;
+@mut_op_expr = @incr_op_expr | @decr_op_expr;
+@un_arith_op_expr = @plus_expr | @minus_expr | @mut_op_expr;
+@arith_op_expr = @bin_arith_op_expr | @un_arith_op_expr;
+
+@ternary_log_op_expr = @conditional_expr;
+@bin_log_op_expr = @log_and_expr | @log_or_expr | @null_coalescing_expr;
+@un_log_op_expr = @log_not_expr;
+@log_expr = @un_log_op_expr | @bin_log_op_expr | @ternary_log_op_expr;
+
+@bin_bit_op_expr = @bit_and_expr | @bit_or_expr | @bit_xor_expr | @lshift_expr
+ | @rshift_expr | @urshift_expr;
+@un_bit_op_expr = @bit_not_expr;
+@bit_expr = @un_bit_op_expr | @bin_bit_op_expr;
+
+@equality_op_expr = @eq_expr | @ne_expr;
+@rel_op_expr = @gt_expr | @lt_expr| @ge_expr | @le_expr;
+@comp_expr = @equality_op_expr | @rel_op_expr;
+
+@op_expr = @assign_expr | @un_op | @bin_op | @ternary_op;
+
+@ternary_op = @ternary_log_op_expr;
+@bin_op = @bin_arith_op_expr | @bin_log_op_expr | @bin_bit_op_expr | @comp_expr;
+@un_op = @un_arith_op_expr | @un_log_op_expr | @un_bit_op_expr | @sizeof_expr
+ | @pointer_indirection_expr | @address_of_expr;
+
+@anonymous_function_expr = @lambda_expr | @anonymous_method_expr;
+
+@call = @method_invocation_expr | @constructor_init_expr | @operator_invocation_expr
+ | @delegate_invocation_expr | @object_creation_expr | @call_access_expr
+ | @local_function_invocation_expr | @function_pointer_invocation_expr;
+
+@call_access_expr = @property_access_expr | @event_access_expr | @indexer_access_expr;
+
+@late_bindable_expr = @dynamic_element_access_expr | @dynamic_member_access_expr
+ | @object_creation_expr | @method_invocation_expr | @operator_invocation_expr;
+
+@throw_element = @throw_expr | @throw_stmt;
+
+@implicitly_typeable_object_creation_expr = @object_creation_expr | @explicit_delegate_creation_expr;
+
+implicitly_typed_array_creation(
+ unique int id: @array_creation_expr ref);
+
+explicitly_sized_array_creation(
+ unique int id: @array_creation_expr ref);
+
+stackalloc_array_creation(
+ unique int id: @array_creation_expr ref);
+
+implicitly_typed_object_creation(
+ unique int id: @implicitly_typeable_object_creation_expr ref);
+
+mutator_invocation_mode(
+ unique int id: @operator_invocation_expr ref,
+ int mode: int ref /* prefix = 1, postfix = 2*/);
+
+expr_compiler_generated(
+ unique int id: @expr ref);
+
+expr_value(
+ unique int id: @expr ref,
+ string value: string ref);
+
+expr_call(
+ unique int caller_id: @expr ref,
+ int target_id: @callable ref);
+
+expr_access(
+ unique int accesser_id: @access_expr ref,
+ int target_id: @accessible ref);
+
+@accessible = @method | @assignable | @local_function | @namespace;
+
+expr_location(
+ unique int id: @expr ref,
+ int loc: @location ref);
+
+dynamic_member_name(
+ unique int id: @late_bindable_expr ref,
+ string name: string ref);
+
+@qualifiable_expr = @member_access_expr
+ | @method_invocation_expr
+ | @element_access_expr;
+
+conditional_access(
+ unique int id: @qualifiable_expr ref);
+
+expr_argument(
+ unique int id: @expr ref,
+ int mode: int ref);
+ /* mode is the same as params: value = 0, ref = 1, out = 2 */
+
+expr_argument_name(
+ unique int id: @expr ref,
+ string name: string ref);
+
+lambda_expr_return_type(
+ unique int id: @lambda_expr ref,
+ int type_id: @type_or_ref ref);
+
+/** CONTROL/DATA FLOW **/
+
+@control_flow_element = @stmt | @expr;
+
+/* XML Files */
+
+xmlEncoding (
+ unique int id: @file ref,
+ string encoding: string ref);
+
+xmlDTDs(
+ unique int id: @xmldtd,
+ string root: string ref,
+ string publicId: string ref,
+ string systemId: string ref,
+ int fileid: @file ref);
+
+xmlElements(
+ unique int id: @xmlelement,
+ string name: string ref,
+ int parentid: @xmlparent ref,
+ int idx: int ref,
+ int fileid: @file ref);
+
+xmlAttrs(
+ unique int id: @xmlattribute,
+ int elementid: @xmlelement ref,
+ string name: string ref,
+ string value: string ref,
+ int idx: int ref,
+ int fileid: @file ref);
+
+xmlNs(
+ int id: @xmlnamespace,
+ string prefixName: string ref,
+ string URI: string ref,
+ int fileid: @file ref);
+
+xmlHasNs(
+ int elementId: @xmlnamespaceable ref,
+ int nsId: @xmlnamespace ref,
+ int fileid: @file ref);
+
+xmlComments(
+ unique int id: @xmlcomment,
+ string text: string ref,
+ int parentid: @xmlparent ref,
+ int fileid: @file ref);
+
+xmlChars(
+ unique int id: @xmlcharacters,
+ string text: string ref,
+ int parentid: @xmlparent ref,
+ int idx: int ref,
+ int isCDATA: int ref,
+ int fileid: @file ref);
+
+@xmlparent = @file | @xmlelement;
+@xmlnamespaceable = @xmlelement | @xmlattribute;
+
+xmllocations(
+ int xmlElement: @xmllocatable ref,
+ int location: @location_default ref);
+
+@xmllocatable = @xmlcharacters | @xmlelement | @xmlcomment | @xmlattribute | @xmldtd | @file | @xmlnamespace;
+
+/* Comments */
+
+commentline(
+ unique int id: @commentline,
+ int kind: int ref,
+ string text: string ref,
+ string rawtext: string ref);
+
+case @commentline.kind of
+ 0 = @singlelinecomment
+| 1 = @xmldoccomment
+| 2 = @multilinecomment;
+
+commentline_location(
+ unique int id: @commentline ref,
+ int loc: @location ref);
+
+commentblock(
+ unique int id : @commentblock);
+
+commentblock_location(
+ unique int id: @commentblock ref,
+ int loc: @location ref);
+
+commentblock_binding(
+ int id: @commentblock ref,
+ int entity: @element ref,
+ int bindtype: int ref); /* 0: Parent, 1: Best, 2: Before, 3: After */
+
+commentblock_child(
+ int id: @commentblock ref,
+ int commentline: @commentline ref,
+ int index: int ref);
+
+/* ASP.NET */
+
+case @asp_element.kind of
+ 0=@asp_close_tag
+| 1=@asp_code
+| 2=@asp_comment
+| 3=@asp_data_binding
+| 4=@asp_directive
+| 5=@asp_open_tag
+| 6=@asp_quoted_string
+| 7=@asp_text
+| 8=@asp_xml_directive;
+
+@asp_attribute = @asp_code | @asp_data_binding | @asp_quoted_string;
+
+asp_elements(
+ unique int id: @asp_element,
+ int kind: int ref,
+ int loc: @location ref);
+
+asp_comment_server(unique int comment: @asp_comment ref);
+asp_code_inline(unique int code: @asp_code ref);
+asp_directive_attribute(
+ int directive: @asp_directive ref,
+ int index: int ref,
+ string name: string ref,
+ int value: @asp_quoted_string ref);
+asp_directive_name(
+ unique int directive: @asp_directive ref,
+ string name: string ref);
+asp_element_body(
+ unique int element: @asp_element ref,
+ string body: string ref);
+asp_tag_attribute(
+ int tag: @asp_open_tag ref,
+ int index: int ref,
+ string name: string ref,
+ int attribute: @asp_attribute ref);
+asp_tag_name(
+ unique int tag: @asp_open_tag ref,
+ string name: string ref);
+asp_tag_isempty(int tag: @asp_open_tag ref);
+
+/* Common Intermediate Language - CIL */
+
+case @cil_instruction.opcode of
+ 0 = @cil_nop
+| 1 = @cil_break
+| 2 = @cil_ldarg_0
+| 3 = @cil_ldarg_1
+| 4 = @cil_ldarg_2
+| 5 = @cil_ldarg_3
+| 6 = @cil_ldloc_0
+| 7 = @cil_ldloc_1
+| 8 = @cil_ldloc_2
+| 9 = @cil_ldloc_3
+| 10 = @cil_stloc_0
+| 11 = @cil_stloc_1
+| 12 = @cil_stloc_2
+| 13 = @cil_stloc_3
+| 14 = @cil_ldarg_s
+| 15 = @cil_ldarga_s
+| 16 = @cil_starg_s
+| 17 = @cil_ldloc_s
+| 18 = @cil_ldloca_s
+| 19 = @cil_stloc_s
+| 20 = @cil_ldnull
+| 21 = @cil_ldc_i4_m1
+| 22 = @cil_ldc_i4_0
+| 23 = @cil_ldc_i4_1
+| 24 = @cil_ldc_i4_2
+| 25 = @cil_ldc_i4_3
+| 26 = @cil_ldc_i4_4
+| 27 = @cil_ldc_i4_5
+| 28 = @cil_ldc_i4_6
+| 29 = @cil_ldc_i4_7
+| 30 = @cil_ldc_i4_8
+| 31 = @cil_ldc_i4_s
+| 32 = @cil_ldc_i4
+| 33 = @cil_ldc_i8
+| 34 = @cil_ldc_r4
+| 35 = @cil_ldc_r8
+| 37 = @cil_dup
+| 38 = @cil_pop
+| 39 = @cil_jmp
+| 40 = @cil_call
+| 41 = @cil_calli
+| 42 = @cil_ret
+| 43 = @cil_br_s
+| 44 = @cil_brfalse_s
+| 45 = @cil_brtrue_s
+| 46 = @cil_beq_s
+| 47 = @cil_bge_s
+| 48 = @cil_bgt_s
+| 49 = @cil_ble_s
+| 50 = @cil_blt_s
+| 51 = @cil_bne_un_s
+| 52 = @cil_bge_un_s
+| 53 = @cil_bgt_un_s
+| 54 = @cil_ble_un_s
+| 55 = @cil_blt_un_s
+| 56 = @cil_br
+| 57 = @cil_brfalse
+| 58 = @cil_brtrue
+| 59 = @cil_beq
+| 60 = @cil_bge
+| 61 = @cil_bgt
+| 62 = @cil_ble
+| 63 = @cil_blt
+| 64 = @cil_bne_un
+| 65 = @cil_bge_un
+| 66 = @cil_bgt_un
+| 67 = @cil_ble_un
+| 68 = @cil_blt_un
+| 69 = @cil_switch
+| 70 = @cil_ldind_i1
+| 71 = @cil_ldind_u1
+| 72 = @cil_ldind_i2
+| 73 = @cil_ldind_u2
+| 74 = @cil_ldind_i4
+| 75 = @cil_ldind_u4
+| 76 = @cil_ldind_i8
+| 77 = @cil_ldind_i
+| 78 = @cil_ldind_r4
+| 79 = @cil_ldind_r8
+| 80 = @cil_ldind_ref
+| 81 = @cil_stind_ref
+| 82 = @cil_stind_i1
+| 83 = @cil_stind_i2
+| 84 = @cil_stind_i4
+| 85 = @cil_stind_i8
+| 86 = @cil_stind_r4
+| 87 = @cil_stind_r8
+| 88 = @cil_add
+| 89 = @cil_sub
+| 90 = @cil_mul
+| 91 = @cil_div
+| 92 = @cil_div_un
+| 93 = @cil_rem
+| 94 = @cil_rem_un
+| 95 = @cil_and
+| 96 = @cil_or
+| 97 = @cil_xor
+| 98 = @cil_shl
+| 99 = @cil_shr
+| 100 = @cil_shr_un
+| 101 = @cil_neg
+| 102 = @cil_not
+| 103 = @cil_conv_i1
+| 104 = @cil_conv_i2
+| 105 = @cil_conv_i4
+| 106 = @cil_conv_i8
+| 107 = @cil_conv_r4
+| 108 = @cil_conv_r8
+| 109 = @cil_conv_u4
+| 110 = @cil_conv_u8
+| 111 = @cil_callvirt
+| 112 = @cil_cpobj
+| 113 = @cil_ldobj
+| 114 = @cil_ldstr
+| 115 = @cil_newobj
+| 116 = @cil_castclass
+| 117 = @cil_isinst
+| 118 = @cil_conv_r_un
+| 121 = @cil_unbox
+| 122 = @cil_throw
+| 123 = @cil_ldfld
+| 124 = @cil_ldflda
+| 125 = @cil_stfld
+| 126 = @cil_ldsfld
+| 127 = @cil_ldsflda
+| 128 = @cil_stsfld
+| 129 = @cil_stobj
+| 130 = @cil_conv_ovf_i1_un
+| 131 = @cil_conv_ovf_i2_un
+| 132 = @cil_conv_ovf_i4_un
+| 133 = @cil_conv_ovf_i8_un
+| 134 = @cil_conv_ovf_u1_un
+| 135 = @cil_conv_ovf_u2_un
+| 136 = @cil_conv_ovf_u4_un
+| 137 = @cil_conv_ovf_u8_un
+| 138 = @cil_conv_ovf_i_un
+| 139 = @cil_conv_ovf_u_un
+| 140 = @cil_box
+| 141 = @cil_newarr
+| 142 = @cil_ldlen
+| 143 = @cil_ldelema
+| 144 = @cil_ldelem_i1
+| 145 = @cil_ldelem_u1
+| 146 = @cil_ldelem_i2
+| 147 = @cil_ldelem_u2
+| 148 = @cil_ldelem_i4
+| 149 = @cil_ldelem_u4
+| 150 = @cil_ldelem_i8
+| 151 = @cil_ldelem_i
+| 152 = @cil_ldelem_r4
+| 153 = @cil_ldelem_r8
+| 154 = @cil_ldelem_ref
+| 155 = @cil_stelem_i
+| 156 = @cil_stelem_i1
+| 157 = @cil_stelem_i2
+| 158 = @cil_stelem_i4
+| 159 = @cil_stelem_i8
+| 160 = @cil_stelem_r4
+| 161 = @cil_stelem_r8
+| 162 = @cil_stelem_ref
+| 163 = @cil_ldelem
+| 164 = @cil_stelem
+| 165 = @cil_unbox_any
+| 179 = @cil_conv_ovf_i1
+| 180 = @cil_conv_ovf_u1
+| 181 = @cil_conv_ovf_i2
+| 182 = @cil_conv_ovf_u2
+| 183 = @cil_conv_ovf_i4
+| 184 = @cil_conv_ovf_u4
+| 185 = @cil_conv_ovf_i8
+| 186 = @cil_conv_ovf_u8
+| 194 = @cil_refanyval
+| 195 = @cil_ckinfinite
+| 198 = @cil_mkrefany
+| 208 = @cil_ldtoken
+| 209 = @cil_conv_u2
+| 210 = @cil_conv_u1
+| 211 = @cil_conv_i
+| 212 = @cil_conv_ovf_i
+| 213 = @cil_conv_ovf_u
+| 214 = @cil_add_ovf
+| 215 = @cil_add_ovf_un
+| 216 = @cil_mul_ovf
+| 217 = @cil_mul_ovf_un
+| 218 = @cil_sub_ovf
+| 219 = @cil_sub_ovf_un
+| 220 = @cil_endfinally
+| 221 = @cil_leave
+| 222 = @cil_leave_s
+| 223 = @cil_stind_i
+| 224 = @cil_conv_u
+| 65024 = @cil_arglist
+| 65025 = @cil_ceq
+| 65026 = @cil_cgt
+| 65027 = @cil_cgt_un
+| 65028 = @cil_clt
+| 65029 = @cil_clt_un
+| 65030 = @cil_ldftn
+| 65031 = @cil_ldvirtftn
+| 65033 = @cil_ldarg
+| 65034 = @cil_ldarga
+| 65035 = @cil_starg
+| 65036 = @cil_ldloc
+| 65037 = @cil_ldloca
+| 65038 = @cil_stloc
+| 65039 = @cil_localloc
+| 65041 = @cil_endfilter
+| 65042 = @cil_unaligned
+| 65043 = @cil_volatile
+| 65044 = @cil_tail
+| 65045 = @cil_initobj
+| 65046 = @cil_constrained
+| 65047 = @cil_cpblk
+| 65048 = @cil_initblk
+| 65050 = @cil_rethrow
+| 65052 = @cil_sizeof
+| 65053 = @cil_refanytype
+| 65054 = @cil_readonly
+;
+
+// CIL ignored instructions
+
+@cil_ignore = @cil_nop | @cil_break | @cil_volatile | @cil_unaligned;
+
+// CIL local/parameter/field access
+
+@cil_ldarg_any = @cil_ldarg_0 | @cil_ldarg_1 | @cil_ldarg_2 | @cil_ldarg_3 | @cil_ldarg_s | @cil_ldarga_s | @cil_ldarg | @cil_ldarga;
+@cil_starg_any = @cil_starg | @cil_starg_s;
+
+@cil_ldloc_any = @cil_ldloc_0 | @cil_ldloc_1 | @cil_ldloc_2 | @cil_ldloc_3 | @cil_ldloc_s | @cil_ldloca_s | @cil_ldloc | @cil_ldloca;
+@cil_stloc_any = @cil_stloc_0 | @cil_stloc_1 | @cil_stloc_2 | @cil_stloc_3 | @cil_stloc_s | @cil_stloc;
+
+@cil_ldfld_any = @cil_ldfld | @cil_ldsfld | @cil_ldsflda | @cil_ldflda;
+@cil_stfld_any = @cil_stfld | @cil_stsfld;
+
+@cil_local_access = @cil_stloc_any | @cil_ldloc_any;
+@cil_arg_access = @cil_starg_any | @cil_ldarg_any;
+@cil_read_access = @cil_ldloc_any | @cil_ldarg_any | @cil_ldfld_any;
+@cil_write_access = @cil_stloc_any | @cil_starg_any | @cil_stfld_any;
+
+@cil_stack_access = @cil_local_access | @cil_arg_access;
+@cil_field_access = @cil_ldfld_any | @cil_stfld_any;
+
+@cil_access = @cil_read_access | @cil_write_access;
+
+// CIL constant/literal instructions
+
+@cil_ldc_i = @cil_ldc_i4_any | @cil_ldc_i8;
+
+@cil_ldc_i4_any = @cil_ldc_i4_m1 | @cil_ldc_i4_0 | @cil_ldc_i4_1 | @cil_ldc_i4_2 | @cil_ldc_i4_3 |
+ @cil_ldc_i4_4 | @cil_ldc_i4_5 | @cil_ldc_i4_6 | @cil_ldc_i4_7 | @cil_ldc_i4_8 | @cil_ldc_i4_s | @cil_ldc_i4;
+
+@cil_ldc_r = @cil_ldc_r4 | @cil_ldc_r8;
+
+@cil_literal = @cil_ldnull | @cil_ldc_i | @cil_ldc_r | @cil_ldstr;
+
+// Control flow
+
+@cil_conditional_jump = @cil_binary_jump | @cil_unary_jump;
+@cil_binary_jump = @cil_beq_s | @cil_bge_s | @cil_bgt_s | @cil_ble_s | @cil_blt_s |
+ @cil_bne_un_s | @cil_bge_un_s | @cil_bgt_un_s | @cil_ble_un_s | @cil_blt_un_s |
+ @cil_beq | @cil_bge | @cil_bgt | @cil_ble | @cil_blt |
+ @cil_bne_un | @cil_bge_un | @cil_bgt_un | @cil_ble_un | @cil_blt_un;
+@cil_unary_jump = @cil_brfalse_s | @cil_brtrue_s | @cil_brfalse | @cil_brtrue | @cil_switch;
+@cil_unconditional_jump = @cil_br | @cil_br_s | @cil_leave_any;
+@cil_leave_any = @cil_leave | @cil_leave_s;
+@cil_jump = @cil_unconditional_jump | @cil_conditional_jump;
+
+// CIL call instructions
+
+@cil_call_any = @cil_jmp | @cil_call | @cil_calli | @cil_tail | @cil_callvirt | @cil_newobj;
+
+// CIL expression instructions
+
+@cil_expr = @cil_literal | @cil_binary_expr | @cil_unary_expr | @cil_call_any | @cil_read_access |
+ @cil_newarr | @cil_ldtoken | @cil_sizeof |
+ @cil_ldftn | @cil_ldvirtftn | @cil_localloc | @cil_mkrefany | @cil_refanytype | @cil_arglist | @cil_dup;
+
+@cil_unary_expr =
+ @cil_conversion_operation | @cil_unary_arithmetic_operation | @cil_unary_bitwise_operation|
+ @cil_ldlen | @cil_isinst | @cil_box | @cil_ldobj | @cil_castclass | @cil_unbox_any |
+ @cil_ldind | @cil_unbox;
+
+@cil_conversion_operation =
+ @cil_conv_i1 | @cil_conv_i2 | @cil_conv_i4 | @cil_conv_i8 |
+ @cil_conv_u1 | @cil_conv_u2 | @cil_conv_u4 | @cil_conv_u8 |
+ @cil_conv_ovf_i | @cil_conv_ovf_i_un | @cil_conv_ovf_i1 | @cil_conv_ovf_i1_un |
+ @cil_conv_ovf_i2 | @cil_conv_ovf_i2_un | @cil_conv_ovf_i4 | @cil_conv_ovf_i4_un |
+ @cil_conv_ovf_i8 | @cil_conv_ovf_i8_un | @cil_conv_ovf_u | @cil_conv_ovf_u_un |
+ @cil_conv_ovf_u1 | @cil_conv_ovf_u1_un | @cil_conv_ovf_u2 | @cil_conv_ovf_u2_un |
+ @cil_conv_ovf_u4 | @cil_conv_ovf_u4_un | @cil_conv_ovf_u8 | @cil_conv_ovf_u8_un |
+ @cil_conv_r4 | @cil_conv_r8 | @cil_conv_ovf_u2 | @cil_conv_ovf_u2_un |
+ @cil_conv_i | @cil_conv_u | @cil_conv_r_un;
+
+@cil_ldind = @cil_ldind_i | @cil_ldind_i1 | @cil_ldind_i2 | @cil_ldind_i4 | @cil_ldind_i8 |
+ @cil_ldind_r4 | @cil_ldind_r8 | @cil_ldind_ref | @cil_ldind_u1 | @cil_ldind_u2 | @cil_ldind_u4;
+
+@cil_stind = @cil_stind_i | @cil_stind_i1 | @cil_stind_i2 | @cil_stind_i4 | @cil_stind_i8 |
+ @cil_stind_r4 | @cil_stind_r8 | @cil_stind_ref;
+
+@cil_bitwise_operation = @cil_binary_bitwise_operation | @cil_unary_bitwise_operation;
+
+@cil_binary_bitwise_operation = @cil_and | @cil_or | @cil_xor | @cil_shr | @cil_shr | @cil_shr_un | @cil_shl;
+
+@cil_binary_arithmetic_operation = @cil_add | @cil_sub | @cil_mul | @cil_div | @cil_div_un |
+ @cil_rem | @cil_rem_un | @cil_add_ovf | @cil_add_ovf_un | @cil_mul_ovf | @cil_mul_ovf_un |
+ @cil_sub_ovf | @cil_sub_ovf_un;
+
+@cil_unary_bitwise_operation = @cil_not;
+
+@cil_binary_expr = @cil_binary_arithmetic_operation | @cil_binary_bitwise_operation | @cil_read_array | @cil_comparison_operation;
+
+@cil_unary_arithmetic_operation = @cil_neg;
+
+@cil_comparison_operation = @cil_cgt_un | @cil_ceq | @cil_cgt | @cil_clt | @cil_clt_un;
+
+// Elements that retrieve an address of something
+@cil_read_ref = @cil_ldloca_s | @cil_ldarga_s | @cil_ldflda | @cil_ldsflda | @cil_ldelema;
+
+// CIL array instructions
+
+@cil_read_array =
+ @cil_ldelem | @cil_ldelema | @cil_ldelem_i1 | @cil_ldelem_ref | @cil_ldelem_i |
+ @cil_ldelem_i1 | @cil_ldelem_i2 | @cil_ldelem_i4 | @cil_ldelem_i8 | @cil_ldelem_r4 |
+ @cil_ldelem_r8 | @cil_ldelem_u1 | @cil_ldelem_u2 | @cil_ldelem_u4;
+
+@cil_write_array = @cil_stelem | @cil_stelem_ref |
+ @cil_stelem_i | @cil_stelem_i1 | @cil_stelem_i2 | @cil_stelem_i4 | @cil_stelem_i8 |
+ @cil_stelem_r4 | @cil_stelem_r8;
+
+@cil_throw_any = @cil_throw | @cil_rethrow;
+
+#keyset[impl, index]
+cil_instruction(
+ unique int id: @cil_instruction,
+ int opcode: int ref,
+ int index: int ref,
+ int impl: @cil_method_implementation ref);
+
+cil_jump(
+ unique int instruction: @cil_jump ref,
+ int target: @cil_instruction ref);
+
+cil_access(
+ unique int instruction: @cil_instruction ref,
+ int target: @cil_accessible ref);
+
+cil_value(
+ unique int instruction: @cil_literal ref,
+ string value: string ref);
+
+#keyset[instruction, index]
+cil_switch(
+ int instruction: @cil_switch ref,
+ int index: int ref,
+ int target: @cil_instruction ref);
+
+cil_instruction_location(
+ unique int id: @cil_instruction ref,
+ int loc: @location ref);
+
+cil_type_location(
+ int id: @cil_type ref,
+ int loc: @location ref);
+
+cil_method_location(
+ int id: @cil_method ref,
+ int loc: @location ref);
+
+@cil_namespace = @namespace;
+
+@cil_type_container = @cil_type | @cil_namespace | @cil_method;
+
+case @cil_type.kind of
+ 0 = @cil_valueorreftype
+| 1 = @cil_typeparameter
+| 2 = @cil_array_type
+| 3 = @cil_pointer_type
+| 4 = @cil_function_pointer_type
+;
+
+cil_type(
+ unique int id: @cil_type,
+ string name: string ref,
+ int kind: int ref,
+ int parent: @cil_type_container ref,
+ int sourceDecl: @cil_type ref);
+
+cil_pointer_type(
+ unique int id: @cil_pointer_type ref,
+ int pointee: @cil_type ref);
+
+cil_array_type(
+ unique int id: @cil_array_type ref,
+ int element_type: @cil_type ref,
+ int rank: int ref);
+
+cil_function_pointer_return_type(
+ unique int id: @cil_function_pointer_type ref,
+ int return_type: @cil_type ref);
+
+cil_method(
+ unique int id: @cil_method,
+ string name: string ref,
+ int parent: @cil_type ref,
+ int return_type: @cil_type ref);
+
+cil_method_source_declaration(
+ unique int method: @cil_method ref,
+ int source: @cil_method ref);
+
+cil_method_implementation(
+ unique int id: @cil_method_implementation,
+ int method: @cil_method ref,
+ int location: @assembly ref);
+
+cil_implements(
+ int id: @cil_method ref,
+ int decl: @cil_method ref);
+
+#keyset[parent, name]
+cil_field(
+ unique int id: @cil_field,
+ int parent: @cil_type ref,
+ string name: string ref,
+ int field_type: @cil_type ref);
+
+@cil_element = @cil_instruction | @cil_declaration | @cil_handler | @cil_attribute | @cil_namespace;
+@cil_named_element = @cil_declaration | @cil_namespace;
+@cil_declaration = @cil_variable | @cil_method | @cil_type | @cil_member;
+@cil_accessible = @cil_declaration;
+@cil_variable = @cil_field | @cil_stack_variable;
+@cil_stack_variable = @cil_local_variable | @cil_parameter;
+@cil_member = @cil_method | @cil_type | @cil_field | @cil_property | @cil_event;
+@cil_custom_modifier_receiver = @cil_method | @cil_property | @cil_parameter | @cil_field | @cil_function_pointer_type;
+@cil_parameterizable = @cil_method | @cil_function_pointer_type;
+@cil_has_type_annotation = @cil_stack_variable | @cil_property | @cil_method | @cil_function_pointer_type;
+
+#keyset[parameterizable, index]
+cil_parameter(
+ unique int id: @cil_parameter,
+ int parameterizable: @cil_parameterizable ref,
+ int index: int ref,
+ int param_type: @cil_type ref);
+
+cil_parameter_in(unique int id: @cil_parameter ref);
+cil_parameter_out(unique int id: @cil_parameter ref);
+
+cil_setter(unique int prop: @cil_property ref,
+ int method: @cil_method ref);
+
+#keyset[id, modifier]
+cil_custom_modifiers(
+ int id: @cil_custom_modifier_receiver ref,
+ int modifier: @cil_type ref,
+ int kind: int ref); // modreq: 1, modopt: 0
+
+cil_type_annotation(
+ int id: @cil_has_type_annotation ref,
+ int annotation: int ref);
+
+cil_getter(unique int prop: @cil_property ref,
+ int method: @cil_method ref);
+
+cil_adder(unique int event: @cil_event ref,
+ int method: @cil_method ref);
+
+cil_remover(unique int event: @cil_event ref, int method: @cil_method ref);
+
+cil_raiser(unique int event: @cil_event ref, int method: @cil_method ref);
+
+cil_property(
+ unique int id: @cil_property,
+ int parent: @cil_type ref,
+ string name: string ref,
+ int property_type: @cil_type ref);
+
+#keyset[parent, name]
+cil_event(unique int id: @cil_event,
+ int parent: @cil_type ref,
+ string name: string ref,
+ int event_type: @cil_type ref);
+
+#keyset[impl, index]
+cil_local_variable(
+ unique int id: @cil_local_variable,
+ int impl: @cil_method_implementation ref,
+ int index: int ref,
+ int var_type: @cil_type ref);
+
+cil_function_pointer_calling_conventions(
+ int id: @cil_function_pointer_type ref,
+ int kind: int ref);
+
+// CIL handlers (exception handlers etc).
+
+case @cil_handler.kind of
+ 0 = @cil_catch_handler
+| 1 = @cil_filter_handler
+| 2 = @cil_finally_handler
+| 4 = @cil_fault_handler
+;
+
+#keyset[impl, index]
+cil_handler(
+ unique int id: @cil_handler,
+ int impl: @cil_method_implementation ref,
+ int index: int ref,
+ int kind: int ref,
+ int try_start: @cil_instruction ref,
+ int try_end: @cil_instruction ref,
+ int handler_start: @cil_instruction ref);
+
+cil_handler_filter(
+ unique int id: @cil_handler ref,
+ int filter_start: @cil_instruction ref);
+
+cil_handler_type(
+ unique int id: @cil_handler ref,
+ int catch_type: @cil_type ref);
+
+@cil_controlflow_node = @cil_entry_point | @cil_instruction;
+
+@cil_entry_point = @cil_method_implementation | @cil_handler;
+
+@cil_dataflow_node = @cil_instruction | @cil_variable | @cil_method;
+
+cil_method_stack_size(
+ unique int method: @cil_method_implementation ref,
+ int size: int ref);
+
+// CIL modifiers
+
+cil_public(int id: @cil_member ref);
+cil_private(int id: @cil_member ref);
+cil_protected(int id: @cil_member ref);
+cil_internal(int id: @cil_member ref);
+cil_static(int id: @cil_member ref);
+cil_sealed(int id: @cil_member ref);
+cil_virtual(int id: @cil_method ref);
+cil_abstract(int id: @cil_member ref);
+cil_class(int id: @cil_type ref);
+cil_interface(int id: @cil_type ref);
+cil_security(int id: @cil_member ref);
+cil_requiresecobject(int id: @cil_method ref);
+cil_specialname(int id: @cil_method ref);
+cil_newslot(int id: @cil_method ref);
+
+cil_base_class(unique int id: @cil_type ref, int base: @cil_type ref);
+cil_base_interface(int id: @cil_type ref, int base: @cil_type ref);
+cil_enum_underlying_type(unique int id: @cil_type ref, int underlying: @cil_type ref);
+
+#keyset[unbound, index]
+cil_type_parameter(
+ int unbound: @cil_member ref,
+ int index: int ref,
+ int param: @cil_typeparameter ref);
+
+#keyset[bound, index]
+cil_type_argument(
+ int bound: @cil_member ref,
+ int index: int ref,
+ int t: @cil_type ref);
+
+// CIL type parameter constraints
+
+cil_typeparam_covariant(int tp: @cil_typeparameter ref);
+cil_typeparam_contravariant(int tp: @cil_typeparameter ref);
+cil_typeparam_class(int tp: @cil_typeparameter ref);
+cil_typeparam_struct(int tp: @cil_typeparameter ref);
+cil_typeparam_new(int tp: @cil_typeparameter ref);
+cil_typeparam_constraint(int tp: @cil_typeparameter ref, int supertype: @cil_type ref);
+
+// CIL attributes
+
+cil_attribute(
+ unique int attributeid: @cil_attribute,
+ int element: @cil_declaration ref,
+ int constructor: @cil_method ref);
+
+#keyset[attribute_id, param]
+cil_attribute_named_argument(
+ int attribute_id: @cil_attribute ref,
+ string param: string ref,
+ string value: string ref);
+
+#keyset[attribute_id, index]
+cil_attribute_positional_argument(
+ int attribute_id: @cil_attribute ref,
+ int index: int ref,
+ string value: string ref);
+
+
+// Common .Net data model covering both C# and CIL
+
+// Common elements
+@dotnet_element = @element | @cil_element;
+@dotnet_named_element = @named_element | @cil_named_element;
+@dotnet_callable = @callable | @cil_method;
+@dotnet_variable = @variable | @cil_variable;
+@dotnet_field = @field | @cil_field;
+@dotnet_parameter = @parameter | @cil_parameter;
+@dotnet_declaration = @declaration | @cil_declaration;
+@dotnet_member = @member | @cil_member;
+@dotnet_event = @event | @cil_event;
+@dotnet_property = @property | @cil_property | @indexer;
+@dotnet_parameterizable = @parameterizable | @cil_parameterizable;
+
+// Common types
+@dotnet_type = @type | @cil_type;
+@dotnet_call = @call | @cil_call_any;
+@dotnet_throw = @throw_element | @cil_throw_any;
+@dotnet_valueorreftype = @cil_valueorreftype | @value_or_ref_type | @cil_array_type | @void_type;
+@dotnet_typeparameter = @type_parameter | @cil_typeparameter;
+@dotnet_array_type = @array_type | @cil_array_type;
+@dotnet_pointer_type = @pointer_type | @cil_pointer_type;
+@dotnet_type_parameter = @type_parameter | @cil_typeparameter;
+@dotnet_generic = @dotnet_valueorreftype | @dotnet_callable;
+
+// Attributes
+@dotnet_attribute = @attribute | @cil_attribute;
+
+// Expressions
+@dotnet_expr = @expr | @cil_expr;
+
+// Literals
+@dotnet_literal = @literal_expr | @cil_literal;
+@dotnet_string_literal = @string_literal_expr | @cil_ldstr;
+@dotnet_int_literal = @integer_literal_expr | @cil_ldc_i;
+@dotnet_float_literal = @float_literal_expr | @cil_ldc_r;
+@dotnet_null_literal = @null_literal_expr | @cil_ldnull;
+
+@metadata_entity = @cil_method | @cil_type | @cil_field | @cil_property | @field | @property |
+ @callable | @value_or_ref_type | @void_type;
+
+#keyset[entity, location]
+metadata_handle(int entity : @metadata_entity ref, int location: @assembly ref, int handle: int ref)
diff --git a/csharp/ql/lib/upgrades/83aca6b3e4fa38dd2b97b9b51dfc199a2ba9c7f2/upgrade.properties b/csharp/ql/lib/upgrades/83aca6b3e4fa38dd2b97b9b51dfc199a2ba9c7f2/upgrade.properties
new file mode 100644
index 00000000000..25d7416df1c
--- /dev/null
+++ b/csharp/ql/lib/upgrades/83aca6b3e4fa38dd2b97b9b51dfc199a2ba9c7f2/upgrade.properties
@@ -0,0 +1,2 @@
+description: Add unsigned right shift and unsigned right shift assignment expression kinds.
+compatibility: backwards
From 1384aa669b34c306b59ba20265ba7736828cec17 Mon Sep 17 00:00:00 2001
From: Michael Nebel
Date: Wed, 11 Jan 2023 16:49:36 +0100
Subject: [PATCH 237/381] C#: Add change note.
---
csharp/ql/lib/change-notes/2023-01-11-unsigned-right-shift.md | 4 ++++
1 file changed, 4 insertions(+)
create mode 100644 csharp/ql/lib/change-notes/2023-01-11-unsigned-right-shift.md
diff --git a/csharp/ql/lib/change-notes/2023-01-11-unsigned-right-shift.md b/csharp/ql/lib/change-notes/2023-01-11-unsigned-right-shift.md
new file mode 100644
index 00000000000..6c644b8b2fb
--- /dev/null
+++ b/csharp/ql/lib/change-notes/2023-01-11-unsigned-right-shift.md
@@ -0,0 +1,4 @@
+---
+category: minorAnalysis
+---
+* C# 11: Added support for the unsigned right shift `>>>` and unsigned right shift assignment `>>>=` operators.
\ No newline at end of file
From c1c0ff4308f5f748bf65cc01e04f1d0230dd1124 Mon Sep 17 00:00:00 2001
From: Michael Nebel
Date: Thu, 12 Jan 2023 10:38:14 +0100
Subject: [PATCH 238/381] C#: Update database stats.
---
.../ql/lib/semmlecode.csharp.dbscheme.stats | 4346 ++++++++---------
1 file changed, 2173 insertions(+), 2173 deletions(-)
diff --git a/csharp/ql/lib/semmlecode.csharp.dbscheme.stats b/csharp/ql/lib/semmlecode.csharp.dbscheme.stats
index 8204b7b9aaa..b7c93de7353 100644
--- a/csharp/ql/lib/semmlecode.csharp.dbscheme.stats
+++ b/csharp/ql/lib/semmlecode.csharp.dbscheme.stats
@@ -17,12 +17,12 @@
0
- @assembly
- 14676
+ @file
+ 106540
- @file
- 106541
+ @assembly
+ 14676@folder
@@ -30,35 +30,31 @@
@namespace
- 500337
+ 500332@namespace_declaration
- 42810
+ 42809@using_namespace_directive
- 223779
+ 223777@using_static_directive3484
-
- @directive_if
- 16750
- @directive_elif275
- @directive_else
- 5439
+ @directive_if
+ 16749
- @location_default
- 137912010
+ @directive_else
+ 5439@directive_endif
@@ -92,6 +88,10 @@
@directive_undefine55
+
+ @location_default
+ 137911541
+ @directive_define66
@@ -106,7 +106,7 @@
@typeref
- 4815264
+ 4815219@bool_type
@@ -162,23 +162,23 @@
@enum_type
- 204056
+ 204054@struct_type
- 1036578
+ 1036568@class_type
- 5157996
+ 5157948@interface_type
- 3246154
+ 3246124@delegate_type
- 1214025
+ 1214014@null_type
@@ -186,7 +186,7 @@
@type_parameter
- 991372
+ 991363@pointer_type
@@ -198,7 +198,7 @@
@array_type
- 116793
+ 116792@void_type
@@ -222,7 +222,7 @@
@tuple_type
- 37858
+ 37857@function_pointer_type
@@ -232,26 +232,26 @@
@uint_ptr_type0
-
- @type_mention
- 2667838
- @attribute_default
- 14361364
+ 14361230@attribute_return
- 224363
+ 224361@attribute_assembly
- 52426
+ 52425@attribute_module53
+
+ @type_mention
+ 2667808
+ @oblivious21291
@@ -266,7 +266,7 @@
@type_parameter_constraints
- 991372
+ 991363@modifier
@@ -274,19 +274,19 @@
@property
- 6642412
+ 6642350@indexer
- 105719
+ 105718@getter
- 6738210
+ 6738147@setter
- 1177149
+ 1177138@event
@@ -302,15 +302,15 @@
@operator
- 629721
+ 629715@method
- 20454980
+ 20454789@constructor
- 5991233
+ 5991176@destructor
@@ -322,15 +322,15 @@
@addressable_field
- 11102837
+ 11102733@constant
- 3873680
+ 3873643@addressable_local_variable
- 497829
+ 497825@local_constant
@@ -342,19 +342,19 @@
@parameter
- 37386455
+ 37386105@block_stmt
- 643009
+ 643003@expr_stmt
- 698450
+ 698444@if_stmt
- 299700
+ 299697@switch_stmt
@@ -366,7 +366,7 @@
@do_stmt
- 1916
+ 1915@for_stmt
@@ -374,15 +374,15 @@
@foreach_stmt
- 26826
+ 26825@break_stmt
- 106776
+ 106775@continue_stmt
- 8596
+ 8595@goto_stmt
@@ -394,11 +394,11 @@
@throw_stmt
- 157116
+ 157106@return_stmt
- 301790
+ 301787@yield_stmt
@@ -426,7 +426,7 @@
@var_decl_stmt
- 449250
+ 449246@const_decl_stmt
@@ -446,7 +446,7 @@
@case_stmt
- 118515
+ 118513@goto_default_stmt
@@ -466,19 +466,19 @@
@using_decl_stmt
- 11564
+ 11563@bool_literal_expr
- 472283
+ 472278@char_literal_expr
- 61271
+ 61270@int_literal_expr
- 3354291
+ 3354259@long_literal_expr
@@ -490,27 +490,27 @@
@ulong_literal_expr
- 3300
+ 3299@float_literal_expr
- 109488
+ 109487@double_literal_expr
- 54800
+ 54799@string_literal_expr
- 2171269
+ 2171248@null_literal_expr
- 215382
+ 215366@this_access_expr
- 857625
+ 857617@base_access_expr
@@ -518,19 +518,19 @@
@local_variable_access_expr
- 1451844
+ 1451830@parameter_access_expr
- 841262
+ 841254@field_access_expr
- 1097227
+ 1097217@property_access_expr
- 1242991
+ 1242979@method_access_expr
@@ -550,15 +550,15 @@
@type_access_expr
- 1243003
+ 1242991@typeof_expr
- 597670
+ 597664@method_invocation_expr
- 1078551
+ 1078542@delegate_invocation_expr
@@ -566,15 +566,15 @@
@operator_invocation_expr
- 596656
+ 596650@cast_expr
- 781499
+ 781491@object_creation_expr
- 202927
+ 202926@explicit_delegate_creation_expr
@@ -586,11 +586,11 @@
@array_creation_expr
- 565044
+ 565039@default_expr
- 669657
+ 669651@minus_expr
@@ -598,7 +598,7 @@
@log_not_expr
- 60763
+ 60762@post_incr_expr
@@ -618,7 +618,7 @@
@mul_expr
- 9154
+ 9153@div_expr
@@ -630,11 +630,11 @@
@add_expr
- 72534
+ 72533@sub_expr
- 25994
+ 25993@lshift_expr
@@ -644,17 +644,13 @@
@rshift_expr5127
-
- @urshift_expr
- 0
- @lt_expr
- 34251
+ 34250@gt_expr
- 20968
+ 20967@le_expr
@@ -662,15 +658,15 @@
@ge_expr
- 12159
+ 12158@eq_expr
- 135300
+ 135298@ne_expr
- 117244
+ 117243@bit_and_expr
@@ -686,7 +682,7 @@
@log_and_expr
- 51646
+ 51645@log_or_expr
@@ -694,7 +690,7 @@
@is_expr
- 19997
+ 19994@as_expr
@@ -706,11 +702,11 @@
@conditional_expr
- 34750
+ 34749@simple_assign_expr
- 1223633
+ 1223622@assign_add_expr
@@ -730,7 +726,7 @@
@object_init_expr
- 163090
+ 163088@collection_init_expr
@@ -738,7 +734,7 @@
@array_init_expr
- 564188
+ 564183@checked_expr
@@ -750,7 +746,7 @@
@constructor_init_expr
- 42947
+ 42945@add_event_expr
@@ -762,11 +758,11 @@
@local_var_decl_expr
- 499277
+ 499273@lambda_expr
- 200792
+ 200791@anonymous_method_expr
@@ -782,7 +778,7 @@
@nameof_expr
- 50715
+ 50714@interpolated_string_expr
@@ -798,15 +794,15 @@
@discard_expr
- 30087
+ 30086@define_symbol_expr
- 32513
+ 32512@decimal_literal_expr
- 157044
+ 157042@plus_expr
@@ -840,10 +836,6 @@
@assign_rshift_expr455
-
- @assign_urshift_expr
- 0
- @par_expr0
@@ -894,11 +886,11 @@
@recursive_pattern_expr
- 3150
+ 3146@property_pattern_expr
- 2543
+ 2533@positional_pattern_expr
@@ -906,7 +898,7 @@
@switch_case_expr
- 660643
+ 660636@assign_coalesce_expr
@@ -914,7 +906,7 @@
@suppress_nullable_warning_expr
- 25801
+ 25799@namespace_access_expr
@@ -938,7 +930,7 @@
@not_pattern_expr
- 2910
+ 2909@and_pattern_expr
@@ -946,7 +938,7 @@
@or_pattern_expr
- 2477
+ 2476@function_pointer_invocation_expr
@@ -964,17 +956,25 @@
@slice_pattern_expr18
+
+ @urshift_expr
+ 50
+
+
+ @assign_urshift_expr
+ 2
+ @xmldtd58@xmlelement
- 60596893
+ 60596686@xmlattribute
- 41517960
+ 41517819@xmlnamespace
@@ -986,23 +986,23 @@
@xmlcharacters
- 45379511
+ 45379357@singlelinecomment
- 673827
+ 673821@xmldoccomment
- 1226196
+ 1226185@multilinecomment
- 82948
+ 82947@commentblock
- 374970
+ 374967@asp_close_tag
@@ -1030,7 +1030,7 @@
@asp_quoted_string
- 47186
+ 47185@asp_text
@@ -1042,15 +1042,15 @@
@cil_valueorreftype
- 10427087
+ 10426990@cil_typeparameter
- 1773609
+ 1773592@cil_array_type
- 181790
+ 181788@cil_pointer_type
@@ -1058,135 +1058,139 @@
@cil_function_pointer_type
- 39912
+ 39911
+
+
+ @cil_method
+ 39373409@cil_nop
- 1327129
+ 1327046@cil_ldarg_0
- 53581819
+ 53581318@cil_ldarg_1
- 20969699
+ 20969503@cil_ldarg_2
- 7471514
+ 7471444@cil_ldarg_3
- 3234755
+ 3234725@cil_ldloc_0
- 17598601
+ 17598436@cil_ldloc_1
- 9495219
+ 9495130@cil_ldloc_2
- 6739302
+ 6739239@cil_ldloc_3
- 4230971
+ 4230931@cil_stloc_0
- 8735189
+ 8735107@cil_stloc_1
- 5003935
+ 5003888@cil_stloc_2
- 3618151
+ 3618117@cil_stloc_3
- 2480277
+ 2480254@cil_ldarg_s
- 3414862
+ 3414830@cil_ldarga_s
- 1248318
+ 1248307@cil_starg_s
- 270382
+ 270379@cil_ldloc_s
- 14457162
+ 14457027@cil_ldloca_s
- 9786184
+ 9786093@cil_stloc_s
- 9038705
+ 9038620@cil_ldnull
- 5794381
+ 5794327@cil_ldc_i4_m1
- 871537
+ 871529@cil_ldc_i4_0
- 10862959
+ 10862858@cil_ldc_i4_1
- 8606701
+ 8606621@cil_ldc_i4_2
- 1948578
+ 1948560@cil_ldc_i4_3
- 1073526
+ 1073516@cil_ldc_i4_4
- 985880
+ 985870@cil_ldc_i4_5
- 578416
+ 578411@cil_ldc_i4_6
- 334080
+ 334076@cil_ldc_i4_7
- 296812
+ 296809@cil_ldc_i4_8
- 444583
+ 444579@cil_ldc_i4_s
- 5378885
+ 5378835@cil_ldc_i4
- 2836653
+ 2836626@cil_ldc_i8
@@ -1194,23 +1198,23 @@
@cil_ldc_r4
- 31066
+ 31065@cil_ldc_r8
- 238341
+ 238339@cil_dup
- 9272617
+ 9272530@cil_pop
- 3880176
+ 3880140@cil_call
- 48855176
+ 48854719@cil_calli
@@ -1218,43 +1222,43 @@
@cil_ret
- 31661234
+ 31660937@cil_br_s
- 5776958
+ 5776904@cil_brfalse_s
- 10010144
+ 10010051@cil_brtrue_s
- 9349219
+ 9349132@cil_beq_s
- 1588452
+ 1588437@cil_bge_s
- 302364
+ 302361@cil_bgt_s
- 237898
+ 237896@cil_ble_s
- 342112
+ 342109@cil_blt_s
- 581015
+ 581009@cil_bne_un_s
- 2310181
+ 2310159@cil_bge_un_s
@@ -1262,11 +1266,11 @@
@cil_bgt_un_s
- 101083
+ 101082@cil_ble_un_s
- 98691
+ 98690@cil_blt_un_s
@@ -1274,23 +1278,23 @@
@cil_br
- 1432176
+ 1432163@cil_brfalse
- 953957
+ 953948@cil_brtrue
- 803794
+ 803786@cil_beq
- 420014
+ 420010@cil_bge
- 34905
+ 34904@cil_bgt
@@ -1302,11 +1306,11 @@
@cil_blt
- 95206
+ 95205@cil_bne_un
- 210730
+ 210728@cil_bge_un
@@ -1326,7 +1330,7 @@
@cil_switch
- 272685
+ 272683@cil_ldind_i1
@@ -1334,7 +1338,7 @@
@cil_ldind_u1
- 90068
+ 90067@cil_ldind_u2
@@ -1342,7 +1346,7 @@
@cil_ldind_i4
- 219353
+ 219351@cil_ldind_u4
@@ -1362,15 +1366,15 @@
@cil_ldind_ref
- 190974
+ 190972@cil_stind_ref
- 325516
+ 325513@cil_stind_i1
- 144847
+ 144846@cil_stind_i2
@@ -1378,7 +1382,7 @@
@cil_stind_i4
- 441482
+ 441478@cil_stind_i8
@@ -1394,19 +1398,19 @@
@cil_add
- 2691805
+ 2691780@cil_sub
- 1007112
+ 1007103@cil_mul
- 426481
+ 426477@cil_div
- 85048
+ 85047@cil_div_un
@@ -1422,31 +1426,31 @@
@cil_and
- 506036
+ 506032@cil_or
- 225791
+ 225789@cil_xor
- 192185
+ 192183@cil_shl
- 118122
+ 118121@cil_shr
- 60626
+ 60625@cil_shr_un
- 114815
+ 114814@cil_neg
- 29501
+ 29500@cil_not
@@ -1462,11 +1466,11 @@
@cil_conv_i4
- 534002
+ 533997@cil_conv_i8
- 309038
+ 309035@cil_conv_r4
@@ -1482,11 +1486,11 @@
@cil_conv_u8
- 142987
+ 142985@cil_callvirt
- 41217611
+ 41217225@cil_cpobj
@@ -1494,23 +1498,23 @@
@cil_ldobj
- 163865
+ 163863@cil_ldstr
- 11254978
+ 11254873@cil_newobj
- 12728409
+ 12728290@cil_castclass
- 1803967
+ 1803950@cil_isinst
- 2744724
+ 2744698@cil_conv_r_un
@@ -1522,23 +1526,23 @@
@cil_throw
- 1827943
+ 1827881@cil_ldfld
- 23008966
+ 23008751@cil_ldflda
- 1951443
+ 1951424@cil_stfld
- 11363976
+ 11363870@cil_ldsfld
- 10513996
+ 10513898@cil_ldsflda
@@ -1546,7 +1550,7 @@
@cil_stsfld
- 2599167
+ 2599143@cil_stobj
@@ -1554,19 +1558,19 @@
@cil_box
- 1419832
+ 1419819@cil_newarr
- 1603690
+ 1603675@cil_ldlen
- 570295
+ 570290@cil_ldelema
- 714434
+ 714427@cil_ldelem_i1
@@ -1574,7 +1578,7 @@
@cil_ldelem_u1
- 104863
+ 104862@cil_ldelem_i2
@@ -1586,15 +1590,15 @@
@cil_ldelem_i4
- 158254
+ 158253@cil_ldelem_u4
- 130732
+ 130730@cil_ldelem_i8
- 64583
+ 64582@cil_ldelem_i
@@ -1610,7 +1614,7 @@
@cil_ldelem_ref
- 344799
+ 344796@cil_stelem_i
@@ -1618,7 +1622,7 @@
@cil_stelem_i1
- 75244
+ 75243@cil_stelem_i2
@@ -1626,11 +1630,11 @@
@cil_stelem_i4
- 173108
+ 173106@cil_stelem_i8
- 31007
+ 31006@cil_stelem_r8
@@ -1638,19 +1642,19 @@
@cil_stelem_ref
- 4221551
+ 4221511@cil_ldelem
- 35909
+ 35908@cil_stelem
- 208190
+ 208188@cil_unbox_any
- 227651
+ 227649@cil_conv_ovf_u1
@@ -1666,7 +1670,7 @@
@cil_ldtoken
- 1020371
+ 1020362@cil_conv_u2
@@ -1674,11 +1678,11 @@
@cil_conv_u1
- 238253
+ 238250@cil_conv_i
- 34285
+ 34284@cil_conv_ovf_i
@@ -1698,15 +1702,15 @@
@cil_endfinally
- 1967891
+ 1967873@cil_leave
- 692729
+ 692723@cil_leave_s
- 3134203
+ 3134174@cil_stind_i
@@ -1714,11 +1718,11 @@
@cil_conv_u
- 114135
+ 114134@cil_ceq
- 930037
+ 930028@cil_cgt
@@ -1726,11 +1730,11 @@
@cil_cgt_un
- 355253
+ 355250@cil_clt
- 75775
+ 75774@cil_clt_un
@@ -1738,7 +1742,7 @@
@cil_ldftn
- 2883016
+ 2882989@cil_ldvirtftn
@@ -1770,15 +1774,15 @@
@cil_volatile
- 55222
+ 55221@cil_initobj
- 950709
+ 950700@cil_constrained
- 758376
+ 758368@cil_cpblk
@@ -1790,7 +1794,7 @@
@cil_rethrow
- 72025
+ 72024@cil_sizeof
@@ -1922,7 +1926,7 @@
@cil_ldloca
- 78758
+ 78757@cil_tail
@@ -1932,37 +1936,33 @@
@cil_refanytype13
-
- @cil_method
- 39373777
- @cil_method_implementation
- 27073001
+ 27072747@cil_field
- 15899467
+ 15899318@cil_parameter
- 75119038
-
-
- @cil_property
- 6002749
+ 75118336@cil_event
- 70696
+ 70695
+
+
+ @cil_property
+ 6002693@cil_local_variable
- 23026507
+ 23026292@cil_catch_handler
- 400819
+ 400815@cil_filter_handler
@@ -1970,15 +1970,15 @@
@cil_finally_handler
- 1662456
+ 1662440@cil_fault_handler
- 305435
+ 305432@cil_attribute
- 5874527
+ 5874473
@@ -2328,7 +2328,7 @@
compilation_compiling_files
- 49881
+ 49880id
@@ -2648,7 +2648,7 @@
12
- 49836
+ 498352
@@ -2669,7 +2669,7 @@
12
- 49836
+ 498352
@@ -2684,7 +2684,7 @@
compilation_referencing_files
- 719519
+ 719512id
@@ -2918,57 +2918,62 @@
15
- 630
+ 57456
- 1159
+ 114867
- 900
+ 9577
- 22
+ 21
+ 540
+
+
+ 21
+ 27574
- 22
- 28
- 574
+ 27
+ 32
+ 540
- 28
- 35
- 517
-
-
- 35
+ 3242529
- 42
- 58
+ 43
+ 59551
- 58
- 67
- 608
+ 59
+ 66
+ 495
- 67
- 70
+ 66
+ 69
+ 506
+
+
+ 69
+ 73585
- 70
- 77
- 416
+ 73
+ 82
+ 45
@@ -3045,62 +3050,62 @@
25
- 585
+ 56256
- 630
+ 49567
- 641
+ 7887
- 10
+ 9
+ 596
+
+
+ 9
+ 19675
- 10
- 20
- 686
-
-
- 20
- 28
- 675
-
-
- 28
- 35
- 619
-
-
- 35
- 51
+ 19
+ 25574
- 51
- 68
- 439
+ 25
+ 32
+ 596
- 68
- 70
- 484
+ 32
+ 38
+ 608
- 70
+ 38
+ 67
+ 517
+
+
+ 67
+ 69
+ 517
+
+
+ 6972
- 574
+ 63072
- 78
- 304
+ 77
+ 326
@@ -3126,7 +3131,7 @@
seconds
- 11226
+ 11530
@@ -3172,12 +3177,12 @@
67
- 11
+ 2278
- 2206
+ 2195
@@ -3223,8 +3228,8 @@
12
- 997
- 998
+ 1024
+ 102511
@@ -3271,19 +3276,24 @@
12
- 138
- 139
+ 143
+ 14411
- 144
- 145
+ 146
+ 14711
- 152
- 153
- 22
+ 155
+ 156
+ 11
+
+
+ 157
+ 158
+ 11197
@@ -3304,7 +3314,7 @@
12
- 9007
+ 93452
@@ -3314,12 +3324,12 @@
35
- 945
+ 10355
- 10
- 247
+ 8
+ 123
@@ -3335,7 +3345,7 @@
12
- 11226
+ 11530
@@ -3351,17 +3361,17 @@
12
- 9570
+ 987423
- 1328
+ 142935
- 326
+ 225
@@ -4420,7 +4430,7 @@
12
- 31693
+ 316922
@@ -4489,7 +4499,7 @@
12
- 31693
+ 316922
@@ -4547,7 +4557,7 @@
12
- 40646
+ 406452
@@ -4568,7 +4578,7 @@
12
- 40646
+ 406452
@@ -4589,7 +4599,7 @@
12
- 40646
+ 406452
@@ -5365,7 +5375,7 @@
cpu_seconds
- 1936
+ 2060elapsed_seconds
@@ -5415,17 +5425,12 @@
12
- 1666
+ 19252
- 3
- 258
-
-
- 34
- 11
+ 135
@@ -5441,17 +5446,12 @@
12
- 1666
+ 19252
- 3
- 258
-
-
- 34
- 11
+ 135
@@ -5696,19 +5696,19 @@
locations_default
- 137912010
+ 137911541id
- 137912010
+ 137911541file
- 73412
+ 73411beginLine
- 328702
+ 328701beginColumn
@@ -5716,7 +5716,7 @@
endLine
- 331303
+ 331302endColumn
@@ -5734,7 +5734,7 @@
12
- 137912010
+ 137911541
@@ -5750,7 +5750,7 @@
12
- 137912010
+ 137911541
@@ -5766,7 +5766,7 @@
12
- 137912010
+ 137911541
@@ -5782,7 +5782,7 @@
12
- 137912010
+ 137911541
@@ -5798,7 +5798,7 @@
12
- 137912010
+ 137911541
@@ -5971,7 +5971,7 @@
16
- 5045
+ 50446
@@ -6107,7 +6107,7 @@
2417135652
- 5197
+ 5196
@@ -6204,7 +6204,7 @@
45
- 21425
+ 214245
@@ -6528,7 +6528,7 @@
5778
- 24880
+ 2487978
@@ -6961,7 +6961,7 @@
23
- 76464
+ 764633
@@ -7159,7 +7159,7 @@
12
- 10090
+ 100892
@@ -7353,15 +7353,15 @@
locations_mapped
- 135223
+ 135221id
- 135223
+ 135221mapped_to
- 83194
+ 83193
@@ -7375,7 +7375,7 @@
12
- 135223
+ 135221
@@ -7391,7 +7391,7 @@
12
- 31212
+ 312112
@@ -7411,11 +7411,11 @@
numlines
- 60897147
+ 60896940element_id
- 60897038
+ 60896831num_lines
@@ -7441,7 +7441,7 @@
12
- 60896930
+ 608967232
@@ -7462,7 +7462,7 @@
12
- 60896932
+ 608967252
@@ -7483,7 +7483,7 @@
12
- 60897026
+ 608968192
@@ -8084,7 +8084,7 @@
12
- 14588
+ 145873
@@ -8105,7 +8105,7 @@
12
- 14588
+ 145873
@@ -8158,7 +8158,7 @@
12
- 14588
+ 145873
@@ -8179,7 +8179,7 @@
12
- 14588
+ 145873
@@ -8390,15 +8390,15 @@
files
- 106541
+ 106540id
- 106541
+ 106540name
- 106541
+ 106540
@@ -8412,7 +8412,7 @@
12
- 106541
+ 106540
@@ -8428,7 +8428,7 @@
12
- 106541
+ 106540
@@ -8486,7 +8486,7 @@
containerparent
- 143755
+ 143753parent
@@ -8494,7 +8494,7 @@
child
- 143755
+ 143753
@@ -8554,7 +8554,7 @@
12
- 143755
+ 143753
@@ -8612,15 +8612,15 @@
namespaces
- 500337
+ 500332id
- 500337
+ 500332name
- 86288
+ 86287
@@ -8634,7 +8634,7 @@
12
- 500337
+ 500332
@@ -8655,7 +8655,7 @@
23
- 52830
+ 528293
@@ -8700,11 +8700,11 @@
namespace_declarations
- 42810
+ 42809id
- 42810
+ 42809namespace_id
@@ -8722,7 +8722,7 @@
12
- 42810
+ 42809
@@ -8783,15 +8783,15 @@
namespace_declaration_location
- 42810
+ 42809id
- 42810
+ 42809loc
- 42810
+ 42809
@@ -8805,7 +8805,7 @@
12
- 42810
+ 42809
@@ -8821,7 +8821,7 @@
12
- 42810
+ 42809
@@ -8831,15 +8831,15 @@
parent_namespace
- 9856437
+ 9856345child_id
- 9856437
+ 9856345namespace_id
- 314826
+ 314823
@@ -8853,7 +8853,7 @@
12
- 9856437
+ 9856345
@@ -8869,12 +8869,12 @@
12
- 81977
+ 8197623
- 44857
+ 448563
@@ -8884,7 +8884,7 @@
45
- 21321
+ 213205
@@ -8899,7 +8899,7 @@
812
- 28556
+ 2855512
@@ -8909,7 +8909,7 @@
1944
- 23831
+ 2383044
@@ -8946,7 +8946,7 @@
12
- 53097
+ 530962
@@ -9003,11 +9003,11 @@
using_namespace_directives
- 223779
+ 223777id
- 223779
+ 223777namespace_id
@@ -9025,7 +9025,7 @@
12
- 223779
+ 223777
@@ -9144,15 +9144,15 @@
using_directive_location
- 223959
+ 223957id
- 223959
+ 223957loc
- 223846
+ 223844
@@ -9166,7 +9166,7 @@
12
- 223959
+ 223957
@@ -9182,7 +9182,7 @@
12
- 223734
+ 2237322
@@ -9197,11 +9197,11 @@
directive_ifs
- 16750
+ 16749id
- 16750
+ 16749branchTaken
@@ -9223,7 +9223,7 @@
12
- 16750
+ 16749
@@ -9239,7 +9239,7 @@
12
- 16750
+ 16749
@@ -10065,7 +10065,7 @@
start
- 16750
+ 16749
@@ -10095,7 +10095,7 @@
12
- 16750
+ 16749
@@ -10105,11 +10105,11 @@
directive_define_symbols
- 32513
+ 32512id
- 32513
+ 32512name
@@ -10127,7 +10127,7 @@
12
- 32513
+ 32512
@@ -11640,15 +11640,15 @@
preprocessor_directive_location
- 79638
+ 79637id
- 79638
+ 79637loc
- 79638
+ 79637
@@ -11662,7 +11662,7 @@
12
- 79638
+ 79637
@@ -11678,7 +11678,7 @@
12
- 79638
+ 79637
@@ -11688,11 +11688,11 @@
preprocessor_directive_compilation
- 79638
+ 79637id
- 79638
+ 79637compilation
@@ -11710,7 +11710,7 @@
12
- 79638
+ 79637
@@ -11761,11 +11761,11 @@
preprocessor_directive_active
- 79638
+ 79637id
- 79638
+ 79637active
@@ -11783,7 +11783,7 @@
12
- 79638
+ 79637
@@ -11814,11 +11814,11 @@
types
- 11520193
+ 11520085id
- 11520193
+ 11520085kind
@@ -11826,7 +11826,7 @@
name
- 3497046
+ 3497013
@@ -11840,7 +11840,7 @@
12
- 11520193
+ 11520085
@@ -11856,7 +11856,7 @@
12
- 11520193
+ 11520085
@@ -11959,17 +11959,17 @@
12
- 3141586
+ 314155725
- 274812
+ 274809521597
- 80648
+ 80647
@@ -11985,7 +11985,7 @@
12
- 3468460
+ 34684282
@@ -12000,15 +12000,15 @@
typerefs
- 4815264
+ 4815219id
- 4815264
+ 4815219name
- 3370389
+ 3370358
@@ -12022,7 +12022,7 @@
12
- 4815264
+ 4815219
@@ -12038,12 +12038,12 @@
12
- 3128415
+ 3128386211806
- 241973
+ 241971
@@ -12053,15 +12053,15 @@
typeref_type
- 4775132
+ 4775087id
- 4775132
+ 4775087typeId
- 4775132
+ 4775087
@@ -12075,7 +12075,7 @@
12
- 4775132
+ 4775087
@@ -12091,7 +12091,7 @@
12
- 4775132
+ 4775087
@@ -12101,11 +12101,11 @@
array_element_type
- 116793
+ 116792array
- 116793
+ 116792dimension
@@ -12117,7 +12117,7 @@
element
- 116409
+ 116408
@@ -12131,7 +12131,7 @@
12
- 116793
+ 116792
@@ -12147,7 +12147,7 @@
12
- 116793
+ 116792
@@ -12163,7 +12163,7 @@
12
- 116793
+ 116792
@@ -12325,7 +12325,7 @@
12
- 116084
+ 1160832
@@ -12346,7 +12346,7 @@
12
- 116409
+ 116408
@@ -12362,7 +12362,7 @@
12
- 116084
+ 1160832
@@ -12473,11 +12473,11 @@
enum_underlying_type
- 204056
+ 204054enum_id
- 204056
+ 204054underlying_type_id
@@ -12495,7 +12495,7 @@
12
- 204056
+ 204054
@@ -12556,15 +12556,15 @@
delegate_return_type
- 1214025
+ 1214014delegate_id
- 1214025
+ 1214014return_type_id
- 609581
+ 609575
@@ -12578,7 +12578,7 @@
12
- 1214025
+ 1214014
@@ -12594,12 +12594,12 @@
12
- 578365
+ 57835922134
- 31216
+ 31215
@@ -12677,15 +12677,15 @@
extend
- 3912749
+ 3912712sub
- 3912749
+ 3912712super
- 608567
+ 608561
@@ -12699,7 +12699,7 @@
12
- 3912749
+ 3912712
@@ -12715,12 +12715,12 @@
12
- 412779
+ 41277523
- 97451
+ 974503
@@ -12730,12 +12730,12 @@
5107
- 45654
+ 4565310731892
- 1447
+ 1446
@@ -12756,15 +12756,15 @@
implement
- 12929395
+ 12929274sub
- 4515705
+ 4515663super
- 2758958
+ 2758932
@@ -12778,32 +12778,32 @@
12
- 1532610
+ 153259523
- 1232578
+ 123256734
- 844694
+ 84468646
- 367567
+ 36756469
- 339011
+ 339008932
- 199243
+ 199241
@@ -12819,27 +12819,27 @@
12
- 1324507
+ 132449523
- 815340
+ 81533335
- 236392
+ 23639056
- 215396
+ 215394690747
- 167320
+ 167318
@@ -12849,11 +12849,11 @@
type_location
- 6161742
+ 6161685id
- 6071408
+ 6071351loc
@@ -12871,7 +12871,7 @@
12
- 6041080
+ 60410242
@@ -12952,15 +12952,15 @@
tuple_underlying_type
- 37858
+ 37857tuple
- 37858
+ 37857struct
- 37858
+ 37857
@@ -12974,7 +12974,7 @@
12
- 37858
+ 37857
@@ -12990,7 +12990,7 @@
12
- 37858
+ 37857
@@ -13000,7 +13000,7 @@
tuple_element
- 99961
+ 99960tuple
@@ -13012,7 +13012,7 @@
field
- 99961
+ 99960
@@ -13330,7 +13330,7 @@
12
- 99961
+ 99960
@@ -13346,7 +13346,7 @@
12
- 99961
+ 99960
@@ -13356,11 +13356,11 @@
attributes
- 14554229
+ 14554093id
- 14554229
+ 14554093kind
@@ -13372,7 +13372,7 @@
target
- 12720347
+ 12720228
@@ -13386,7 +13386,7 @@
12
- 14554229
+ 14554093
@@ -13402,7 +13402,7 @@
12
- 14554229
+ 14554093
@@ -13418,7 +13418,7 @@
12
- 14554229
+ 14554093
@@ -13542,7 +13542,7 @@
1423
- 1447
+ 144623
@@ -13552,7 +13552,7 @@
4086
- 1447
+ 144688
@@ -13659,7 +13659,7 @@
152380
- 1447
+ 1446385
@@ -13685,12 +13685,12 @@
12
- 11789749
+ 1178963823520
- 930598
+ 930589
@@ -13706,7 +13706,7 @@
12
- 12664594
+ 126644752
@@ -13727,12 +13727,12 @@
12
- 11960465
+ 11960353229
- 759882
+ 759875
@@ -13742,11 +13742,11 @@
attribute_location
- 14556089
+ 14555953id
- 14554229
+ 14554093loc
@@ -13764,7 +13764,7 @@
12
- 14552752
+ 145526162
@@ -13855,19 +13855,19 @@
type_mention
- 2667838
+ 2667808id
- 2667838
+ 2667808type_id
- 76163
+ 76156parent
- 2110780
+ 2110766
@@ -13881,7 +13881,7 @@
12
- 2667838
+ 2667808
@@ -13897,7 +13897,7 @@
12
- 2667838
+ 2667808
@@ -13913,17 +13913,17 @@
12
- 13028
+ 1302723
- 14823
+ 1482034
- 8378
+ 83774
@@ -13938,7 +13938,7 @@
67
- 5252
+ 52517
@@ -13953,17 +13953,17 @@
1636
- 5803
+ 580236
- 760
- 5714
+ 758
+ 5711
- 762
+ 75997094
- 360
+ 362
@@ -13979,12 +13979,12 @@
12
- 23361
+ 2335923
- 12267
+ 122643
@@ -13994,7 +13994,7 @@
45
- 6013
+ 60125
@@ -14009,7 +14009,7 @@
813
- 5964
+ 596313
@@ -14018,13 +14018,13 @@
30
- 609
- 5714
+ 607
+ 5711
- 612
- 73794
- 383
+ 608
+ 73798
+ 385
@@ -14040,17 +14040,17 @@
12
- 1801358
+ 180133923
- 219426
+ 2194083613
- 89995
+ 90019
@@ -14066,12 +14066,12 @@
12
- 2067454
+ 2067445238
- 43325
+ 43320
@@ -14081,15 +14081,15 @@
type_mention_location
- 2667838
+ 2667808id
- 2667838
+ 2667808loc
- 2358635
+ 2358655
@@ -14103,7 +14103,7 @@
12
- 2667838
+ 2667808
@@ -14119,12 +14119,12 @@
12
- 2217587
+ 22175922205
- 141048
+ 141062
@@ -14134,11 +14134,11 @@
type_annotation
- 1259639
+ 1259627id
- 1259639
+ 1259627annotation
@@ -14156,7 +14156,7 @@
12
- 1259639
+ 1259627
@@ -14551,15 +14551,15 @@
type_nullability
- 44405235
+ 44404820id
- 44402076
+ 44401660nullability
- 28113
+ 28112
@@ -14573,7 +14573,7 @@
12
- 44399034
+ 443986192
@@ -14594,7 +14594,7 @@
12
- 10129
+ 101282
@@ -14604,7 +14604,7 @@
34
- 2894
+ 28934
@@ -14644,11 +14644,11 @@
expr_flowstate
- 5429110
+ 5429197id
- 5429110
+ 5429197state
@@ -14666,7 +14666,7 @@
12
- 5429110
+ 5429197
@@ -14680,13 +14680,13 @@
12
- 223701
- 223702
+ 223736
+ 2237372
- 2337771
- 2337772
+ 2337938
+ 23379392
@@ -14697,11 +14697,11 @@
type_parameters
- 991372
+ 991363id
- 991372
+ 991363index
@@ -14709,7 +14709,7 @@
generic_id
- 758317
+ 758309variance
@@ -14727,7 +14727,7 @@
12
- 991372
+ 991363
@@ -14743,7 +14743,7 @@
12
- 991372
+ 991363
@@ -14759,7 +14759,7 @@
12
- 991372
+ 991363
@@ -14923,12 +14923,12 @@
12
- 592797
+ 59279223
- 137258
+ 1372573
@@ -14949,12 +14949,12 @@
12
- 592797
+ 59279223
- 137258
+ 1372573
@@ -14975,7 +14975,7 @@
12
- 757135
+ 7571282
@@ -15068,11 +15068,11 @@
type_arguments
- 24843956
+ 24843724id
- 789924
+ 789917index
@@ -15080,7 +15080,7 @@
constructed_id
- 2591723
+ 2591698
@@ -15094,17 +15094,17 @@
12
- 216091
+ 21608923
- 548605
+ 54860038
- 25228
+ 25227
@@ -15120,22 +15120,22 @@
12
- 82752
+ 8275123
- 587919
+ 587914310
- 61303
+ 61302103477
- 57949
+ 57948
@@ -15333,37 +15333,37 @@
12
- 408050
+ 40804723
- 1236259
+ 1236248319
- 213081
+ 2130791924
- 198798
+ 1987962428
- 230194
+ 2301922831
- 221032
+ 2210303133
- 84306
+ 84305
@@ -15379,37 +15379,37 @@
12
- 403306
+ 40330223
- 1238582
+ 1238571319
- 215502
+ 2155001924
- 198798
+ 1987962428
- 230194
+ 2301922831
- 221032
+ 2210303133
- 84306
+ 84305
@@ -15419,15 +15419,15 @@
constructed_generic
- 5258135
+ 5258085constructed
- 5258135
+ 5258085generic
- 108318
+ 108317
@@ -15441,7 +15441,7 @@
12
- 5258135
+ 5258085
@@ -15467,7 +15467,7 @@
34
- 10631
+ 106304
@@ -15497,7 +15497,7 @@
14919826
- 3396
+ 3395
@@ -15507,15 +15507,15 @@
type_parameter_constraints
- 991372
+ 991363id
- 991372
+ 991363param_id
- 991372
+ 991363
@@ -15529,7 +15529,7 @@
12
- 991372
+ 991363
@@ -15545,7 +15545,7 @@
12
- 991372
+ 991363
@@ -15591,11 +15591,11 @@
general_type_parameter_constraints
- 283258
+ 283256id
- 282033
+ 282031kind
@@ -15613,7 +15613,7 @@
12
- 280808
+ 2808062
@@ -15664,11 +15664,11 @@
specific_type_parameter_constraints
- 302127
+ 302125id
- 295217
+ 295214base_id
@@ -15686,7 +15686,7 @@
12
- 290167
+ 2901652
@@ -15707,7 +15707,7 @@
12
- 24776
+ 247752
@@ -15747,7 +15747,7 @@
specific_type_parameter_nullability
- 35626
+ 35625id
@@ -16134,11 +16134,11 @@
has_modifiers
- 100736682
+ 100735739id
- 66663238
+ 66662615mod_id
@@ -16156,17 +16156,17 @@
12
- 34234237
+ 3423391723
- 30788810
+ 3078852235
- 1640190
+ 1640174
@@ -16257,11 +16257,11 @@
compiler_generated
- 1278339
+ 1278327id
- 1278339
+ 1278327
@@ -16356,19 +16356,19 @@
nested_types
- 2161819
+ 2161798id
- 2161819
+ 2161798declaring_type_id
- 867580
+ 867572unbound_id
- 1812914
+ 1812897
@@ -16382,7 +16382,7 @@
12
- 2161819
+ 2161798
@@ -16398,7 +16398,7 @@
12
- 2161819
+ 2161798
@@ -16414,12 +16414,12 @@
12
- 507720
+ 50771523
- 151344
+ 1513433
@@ -16455,27 +16455,27 @@
12
- 509816
+ 50981223
- 152023
+ 15202234
- 71848
+ 7184746
- 65587
+ 65586626
- 65085
+ 6508426
@@ -16496,12 +16496,12 @@
12
- 1746795
+ 17467792490
- 66119
+ 66118
@@ -16517,7 +16517,7 @@
12
- 1757397
+ 17573802
@@ -16532,27 +16532,27 @@
properties
- 6642412
+ 6642350id
- 6642412
+ 6642350name
- 1540642
+ 1540628declaring_type_id
- 1854464
+ 1854447type_id
- 737232
+ 737225unbound_id
- 5942802
+ 5942747
@@ -16566,7 +16566,7 @@
12
- 6642412
+ 6642350
@@ -16582,7 +16582,7 @@
12
- 6642412
+ 6642350
@@ -16598,7 +16598,7 @@
12
- 6642412
+ 6642350
@@ -16614,7 +16614,7 @@
12
- 6642412
+ 6642350
@@ -16630,27 +16630,27 @@
12
- 972266
+ 97225723
- 248204
+ 24820234
- 95265
+ 9526448
- 124087
+ 12408688341
- 100817
+ 100816
@@ -16666,27 +16666,27 @@
12
- 972266
+ 97225723
- 248559
+ 24855634
- 95118
+ 9511748
- 124412
+ 12441184889
- 100286
+ 100285
@@ -16702,12 +16702,12 @@
12
- 1346951
+ 134693823
- 111448
+ 1114473
@@ -16728,12 +16728,12 @@
12
- 980741
+ 98073223
- 254051
+ 2540493
@@ -16743,12 +16743,12 @@
48
- 120130
+ 12012987118
- 90275
+ 90274
@@ -16764,37 +16764,37 @@
12
- 660127
+ 66012123
- 435281
+ 43527734
- 247023
+ 24702145
- 156837
+ 15683557
- 156010
+ 156008714
- 142130
+ 142129142090
- 57053
+ 57052
@@ -16810,37 +16810,37 @@
12
- 762392
+ 76238523
- 334641
+ 33463734
- 247407
+ 24740545
- 159435
+ 15943457
- 155951
+ 155949714
- 139916
+ 139914142090
- 54720
+ 54719
@@ -16856,27 +16856,27 @@
12
- 764990
+ 76498323
- 530281
+ 53027634
- 228389
+ 22838745
- 122552
+ 12255059
- 154563
+ 1545619
@@ -16897,37 +16897,37 @@
12
- 660127
+ 66012123
- 435281
+ 43527734
- 247023
+ 24702145
- 156837
+ 15683557
- 156010
+ 156008714
- 142130
+ 142129142090
- 57053
+ 57052
@@ -16943,17 +16943,17 @@
12
- 402738
+ 40273423
- 152023
+ 15202234
- 49375
+ 493744
@@ -16963,7 +16963,7 @@
732
- 55340
+ 5533932
@@ -16984,12 +16984,12 @@
12
- 589136
+ 58913023
- 82449
+ 824483
@@ -17015,12 +17015,12 @@
12
- 421756
+ 42175223
- 145733
+ 1457323
@@ -17035,7 +17035,7 @@
751
- 55399
+ 5539851
@@ -17056,12 +17056,12 @@
12
- 404923
+ 40492023
- 154268
+ 1542663
@@ -17071,12 +17071,12 @@
47
- 62575
+ 62574740
- 55399
+ 5539840
@@ -17097,12 +17097,12 @@
12
- 5841365
+ 584131021206
- 101437
+ 101436
@@ -17118,7 +17118,7 @@
12
- 5942802
+ 5942747
@@ -17134,12 +17134,12 @@
12
- 5841365
+ 584131021206
- 101437
+ 101436
@@ -17155,12 +17155,12 @@
12
- 5921038
+ 592098321206
- 21764
+ 21763
@@ -17170,15 +17170,15 @@
property_location
- 6657089
+ 6657027id
- 6642412
+ 6642350loc
- 10926
+ 10955
@@ -17192,7 +17192,7 @@
12
- 6631840
+ 66317782
@@ -17213,7 +17213,7 @@
15
- 885
+ 9155
@@ -17288,11 +17288,11 @@
indexers
- 105719
+ 105718id
- 105719
+ 105718name
@@ -17300,7 +17300,7 @@
declaring_type_id
- 92814
+ 92813type_id
@@ -17322,7 +17322,7 @@
12
- 105719
+ 105718
@@ -17338,7 +17338,7 @@
12
- 105719
+ 105718
@@ -17354,7 +17354,7 @@
12
- 105719
+ 105718
@@ -17370,7 +17370,7 @@
12
- 105719
+ 105718
@@ -17571,7 +17571,7 @@
12
- 92726
+ 927252
@@ -17592,7 +17592,7 @@
12
- 86731
+ 867302
@@ -17696,7 +17696,7 @@
12
- 14027
+ 140262
@@ -17826,7 +17826,7 @@
12
- 35968
+ 359672
@@ -17841,11 +17841,11 @@
indexer_location
- 106044
+ 106043id
- 105719
+ 105718loc
@@ -17863,7 +17863,7 @@
12
- 105394
+ 1053932
@@ -17934,11 +17934,11 @@
accessors
- 7915360
+ 7915286id
- 7915360
+ 7915286kind
@@ -17946,15 +17946,15 @@
name
- 2102196
+ 2102177declaring_member_id
- 6746921
+ 6746858unbound_id
- 7039570
+ 7039504
@@ -17968,7 +17968,7 @@
12
- 7915360
+ 7915286
@@ -17984,7 +17984,7 @@
12
- 7915360
+ 7915286
@@ -18000,7 +18000,7 @@
12
- 7915360
+ 7915286
@@ -18016,7 +18016,7 @@
12
- 7915360
+ 7915286
@@ -18116,27 +18116,27 @@
12
- 1367179
+ 136716623
- 330831
+ 33082835
- 191653
+ 191651517
- 160587
+ 160586173385
- 51944
+ 51943
@@ -18152,7 +18152,7 @@
12
- 2102196
+ 2102177
@@ -18168,27 +18168,27 @@
12
- 1367179
+ 136716623
- 330831
+ 33082835
- 191653
+ 191651517
- 160587
+ 160586173385
- 51944
+ 51943
@@ -18204,22 +18204,22 @@
12
- 1382003
+ 138199023
- 339690
+ 33968735
- 189616
+ 189614524
- 158786
+ 15878424
@@ -18240,12 +18240,12 @@
12
- 5578483
+ 557843123
- 1168438
+ 1168427
@@ -18261,12 +18261,12 @@
12
- 5578483
+ 557843123
- 1168438
+ 1168427
@@ -18282,12 +18282,12 @@
12
- 5578483
+ 557843123
- 1168438
+ 1168427
@@ -18303,12 +18303,12 @@
12
- 5578483
+ 557843123
- 1168438
+ 1168427
@@ -18324,12 +18324,12 @@
12
- 6919853
+ 691978821206
- 119717
+ 119716
@@ -18345,7 +18345,7 @@
12
- 7039570
+ 7039504
@@ -18361,7 +18361,7 @@
12
- 7039570
+ 7039504
@@ -18377,12 +18377,12 @@
12
- 6919853
+ 691978821206
- 119717
+ 119716
@@ -18403,15 +18403,15 @@
accessor_location
- 7933078
+ 7933004id
- 7915360
+ 7915286loc
- 10926
+ 10955
@@ -18425,7 +18425,7 @@
12
- 7901923
+ 79018492
@@ -18446,67 +18446,67 @@
16
- 885
+ 9446
- 12
+ 13
+ 974
+
+
+ 13
+ 26
+ 856
+
+
+ 26
+ 43826
- 12
- 22
+ 44
+ 68826
- 22
- 38
- 885
-
-
- 38
- 66
- 915
-
-
- 67
- 105
+ 68
+ 106826
- 105
- 161
+ 116
+ 167826
- 164
- 269
+ 168
+ 273
+ 856
+
+
+ 275
+ 373826
- 269
- 361
+ 373
+ 492826
- 364
- 464
+ 517
+ 1154826
- 477
- 1105
+ 1167
+ 2661826
- 1105
- 2387
- 826
-
-
- 2455
+ 285313984
- 797
+ 708
@@ -18528,7 +18528,7 @@
declaring_type_id
- 33842
+ 33841type_id
@@ -18536,7 +18536,7 @@
unbound_id
- 70637
+ 70636
@@ -18799,7 +18799,7 @@
34
- 3396
+ 33954
@@ -18953,7 +18953,7 @@
3262
- 1447
+ 1446
@@ -19015,7 +19015,7 @@
34
- 3396
+ 33954
@@ -19041,7 +19041,7 @@
12
- 68127
+ 681262
@@ -19062,7 +19062,7 @@
12
- 70637
+ 70636
@@ -19078,7 +19078,7 @@
12
- 68127
+ 681262
@@ -19207,11 +19207,11 @@
event_accessors
- 160823
+ 160822id
- 160823
+ 160822kind
@@ -19219,7 +19219,7 @@
name
- 68688
+ 68687declaring_event_id
@@ -19227,7 +19227,7 @@
unbound_id
- 141274
+ 141273
@@ -19241,7 +19241,7 @@
12
- 160823
+ 160822
@@ -19257,7 +19257,7 @@
12
- 160823
+ 160822
@@ -19273,7 +19273,7 @@
12
- 160823
+ 160822
@@ -19289,7 +19289,7 @@
12
- 160823
+ 160822
@@ -19405,7 +19405,7 @@
12
- 68688
+ 68687
@@ -19557,7 +19557,7 @@
12
- 136254
+ 1362532
@@ -19578,7 +19578,7 @@
12
- 141274
+ 141273
@@ -19594,7 +19594,7 @@
12
- 141274
+ 141273
@@ -19610,7 +19610,7 @@
12
- 136254
+ 1362532
@@ -19625,11 +19625,11 @@
event_accessor_location
- 160823
+ 160822id
- 160823
+ 160822loc
@@ -19647,7 +19647,7 @@
12
- 160823
+ 160822
@@ -19718,11 +19718,11 @@
operators
- 629721
+ 629715id
- 629721
+ 629715name
@@ -19734,11 +19734,11 @@
declaring_type_id
- 75488
+ 75487type_id
- 30578
+ 30577unbound_id
@@ -19756,7 +19756,7 @@
12
- 629721
+ 629715
@@ -19772,7 +19772,7 @@
12
- 629721
+ 629715
@@ -19788,7 +19788,7 @@
12
- 629721
+ 629715
@@ -19804,7 +19804,7 @@
12
- 629721
+ 629715
@@ -19820,7 +19820,7 @@
12
- 629721
+ 629715
@@ -20451,7 +20451,7 @@
716
- 5808
+ 580716
@@ -20560,7 +20560,7 @@
716
- 5808
+ 580716
@@ -20821,7 +20821,7 @@
12
- 66686
+ 666852
@@ -20879,7 +20879,7 @@
12
- 66686
+ 666852
@@ -20925,15 +20925,15 @@
operator_location
- 1210557
+ 1210545id
- 586251
+ 586245loc
- 10667
+ 10683
@@ -20952,12 +20952,12 @@
23
- 567174
+ 56716937
- 15248
+ 15247
@@ -20993,7 +20993,7 @@
3950
- 916
+ 89952
@@ -21018,7 +21018,7 @@
7983
- 850
+ 86785
@@ -21033,12 +21033,12 @@
97279
- 801
+ 834
- 345
- 17300
- 65
+ 664
+ 17251
+ 49
@@ -21048,15 +21048,15 @@
constant_value
- 3875422
+ 3875386id
- 3873680
+ 3873643value
- 1314319
+ 1314307
@@ -21070,7 +21070,7 @@
12
- 3872528
+ 38724922
@@ -21091,17 +21091,17 @@
12
- 1062512
+ 106250223
- 130820
+ 130819310
- 101821
+ 10182010
@@ -21116,27 +21116,27 @@
methods
- 20454980
+ 20454789id
- 20454980
+ 20454789name
- 5761337
+ 5761283declaring_type_id
- 4275208
+ 4275168type_id
- 1360564
+ 1360551unbound_id
- 16901323
+ 16901165
@@ -21150,7 +21150,7 @@
12
- 20454980
+ 20454789
@@ -21166,7 +21166,7 @@
12
- 20454980
+ 20454789
@@ -21182,7 +21182,7 @@
12
- 20454980
+ 20454789
@@ -21198,7 +21198,7 @@
12
- 20454980
+ 20454789
@@ -21214,22 +21214,22 @@
12
- 4128352
+ 412831323
- 674804
+ 67479835
- 458551
+ 458547526
- 434749
+ 43474526
@@ -21250,22 +21250,22 @@
12
- 4308282
+ 430824223
- 587629
+ 58762436
- 515220
+ 515216610142
- 350203
+ 350200
@@ -21281,17 +21281,17 @@
12
- 5249541
+ 524949227
- 440360
+ 44035672905
- 71434
+ 71433
@@ -21307,22 +21307,22 @@
12
- 4191695
+ 419165623
- 694589
+ 69458335
- 457960
+ 45795658458
- 417090
+ 417086
@@ -21338,42 +21338,42 @@
12
- 1491562
+ 149154823
- 954902
+ 95489334
- 425388
+ 42538445
- 301773
+ 30177056
- 243096
+ 24309369
- 373828
+ 373824918
- 328971
+ 328968188066
- 155685
+ 155684
@@ -21389,37 +21389,37 @@
12
- 1548261
+ 154824623
- 987947
+ 98793734
- 436728
+ 43672445
- 342466
+ 34246356
- 264771
+ 264769610
- 361484
+ 3614811070
- 320850
+ 32084770
@@ -21440,32 +21440,32 @@
12
- 2042987
+ 204296823
- 1046683
+ 104667334
- 428371
+ 42836745
- 350735
+ 350731510
- 321559
+ 32155610848
- 84871
+ 84870
@@ -21481,42 +21481,42 @@
12
- 1491592
+ 149157823
- 954872
+ 95486334
- 425388
+ 42538445
- 301773
+ 30177056
- 243096
+ 24309369
- 373828
+ 373824918
- 328971
+ 328968188066
- 155685
+ 155684
@@ -21532,32 +21532,32 @@
12
- 771576
+ 77156923
- 224580
+ 22457834
- 98868
+ 9886747
- 120691
+ 120690723
- 102766
+ 10276523192615
- 42081
+ 42080
@@ -21573,22 +21573,22 @@
12
- 948848
+ 94883923
- 179546
+ 17954435
- 116380
+ 116379527
- 102235
+ 10223427
@@ -21609,22 +21609,22 @@
12
- 883290
+ 88328223
- 215160
+ 21515834
- 88798
+ 8879749
- 108554
+ 1085539
@@ -21645,22 +21645,22 @@
12
- 774322
+ 77431523
- 226381
+ 22637934
- 99163
+ 9916247
- 121607
+ 1216057
@@ -21670,7 +21670,7 @@
24167300
- 36913
+ 36912
@@ -21686,12 +21686,12 @@
12
- 16368679
+ 1636852623017
- 532643
+ 532638
@@ -21707,7 +21707,7 @@
12
- 16901323
+ 16901165
@@ -21723,12 +21723,12 @@
12
- 16368797
+ 1636864423017
- 532525
+ 532520
@@ -21744,12 +21744,12 @@
12
- 16731877
+ 1673172021636
- 169446
+ 169445
@@ -21759,11 +21759,11 @@
method_location
- 20553553
+ 20553361id
- 20454980
+ 20454789loc
@@ -21781,7 +21781,7 @@
12
- 20387030
+ 203868392
@@ -21872,23 +21872,23 @@
constructors
- 5991233
+ 5991176id
- 5991233
+ 5991176name
- 2792770
+ 2792744declaring_type_id
- 4484787
+ 4484745unbound_id
- 5562625
+ 5562573
@@ -21902,7 +21902,7 @@
12
- 5991233
+ 5991176
@@ -21918,7 +21918,7 @@
12
- 5991233
+ 5991176
@@ -21934,7 +21934,7 @@
12
- 5991233
+ 5991176
@@ -21950,17 +21950,17 @@
12
- 2023704
+ 202368523
- 507720
+ 50771537
- 213388
+ 2133867
@@ -21981,17 +21981,17 @@
12
- 2556289
+ 255626526
- 210435
+ 210433611806
- 26046
+ 26045
@@ -22007,17 +22007,17 @@
12
- 2053914
+ 205389523
- 509344
+ 509339310
- 211291
+ 21128910
@@ -22038,17 +22038,17 @@
12
- 3341745
+ 334171323
- 968752
+ 968743355
- 174289
+ 174288
@@ -22064,7 +22064,7 @@
12
- 4484787
+ 4484745
@@ -22080,17 +22080,17 @@
12
- 3341745
+ 334171323
- 968752
+ 968743355
- 174289
+ 174288
@@ -22106,7 +22106,7 @@
12
- 5506044
+ 55059932
@@ -22127,7 +22127,7 @@
12
- 5562625
+ 5562573
@@ -22143,7 +22143,7 @@
12
- 5506044
+ 55059932
@@ -22158,11 +22158,11 @@
constructor_location
- 6040667
+ 6040610id
- 5991233
+ 5991176loc
@@ -22180,7 +22180,7 @@
12
- 5971329
+ 59712732
@@ -22534,7 +22534,7 @@
12
- 6290
+ 62892
@@ -22590,15 +22590,15 @@
overrides
- 4832155
+ 4832110id
- 4832155
+ 4832110base_id
- 1569700
+ 1569685
@@ -22612,7 +22612,7 @@
12
- 4832155
+ 4832110
@@ -22628,22 +22628,22 @@
12
- 1071371
+ 107136123
- 247171
+ 24716935
- 127336
+ 127334544
- 117738
+ 11773744
@@ -22658,15 +22658,15 @@
explicitly_implements
- 1824372
+ 1824355id
- 1823811
+ 1823794interface_id
- 134836
+ 134835
@@ -22680,7 +22680,7 @@
12
- 1823250
+ 18232332
@@ -22701,7 +22701,7 @@
12
- 69072
+ 690712
@@ -22721,12 +22721,12 @@
610
- 10188
+ 101871035
- 10188
+ 1018735
@@ -23085,11 +23085,11 @@
fields
- 14976517
+ 14976377id
- 14976517
+ 14976377kind
@@ -23097,19 +23097,19 @@
name
- 6219416
+ 6219358declaring_type_id
- 3386631
+ 3386599type_id
- 2968123
+ 2968095unbound_id
- 14485511
+ 14485376
@@ -23123,7 +23123,7 @@
12
- 14976517
+ 14976377
@@ -23139,7 +23139,7 @@
12
- 14976517
+ 14976377
@@ -23155,7 +23155,7 @@
12
- 14976517
+ 14976377
@@ -23171,7 +23171,7 @@
12
- 14976517
+ 14976377
@@ -23187,7 +23187,7 @@
12
- 14976517
+ 14976377
@@ -23308,22 +23308,22 @@
12
- 4898363
+ 489831723
- 694826
+ 69481938
- 467558
+ 467554812308
- 158668
+ 158666
@@ -23339,12 +23339,12 @@
12
- 6076724
+ 607666723
- 142691
+ 142690
@@ -23360,22 +23360,22 @@
12
- 4898363
+ 489831723
- 694855
+ 69484938
- 467528
+ 467524812308
- 158668
+ 158666
@@ -23391,17 +23391,17 @@
12
- 5453627
+ 545357623
- 467587
+ 467583312308
- 298200
+ 298197
@@ -23417,22 +23417,22 @@
12
- 4931319
+ 493127323
- 696538
+ 696532310
- 479636
+ 4796311012308
- 111921
+ 111920
@@ -23448,42 +23448,42 @@
12
- 934142
+ 93413323
- 866074
+ 86606634
- 480847
+ 48084245
- 296428
+ 29642556
- 198859
+ 19885768
- 247466
+ 247464815
- 263619
+ 263617156823
- 99193
+ 99192
@@ -23499,12 +23499,12 @@
12
- 3183076
+ 318304723
- 203554
+ 203552
@@ -23520,42 +23520,42 @@
12
- 934142
+ 93413323
- 866103
+ 86609534
- 480817
+ 48081345
- 296428
+ 29642556
- 198859
+ 19885768
- 247466
+ 247464815
- 263619
+ 263617156823
- 99193
+ 99192
@@ -23571,32 +23571,32 @@
12
- 1290399
+ 129038723
- 940550
+ 94054134
- 442309
+ 44230545
- 234473
+ 23447058
- 310957
+ 3109548524
- 167940
+ 167939
@@ -23612,42 +23612,42 @@
12
- 934142
+ 93413323
- 866074
+ 86606634
- 480847
+ 48084245
- 296428
+ 29642556
- 198859
+ 19885768
- 247466
+ 247464815
- 263619
+ 263617156823
- 99193
+ 99192
@@ -23663,22 +23663,22 @@
12
- 2017945
+ 201792723
- 365766
+ 36576235
- 273335
+ 273332514
- 225436
+ 22543414
@@ -23699,12 +23699,12 @@
12
- 2881953
+ 288192623
- 86170
+ 86169
@@ -23720,22 +23720,22 @@
12
- 2161080
+ 216106023
- 352477
+ 35247435
- 233675
+ 233673533041
- 220889
+ 220887
@@ -23751,22 +23751,22 @@
12
- 2240193
+ 224017223
- 357172
+ 35716936
- 229600
+ 229598619141
- 141156
+ 141155
@@ -23782,27 +23782,27 @@
12
- 2022907
+ 202288823
- 368453
+ 36845035
- 271356
+ 271354515
- 228626
+ 2286231556593
- 76779
+ 76778
@@ -23818,12 +23818,12 @@
12
- 14401378
+ 1440124421016
- 84132
+ 84131
@@ -23839,7 +23839,7 @@
12
- 14485511
+ 14485376
@@ -23855,7 +23855,7 @@
12
- 14485511
+ 14485376
@@ -23871,12 +23871,12 @@
12
- 14401378
+ 1440124421016
- 84132
+ 84131
@@ -23892,7 +23892,7 @@
12
- 14459317
+ 144591822
@@ -23907,11 +23907,11 @@
field_location
- 14965266
+ 14965126id
- 14877383
+ 14877243loc
@@ -23929,12 +23929,12 @@
12
- 14824434
+ 14824296222
- 52948
+ 52947
@@ -24025,11 +24025,11 @@
localvars
- 499216
+ 499212id
- 499216
+ 499212kind
@@ -24037,7 +24037,7 @@
name
- 91306
+ 91305implicitly_typed
@@ -24049,7 +24049,7 @@
parent_id
- 499216
+ 499212
@@ -24063,7 +24063,7 @@
12
- 499216
+ 499212
@@ -24079,7 +24079,7 @@
12
- 499216
+ 499212
@@ -24095,7 +24095,7 @@
12
- 499216
+ 499212
@@ -24111,7 +24111,7 @@
12
- 499216
+ 499212
@@ -24127,7 +24127,7 @@
12
- 499216
+ 499212
@@ -24248,7 +24248,7 @@
12
- 57798
+ 577972
@@ -24284,7 +24284,7 @@
12
- 91122
+ 911212
@@ -24326,7 +24326,7 @@
12
- 78906
+ 789052
@@ -24352,7 +24352,7 @@
12
- 57798
+ 577972
@@ -24601,7 +24601,7 @@
12
- 18824
+ 188232
@@ -24668,7 +24668,7 @@
12
- 499216
+ 499212
@@ -24684,7 +24684,7 @@
12
- 499216
+ 499212
@@ -24700,7 +24700,7 @@
12
- 499216
+ 499212
@@ -24716,7 +24716,7 @@
12
- 499216
+ 499212
@@ -24732,7 +24732,7 @@
12
- 499216
+ 499212
@@ -24742,15 +24742,15 @@
localvar_location
- 499216
+ 499212id
- 499216
+ 499212loc
- 499216
+ 499212
@@ -24764,7 +24764,7 @@
12
- 499216
+ 499212
@@ -24780,7 +24780,7 @@
12
- 499216
+ 499212
@@ -24790,19 +24790,19 @@
params
- 37386455
+ 37386105id
- 37386455
+ 37386105name
- 2196576
+ 2196556type_id
- 2827941
+ 2827915index
@@ -24814,11 +24814,11 @@
parent_id
- 20722350
+ 20722157unbound_id
- 30114153
+ 30113872
@@ -24832,7 +24832,7 @@
12
- 37386455
+ 37386105
@@ -24848,7 +24848,7 @@
12
- 37386455
+ 37386105
@@ -24864,7 +24864,7 @@
12
- 37386455
+ 37386105
@@ -24880,7 +24880,7 @@
12
- 37386455
+ 37386105
@@ -24896,7 +24896,7 @@
12
- 37386455
+ 37386105
@@ -24912,7 +24912,7 @@
12
- 37386455
+ 37386105
@@ -24928,37 +24928,37 @@
12
- 981598
+ 98158823
- 381535
+ 38153234
- 185481
+ 18548046
- 196585
+ 196583610
- 173876
+ 1738741025
- 165666
+ 1656652574292
- 111832
+ 111831
@@ -24974,22 +24974,22 @@
12
- 1784417
+ 178440123
- 214156
+ 214154313
- 166995
+ 1669941313366
- 31007
+ 31006
@@ -25005,22 +25005,22 @@
12
- 1518996
+ 151898223
- 374596
+ 37459234
- 146294
+ 146293421
- 156689
+ 156688
@@ -25036,12 +25036,12 @@
12
- 2031234
+ 203121526
- 164928
+ 1649276
@@ -25062,37 +25062,37 @@
12
- 981598
+ 98158823
- 381535
+ 38153234
- 185481
+ 18548046
- 196585
+ 196583610
- 173876
+ 1738741025
- 165666
+ 1656652574292
- 111832
+ 111831
@@ -25108,37 +25108,37 @@
12
- 1002151
+ 100214223
- 388504
+ 38850134
- 199951
+ 19995046
- 201103
+ 201101610
- 166050
+ 1660491035
- 166670
+ 1666693563585
- 72143
+ 72142
@@ -25154,37 +25154,37 @@
12
- 1386197
+ 138618423
- 410623
+ 41061934
- 235861
+ 23585845
- 175736
+ 17573558
- 215278
+ 215276819
- 219383
+ 2193801990397
- 184861
+ 184860
@@ -25200,22 +25200,22 @@
12
- 1901536
+ 190151823
- 477539
+ 47753534
- 203436
+ 203434413
- 212650
+ 21264813
@@ -25236,22 +25236,22 @@
12
- 2062921
+ 206290123
- 482589
+ 48258536
- 239670
+ 239668654
- 42760
+ 42759
@@ -25267,12 +25267,12 @@
12
- 2663278
+ 266325326
- 164662
+ 164661
@@ -25288,37 +25288,37 @@
12
- 1428366
+ 142835323
- 383720
+ 38371734
- 237012
+ 23701045
- 173403
+ 17340259
- 247850
+ 247848924
- 214362
+ 2143602474138
- 143223
+ 143222
@@ -25334,37 +25334,37 @@
12
- 1394672
+ 139465923
- 412158
+ 41215534
- 252280
+ 25227745
- 174703
+ 17470158
- 225377
+ 225375819
- 214185
+ 2141831984336
- 154563
+ 154561
@@ -25972,27 +25972,27 @@
12
- 11717399
+ 1171728923
- 5233890
+ 523384134
- 2032032
+ 203201348
- 1570586
+ 1570571856
- 168442
+ 168441
@@ -26008,27 +26008,27 @@
12
- 11717369
+ 1171725923
- 5233890
+ 523384134
- 2032032
+ 203201348
- 1570616
+ 1570601856
- 168442
+ 168441
@@ -26044,22 +26044,22 @@
12
- 12389722
+ 1238960723
- 5150023
+ 514997534
- 1884349
+ 1884331443
- 1298255
+ 1298242
@@ -26075,27 +26075,27 @@
12
- 11717399
+ 1171728923
- 5233890
+ 523384134
- 2032032
+ 203201348
- 1570586
+ 1570571856
- 168442
+ 168441
@@ -26111,12 +26111,12 @@
12
- 19796358
+ 1979617325
- 925991
+ 925983
@@ -26132,27 +26132,27 @@
12
- 11717399
+ 1171728923
- 5233890
+ 523384134
- 2032032
+ 203201348
- 1570586
+ 1570571856
- 168442
+ 168441
@@ -26168,12 +26168,12 @@
12
- 29105919
+ 29105646217584
- 1008234
+ 1008225
@@ -26189,7 +26189,7 @@
12
- 30114065
+ 301137832
@@ -26210,12 +26210,12 @@
12
- 29808925
+ 2980864629835
- 305228
+ 305225
@@ -26231,7 +26231,7 @@
12
- 30114153
+ 30113872
@@ -26247,7 +26247,7 @@
12
- 30114153
+ 30113872
@@ -26263,12 +26263,12 @@
12
- 29105919
+ 29105646217584
- 1008234
+ 1008225
@@ -26278,11 +26278,11 @@
param_location
- 37558973
+ 37558621id
- 37386071
+ 37385721loc
@@ -26300,12 +26300,12 @@
12
- 37269041
+ 37268692270
- 117029
+ 117028
@@ -26391,11 +26391,11 @@
statements
- 2457863
+ 2457840id
- 2457863
+ 2457840kind
@@ -26413,7 +26413,7 @@
12
- 2457863
+ 2457840
@@ -26509,11 +26509,11 @@
stmt_parent
- 2097112
+ 2097092stmt
- 2097112
+ 2097092index
@@ -26521,7 +26521,7 @@
parent
- 1004054
+ 1004045
@@ -26535,7 +26535,7 @@
12
- 2097112
+ 2097092
@@ -26551,7 +26551,7 @@
12
- 2097112
+ 2097092
@@ -26679,27 +26679,27 @@
12
- 647155
+ 64714923
- 190657
+ 19065634
- 62747
+ 6274649
- 80168
+ 8016793407
- 23326
+ 23325
@@ -26715,27 +26715,27 @@
12
- 647155
+ 64714923
- 190657
+ 19065634
- 62747
+ 6274649
- 80168
+ 8016793407
- 23326
+ 23325
@@ -26745,11 +26745,11 @@
stmt_parent_top_level
- 360750
+ 360747stmt
- 360750
+ 360747index
@@ -26757,7 +26757,7 @@
parent
- 340705
+ 340702
@@ -26771,7 +26771,7 @@
12
- 360750
+ 360747
@@ -26787,7 +26787,7 @@
12
- 360750
+ 360747
@@ -26835,12 +26835,12 @@
12
- 322204
+ 32220125
- 18501
+ 18500
@@ -26856,7 +26856,7 @@
12
- 340705
+ 340702
@@ -26866,15 +26866,15 @@
stmt_location
- 2457857
+ 2457834id
- 2457857
+ 2457834loc
- 2376792
+ 2376770
@@ -26888,7 +26888,7 @@
12
- 2457857
+ 2457834
@@ -26904,7 +26904,7 @@
12
- 2300098
+ 23000762
@@ -27138,7 +27138,7 @@
foreach_stmt_desugar
- 133866
+ 133865id
@@ -27319,11 +27319,11 @@
expressions
- 9729220
+ 9729129id
- 9729220
+ 9729129kind
@@ -27345,7 +27345,7 @@
12
- 9729220
+ 9729129
@@ -27361,7 +27361,7 @@
12
- 9729220
+ 9729129
@@ -27570,7 +27570,7 @@
12
- 33100
+ 330992
@@ -27610,19 +27610,19 @@
expr_parent
- 9420716
+ 9420628expr
- 9420716
+ 9420628index
- 32816
+ 32815parent
- 6308266
+ 6308207
@@ -27636,7 +27636,7 @@
12
- 9420716
+ 9420628
@@ -27652,7 +27652,7 @@
12
- 9420716
+ 9420628
@@ -27673,7 +27673,7 @@
45
- 17079
+ 170785
@@ -27719,7 +27719,7 @@
45
- 17079
+ 170785
@@ -27760,17 +27760,17 @@
12
- 4096813
+ 409677423
- 1896471
+ 1896453322534
- 314982
+ 314979
@@ -27786,17 +27786,17 @@
12
- 4096813
+ 409677423
- 1896471
+ 1896453322534
- 314982
+ 314979
@@ -27806,11 +27806,11 @@
expr_parent_top_level
- 5483306
+ 5483254expr
- 5483306
+ 5483254index
@@ -27818,7 +27818,7 @@
parent
- 3999864
+ 3999827
@@ -27832,7 +27832,7 @@
12
- 5483306
+ 5483254
@@ -27848,7 +27848,7 @@
12
- 5483306
+ 5483254
@@ -28006,17 +28006,17 @@
12
- 3335573
+ 333554123
- 383809
+ 383805314
- 280481
+ 280479
@@ -28032,17 +28032,17 @@
12
- 3339559
+ 333952823
- 380649
+ 380646312
- 279655
+ 279652
@@ -28149,26 +28149,26 @@
expr_compiler_generated
- 9719652
+ 9719561id
- 9719652
+ 9719561expr_value
- 6749402
+ 6749339id
- 6749402
+ 6749339value
- 838197
+ 838189
@@ -28182,7 +28182,7 @@
12
- 6749402
+ 6749339
@@ -28198,17 +28198,17 @@
12
- 578711
+ 57870623
- 137760
+ 13775934
- 66857
+ 668564
@@ -28223,15 +28223,15 @@
expr_call
- 1585560
+ 1585545caller_id
- 1585560
+ 1585545target_id
- 207402
+ 207400
@@ -28245,7 +28245,7 @@
12
- 1585560
+ 1585545
@@ -28261,17 +28261,17 @@
12
- 110904
+ 11090323
- 41217
+ 4121834
- 15565
+ 155634
@@ -28296,15 +28296,15 @@
expr_access
- 3615705
+ 3615672accesser_id
- 3615705
+ 3615672target_id
- 874845
+ 874837
@@ -28318,7 +28318,7 @@
12
- 3615705
+ 3615672
@@ -28334,32 +28334,32 @@
12
- 292104
+ 29210123
- 190758
+ 19075634
- 134524
+ 13452345
- 82548
+ 8254757
- 80286
+ 80285715
- 68016
+ 6801515
@@ -28374,15 +28374,15 @@
expr_location
- 9729220
+ 9729129id
- 9729220
+ 9729129loc
- 7546334
+ 7546264
@@ -28396,7 +28396,7 @@
12
- 9729220
+ 9729129
@@ -28412,17 +28412,17 @@
12
- 6528710
+ 652864823
- 981628
+ 98161939211
- 35996
+ 35995
@@ -28584,11 +28584,11 @@
expr_argument_name
- 731798
+ 731791id
- 731798
+ 731791name
@@ -28606,7 +28606,7 @@
12
- 731798
+ 731791
@@ -29256,11 +29256,11 @@
xmlElements
- 60596893
+ 60596686id
- 60596893
+ 60596686name
@@ -29268,7 +29268,7 @@
parentid
- 24508816
+ 24508733idx
@@ -29290,7 +29290,7 @@
12
- 60596893
+ 60596686
@@ -29306,7 +29306,7 @@
12
- 60596893
+ 60596686
@@ -29322,7 +29322,7 @@
12
- 60596893
+ 60596686
@@ -29338,7 +29338,7 @@
12
- 60596893
+ 60596686
@@ -29528,27 +29528,27 @@
12
- 14236583
+ 1423653423
- 4770003
+ 476998734
- 2178795
+ 217878746
- 2111342
+ 2111335617196
- 1212092
+ 1212088
@@ -29564,22 +29564,22 @@
12
- 16928804
+ 1692874723
- 4145902
+ 414588834
- 2094945
+ 20949384125
- 1339163
+ 1339158
@@ -29595,27 +29595,27 @@
12
- 14236583
+ 1423653423
- 4770003
+ 476998734
- 2178795
+ 217878746
- 2111342
+ 2111335617196
- 1212092
+ 1212088
@@ -29631,7 +29631,7 @@
12
- 24508816
+ 24508733
@@ -30219,15 +30219,15 @@
xmlAttrs
- 41517960
+ 41517819id
- 41517960
+ 41517819elementid
- 41169454
+ 41169314name
@@ -30235,7 +30235,7 @@
value
- 884047
+ 884044idx
@@ -30257,7 +30257,7 @@
12
- 41517960
+ 41517819
@@ -30273,7 +30273,7 @@
12
- 41517960
+ 41517819
@@ -30289,7 +30289,7 @@
12
- 41517960
+ 41517819
@@ -30305,7 +30305,7 @@
12
- 41517960
+ 41517819
@@ -30321,7 +30321,7 @@
12
- 41517960
+ 41517819
@@ -30337,7 +30337,7 @@
12
- 40983430
+ 409832902
@@ -30358,7 +30358,7 @@
12
- 40983430
+ 409832902
@@ -30379,12 +30379,12 @@
12
- 40983630
+ 40983491213
- 185823
+ 185822
@@ -30400,7 +30400,7 @@
12
- 40983430
+ 409832902
@@ -30421,7 +30421,7 @@
12
- 41169454
+ 41169314
@@ -30722,7 +30722,7 @@
23
- 308689
+ 3086883
@@ -30747,12 +30747,12 @@
813
- 75195
+ 751941329
- 70437
+ 7043629
@@ -30783,7 +30783,7 @@
23
- 308696
+ 3086953
@@ -30793,12 +30793,12 @@
45
- 76925
+ 7692456
- 38840
+ 388396
@@ -30823,7 +30823,7 @@
150471089
- 33754
+ 33753
@@ -30839,7 +30839,7 @@
12
- 781511
+ 7815092
@@ -30865,7 +30865,7 @@
12
- 882313
+ 8823102
@@ -30891,7 +30891,7 @@
23
- 365376
+ 3653753
@@ -30921,7 +30921,7 @@
28159
- 69846
+ 69845159
@@ -31469,7 +31469,7 @@
23
- 20057
+ 200563
@@ -31489,7 +31489,7 @@
671
- 3414
+ 3413
@@ -32002,11 +32002,11 @@
xmlHasNs
- 501577
+ 501573elementId
- 501577
+ 501573nsId
@@ -32028,7 +32028,7 @@
12
- 501577
+ 501573
@@ -32044,7 +32044,7 @@
12
- 501577
+ 501573
@@ -32524,19 +32524,19 @@
xmlChars
- 45379511
+ 45379357id
- 45379511
+ 45379357text
- 1700662
+ 1700656parentid
- 28480349
+ 28480252idx
@@ -32562,7 +32562,7 @@
12
- 45379511
+ 45379357
@@ -32578,7 +32578,7 @@
12
- 45379511
+ 45379357
@@ -32594,7 +32594,7 @@
12
- 45379511
+ 45379357
@@ -32610,7 +32610,7 @@
12
- 45379511
+ 45379357
@@ -32626,7 +32626,7 @@
12
- 45379511
+ 45379357
@@ -32647,7 +32647,7 @@
23
- 421882
+ 4218813
@@ -32667,12 +32667,12 @@
68
- 141441
+ 14144089
- 87852
+ 878519
@@ -32682,7 +32682,7 @@
1215
- 83186
+ 8318515
@@ -32713,12 +32713,12 @@
12
- 165834
+ 16583323
- 421942
+ 4219413
@@ -32728,7 +32728,7 @@
45
- 175866
+ 1758655
@@ -32748,7 +32748,7 @@
912
- 148677
+ 14867612
@@ -32763,12 +32763,12 @@
1954
- 127684
+ 12768354918936
- 93732
+ 93731
@@ -32784,12 +32784,12 @@
12
- 1668609
+ 1668603233
- 32053
+ 32052
@@ -32805,7 +32805,7 @@
12
- 1700660
+ 17006542
@@ -32831,12 +32831,12 @@
23
- 498940
+ 49893834
- 94931
+ 949304
@@ -32851,12 +32851,12 @@
68
- 145526
+ 145525810
- 153688
+ 15368710
@@ -32871,7 +32871,7 @@
1714127
- 118981
+ 118980
@@ -32887,22 +32887,22 @@
12
- 17038280
+ 1703822223
- 8292992
+ 829296434
- 2084035
+ 2084028461
- 1065041
+ 1065037
@@ -32918,22 +32918,22 @@
12
- 17040164
+ 1704010623
- 8301726
+ 830169834
- 2100188
+ 2100181447
- 1038269
+ 1038266
@@ -32949,22 +32949,22 @@
12
- 17038280
+ 1703822223
- 8292992
+ 829296434
- 2084035
+ 2084028461
- 1065041
+ 1065037
@@ -32980,7 +32980,7 @@
12
- 28479968
+ 284798712
@@ -33001,7 +33001,7 @@
12
- 28480349
+ 28480252
@@ -33696,15 +33696,15 @@
xmllocations
- 147551916
+ 147551414xmlElement
- 147546832
+ 147546330location
- 128989681
+ 128989242
@@ -33718,7 +33718,7 @@
12
- 147546786
+ 1475462842
@@ -33739,17 +33739,17 @@
12
- 110766476
+ 11076610023
- 18041929
+ 18041868315
- 181275
+ 181274
@@ -33759,11 +33759,11 @@
commentline
- 1542316
+ 1542302id
- 1542316
+ 1542302kind
@@ -33771,11 +33771,11 @@
text
- 576331
+ 576326rawtext
- 581672
+ 581666
@@ -33789,7 +33789,7 @@
12
- 1542316
+ 1542302
@@ -33805,7 +33805,7 @@
12
- 1542316
+ 1542302
@@ -33821,7 +33821,7 @@
12
- 1542316
+ 1542302
@@ -33915,7 +33915,7 @@
12
- 482114
+ 4821102
@@ -33925,7 +33925,7 @@
321079
- 40791
+ 40790
@@ -33941,7 +33941,7 @@
12
- 574463
+ 5744582
@@ -33962,12 +33962,12 @@
12
- 572802
+ 572797240
- 3529
+ 3528
@@ -33983,12 +33983,12 @@
12
- 487842
+ 48783723
- 52897
+ 528963
@@ -34009,7 +34009,7 @@
12
- 581672
+ 581666
@@ -34025,7 +34025,7 @@
12
- 581672
+ 581666
@@ -34035,15 +34035,15 @@
commentline_location
- 1542316
+ 1542302id
- 1542316
+ 1542302loc
- 1542316
+ 1542302
@@ -34057,7 +34057,7 @@
12
- 1542316
+ 1542302
@@ -34073,7 +34073,7 @@
12
- 1542316
+ 1542302
@@ -34083,26 +34083,26 @@
commentblock
- 374970
+ 374967id
- 374970
+ 374967commentblock_location
- 374970
+ 374967id
- 374970
+ 374967loc
- 374970
+ 374967
@@ -34116,7 +34116,7 @@
12
- 374970
+ 374967
@@ -34132,7 +34132,7 @@
12
- 374970
+ 374967
@@ -34142,15 +34142,15 @@
commentblock_binding
- 1356034
+ 1356021id
- 374970
+ 374967entity
- 587088
+ 587083bindtype
@@ -34173,12 +34173,12 @@
23
- 86989
+ 8698834
- 264873
+ 264871
@@ -34194,17 +34194,17 @@
13
- 23382
+ 2338134
- 86715
+ 8671445
- 264873
+ 264871
@@ -34220,17 +34220,17 @@
12
- 415337
+ 41533323
- 139839
+ 1398373524
- 31912
+ 31911
@@ -34246,17 +34246,17 @@
12
- 222402
+ 22240023
- 230404
+ 23040234
- 124694
+ 1246934
@@ -34333,15 +34333,15 @@
commentblock_child
- 1901595
+ 1901577id
- 374970
+ 374967commentline
- 1541684
+ 1541669index
@@ -34359,17 +34359,17 @@
12
- 116560
+ 11655923
- 36356
+ 3635534
- 86073
+ 860724
@@ -34379,12 +34379,12 @@
56
- 48132
+ 48131610
- 32865
+ 3286410
@@ -34410,7 +34410,7 @@
23
- 114183
+ 1141823
@@ -34456,7 +34456,7 @@
12
- 1541684
+ 1541669
@@ -34472,12 +34472,12 @@
12
- 1181773
+ 118176123
- 359911
+ 359907
@@ -34589,11 +34589,11 @@
asp_elements
- 148402
+ 148401id
- 148402
+ 148401kind
@@ -34601,7 +34601,7 @@
loc
- 148402
+ 148401
@@ -34615,7 +34615,7 @@
12
- 148402
+ 148401
@@ -34631,7 +34631,7 @@
12
- 148402
+ 148401
@@ -34759,7 +34759,7 @@
12
- 148402
+ 148401
@@ -34775,7 +34775,7 @@
12
- 148402
+ 148401
@@ -35376,11 +35376,11 @@
asp_element_body
- 118618
+ 118617element
- 118618
+ 118617body
@@ -35398,7 +35398,7 @@
12
- 118618
+ 118617
@@ -36224,11 +36224,11 @@
cil_instruction
- 504260704
+ 504255988id
- 504260704
+ 504255988opcode
@@ -36236,11 +36236,11 @@
index
- 1697213
+ 1697197impl
- 23978900
+ 23978675
@@ -36254,7 +36254,7 @@
12
- 504260704
+ 504255988
@@ -36270,7 +36270,7 @@
12
- 504260704
+ 504255988
@@ -36286,7 +36286,7 @@
12
- 504260704
+ 504255988
@@ -36530,47 +36530,47 @@
12
- 352005
+ 35200123
- 5788
+ 578734
- 466938
+ 46693345
- 116203
+ 11620156
- 205090
+ 205088615
- 83276
+ 832751516
- 145172
+ 1451711620
- 144670
+ 14466920126
- 127395
+ 127393126
@@ -36591,42 +36591,42 @@
12
- 713164
+ 71315823
- 246078
+ 24607634
- 152584
+ 15258347
- 101880
+ 10187979
- 152496
+ 152494911
- 130052
+ 1300511129
- 129462
+ 12946129177
- 71493
+ 71492
@@ -36642,47 +36642,47 @@
12
- 352005
+ 35200123
- 5788
+ 578734
- 466938
+ 46693345
- 116203
+ 11620156
- 205090
+ 205088615
- 83276
+ 832751516
- 145172
+ 1451711620
- 144670
+ 14466920126
- 127395
+ 127393126
@@ -36703,57 +36703,57 @@
13
- 1768175
+ 176815934
- 5292243
+ 529219345
- 2487040
+ 248701656
- 1620227
+ 162021268
- 1895748
+ 1895730811
- 1892411
+ 18923931116
- 1968659
+ 19686401623
- 1813062
+ 18130452335
- 1856944
+ 18569273567
- 1825790
+ 18257736757474
- 1558597
+ 1558582
@@ -36769,52 +36769,52 @@
13
- 1771808
+ 177179134
- 5485048
+ 548499745
- 2836594
+ 283656756
- 2484441
+ 248441867
- 1600973
+ 160095879
- 2124669
+ 2124649912
- 2168581
+ 21685611216
- 2034335
+ 20343161624
- 1878207
+ 18781892477
- 1594240
+ 1594225
@@ -36830,57 +36830,57 @@
13
- 1768175
+ 176815934
- 5292243
+ 529219345
- 2487040
+ 248701656
- 1620227
+ 162021268
- 1895748
+ 1895730811
- 1892411
+ 18923931116
- 1968659
+ 19686401623
- 1813062
+ 18130452335
- 1856944
+ 18569273567
- 1825790
+ 18257736757474
- 1558597
+ 1558582
@@ -36890,15 +36890,15 @@
cil_jump
- 38654205
+ 38653843instruction
- 38654205
+ 38653843target
- 29345826
+ 29345551
@@ -36912,7 +36912,7 @@
12
- 38654205
+ 38653843
@@ -36928,17 +36928,17 @@
12
- 24482485
+ 2448225623
- 3200027
+ 31999973473
- 1663312
+ 1663297
@@ -36948,15 +36948,15 @@
cil_access
- 205357557
+ 205355636instruction
- 205357557
+ 205355636target
- 48924367
+ 48923909
@@ -36970,7 +36970,7 @@
12
- 205357557
+ 205355636
@@ -36986,32 +36986,32 @@
12
- 20166732
+ 2016654323
- 12282703
+ 1228258934
- 5954349
+ 595429345
- 3067877
+ 306784958
- 4125074
+ 4125035872956
- 3327629
+ 3327598
@@ -37021,15 +37021,15 @@
cil_value
- 19775953
+ 19775768instruction
- 19775953
+ 19775768value
- 4923700
+ 4923654
@@ -37043,7 +37043,7 @@
12
- 19775953
+ 19775768
@@ -37059,22 +37059,22 @@
12
- 3687282
+ 368724823
- 676753
+ 67674737
- 372292
+ 3722897182148
- 187371
+ 187370
@@ -37084,19 +37084,19 @@
cil_switch
- 4070472
+ 4070434instruction
- 272685
+ 272683index
- 141510
+ 141509target
- 1795403
+ 1795386
@@ -37115,17 +37115,17 @@
34
- 75037
+ 7503645
- 45979
+ 4597856
- 32454
+ 324536
@@ -37176,12 +37176,12 @@
23
- 33340
+ 3333934
- 96919
+ 969184
@@ -37227,7 +37227,7 @@
67
- 70489
+ 704887
@@ -37242,7 +37242,7 @@
15655
- 10631
+ 10630688
@@ -37268,7 +37268,7 @@
67
- 70489
+ 704887
@@ -37283,7 +37283,7 @@
15645
- 10631
+ 10630675
@@ -37304,12 +37304,12 @@
12
- 1771690
+ 1771673218
- 23713
+ 23712
@@ -37325,12 +37325,12 @@
12
- 1596219
+ 159620426
- 141422
+ 1414206
@@ -37387,15 +37387,15 @@
cil_type_location
- 4842462
+ 4842416id
- 4842462
+ 4842416loc
- 14588
+ 14587
@@ -37409,7 +37409,7 @@
12
- 4842462
+ 4842416
@@ -37485,11 +37485,11 @@
cil_method_location
- 29356250
+ 29355975id
- 29356250
+ 29355975loc
@@ -37507,7 +37507,7 @@
12
- 29356250
+ 29355975
@@ -37598,15 +37598,15 @@
cil_type
- 12399763
+ 12399647id
- 12399763
+ 12399647name
- 3497607
+ 3497574kind
@@ -37614,11 +37614,11 @@
parent
- 2509483
+ 2509459sourceDecl
- 6934884
+ 6934819
@@ -37632,7 +37632,7 @@
12
- 12399763
+ 12399647
@@ -37648,7 +37648,7 @@
12
- 12399763
+ 12399647
@@ -37664,7 +37664,7 @@
12
- 12399763
+ 12399647
@@ -37680,7 +37680,7 @@
12
- 12399763
+ 12399647
@@ -37696,17 +37696,17 @@
12
- 3073163
+ 307313524
- 292855
+ 292852445085
- 131588
+ 131587
@@ -37722,7 +37722,7 @@
12
- 3497607
+ 3497574
@@ -37738,12 +37738,12 @@
12
- 3232334
+ 3232303248
- 262409
+ 26240648
@@ -37764,17 +37764,17 @@
12
- 3194150
+ 319412125
- 271947
+ 271945545085
- 31509
+ 31508
@@ -37929,27 +37929,27 @@
12
- 1632423
+ 163240823
- 460795
+ 46079135
- 196792
+ 196790528
- 189025
+ 1890232856074
- 30446
+ 30445
@@ -37965,22 +37965,22 @@
12
- 1641164
+ 164114923
- 468149
+ 46814435
- 196821
+ 196819538
- 188671
+ 18866938
@@ -38001,12 +38001,12 @@
12
- 2470739
+ 247071624
- 38744
+ 38743
@@ -38022,22 +38022,22 @@
12
- 1640633
+ 164061723
- 467971
+ 46796735
- 196821
+ 196819538
- 188700
+ 18869838
@@ -38058,12 +38058,12 @@
12
- 6636063
+ 6636001223276
- 298820
+ 298817
@@ -38079,7 +38079,7 @@
12
- 6934884
+ 6934819
@@ -38095,7 +38095,7 @@
12
- 6934884
+ 6934819
@@ -38111,12 +38111,12 @@
12
- 6836960
+ 683689621652
- 97923
+ 97922
@@ -38174,15 +38174,15 @@
cil_array_type
- 181790
+ 181788id
- 181790
+ 181788element_type
- 181199
+ 181198rank
@@ -38200,7 +38200,7 @@
12
- 181790
+ 181788
@@ -38216,7 +38216,7 @@
12
- 181790
+ 181788
@@ -38232,7 +38232,7 @@
12
- 180668
+ 1806662
@@ -38253,7 +38253,7 @@
12
- 180668
+ 1806662
@@ -38393,23 +38393,23 @@
cil_method
- 39373777
+ 39373409id
- 39373777
+ 39373409name
- 7889520
+ 7889447parent
- 7602010
+ 7601939return_type
- 3365930
+ 3365899
@@ -38423,7 +38423,7 @@
12
- 39373777
+ 39373409
@@ -38439,7 +38439,7 @@
12
- 39373777
+ 39373409
@@ -38455,7 +38455,7 @@
12
- 39373777
+ 39373409
@@ -38471,27 +38471,27 @@
12
- 5260940
+ 526089123
- 1204170
+ 120415935
- 695180
+ 695174519
- 592856
+ 59285119206309
- 136372
+ 136371
@@ -38507,22 +38507,22 @@
12
- 5492194
+ 549214323
- 1123167
+ 112315735
- 645244
+ 645238548
- 591941
+ 59193548
@@ -38543,17 +38543,17 @@
12
- 7115788
+ 711572225
- 616717
+ 616711510798
- 157014
+ 157012
@@ -38569,37 +38569,37 @@
12
- 2404058
+ 240403623
- 1743783
+ 174376734
- 872216
+ 87220845
- 624395
+ 62438957
- 648758
+ 648752711
- 655048
+ 6550421139
- 572894
+ 57288839
@@ -38620,37 +38620,37 @@
12
- 2458365
+ 245834223
- 1772487
+ 177247034
- 893892
+ 89388345
- 633550
+ 63354457
- 698104
+ 698097711
- 599442
+ 599436113640
- 546168
+ 546163
@@ -38666,32 +38666,32 @@
12
- 3242994
+ 324296423
- 2011094
+ 201107634
- 858366
+ 85835845
- 456927
+ 45692357
- 614059
+ 614054712757
- 418567
+ 418563
@@ -38707,27 +38707,27 @@
12
- 2033124
+ 203310523
- 586123
+ 58611834
- 222572
+ 22257048
- 285561
+ 2855588508819
- 238548
+ 238546
@@ -38743,22 +38743,22 @@
12
- 2303713
+ 230369223
- 542595
+ 54259035
- 273778
+ 273775578481
- 245842
+ 245840
@@ -38774,27 +38774,27 @@
12
- 2200592
+ 220057223
- 562588
+ 56258234
- 209874
+ 20987249
- 261818
+ 2618169207300
- 131056
+ 131055
@@ -38804,15 +38804,15 @@
cil_method_source_declaration
- 34929152
+ 34928825method
- 34929152
+ 34928825source
- 30419382
+ 30419098
@@ -38826,7 +38826,7 @@
12
- 34929152
+ 34928825
@@ -38842,12 +38842,12 @@
12
- 28648401
+ 286481332981
- 1770981
+ 1770964
@@ -38857,15 +38857,15 @@
cil_method_implementation
- 27073001
+ 27072747id
- 27073001
+ 27072747method
- 27049967
+ 27049714location
@@ -38883,7 +38883,7 @@
12
- 27073001
+ 27072747
@@ -38899,7 +38899,7 @@
12
- 27073001
+ 27072747
@@ -38915,12 +38915,12 @@
12
- 27047073
+ 27046820227
- 2894
+ 2893
@@ -38936,7 +38936,7 @@
12
- 27049967
+ 27049714
@@ -39098,15 +39098,15 @@
cil_implements
- 1403915
+ 1403902id
- 1403325
+ 1403311decl
- 259544
+ 259542
@@ -39120,7 +39120,7 @@
12
- 1402734
+ 14027212
@@ -39141,12 +39141,12 @@
12
- 169860
+ 16985823
- 42701
+ 427003
@@ -39156,12 +39156,12 @@
410
- 19815
+ 19814103161
- 10129
+ 10128
@@ -39171,23 +39171,23 @@
cil_field
- 15899467
+ 15899318id
- 15899467
+ 15899318parent
- 3685983
+ 3685949name
- 6243572
+ 6243513field_type
- 3062916
+ 3062888
@@ -39201,7 +39201,7 @@
12
- 15899467
+ 15899318
@@ -39217,7 +39217,7 @@
12
- 15899467
+ 15899318
@@ -39233,7 +39233,7 @@
12
- 15899467
+ 15899318
@@ -39249,42 +39249,42 @@
12
- 1083833
+ 108382223
- 913352
+ 91334434
- 486546
+ 48654245
- 328173
+ 32817056
- 220977
+ 22097568
- 262556
+ 262554815
- 285797
+ 285794156824
- 104745
+ 104744
@@ -39300,42 +39300,42 @@
12
- 1083833
+ 108382223
- 913352
+ 91334434
- 486546
+ 48654245
- 328173
+ 32817056
- 220977
+ 22097568
- 262556
+ 262554815
- 285797
+ 285794156824
- 104745
+ 104744
@@ -39351,32 +39351,32 @@
12
- 1248614
+ 124860223
- 1218965
+ 121895334
- 465934
+ 46592945
- 247702
+ 24770058
- 323921
+ 3239188524
- 180845
+ 180843
@@ -39392,22 +39392,22 @@
12
- 4788627
+ 478858223
- 792897
+ 79288938
- 498152
+ 498147813940
- 163894
+ 163893
@@ -39423,22 +39423,22 @@
12
- 4788627
+ 478858223
- 792897
+ 79288938
- 498152
+ 498147813940
- 163894
+ 163893
@@ -39454,17 +39454,17 @@
12
- 5453746
+ 545369523
- 488968
+ 488963312921
- 300858
+ 300855
@@ -39480,27 +39480,27 @@
12
- 1844158
+ 184414023
- 591203
+ 59119734
- 171750
+ 17174847
- 244247
+ 244245758308
- 211557
+ 211555
@@ -39516,22 +39516,22 @@
12
- 2063098
+ 206307923
- 593654
+ 59364836
- 251807
+ 251805622697
- 154356
+ 154355
@@ -39547,22 +39547,22 @@
12
- 2244002
+ 224398123
- 356316
+ 35631335
- 237987
+ 237985533056
- 224609
+ 224607
@@ -39572,15 +39572,15 @@
cil_parameter
- 75119038
+ 75118336id
- 75119038
+ 75118336parameterizable
- 37743421
+ 37743068index
@@ -39588,7 +39588,7 @@
param_type
- 9706924
+ 9706833
@@ -39602,7 +39602,7 @@
12
- 75119038
+ 75118336
@@ -39618,7 +39618,7 @@
12
- 75119038
+ 75118336
@@ -39634,7 +39634,7 @@
12
- 75119038
+ 75118336
@@ -39650,27 +39650,27 @@
12
- 16498466
+ 1649831223
- 12068636
+ 1206852334
- 5792078
+ 579202447
- 2932037
+ 2932009757
- 452202
+ 452198
@@ -39686,27 +39686,27 @@
12
- 16498466
+ 1649831223
- 12068636
+ 1206852334
- 5792078
+ 579202447
- 2932037
+ 2932009757
- 452202
+ 452198
@@ -39722,22 +39722,22 @@
12
- 16985988
+ 1698582923
- 12300274
+ 1230015934
- 5685768
+ 5685715443
- 2771390
+ 2771364
@@ -39936,42 +39936,42 @@
12
- 2729575
+ 272954923
- 2863142
+ 286311534
- 1063663
+ 106365345
- 653955
+ 65394957
- 740805
+ 740798711
- 735224
+ 7352171136
- 733481
+ 73347436108909
- 187076
+ 187074
@@ -39987,42 +39987,42 @@
12
- 2768466
+ 276844123
- 2861370
+ 286134334
- 1055365
+ 105535545
- 645096
+ 64509057
- 739919
+ 739912711
- 731916
+ 7319091137
- 728668
+ 7286613789965
- 176120
+ 176119
@@ -40038,17 +40038,17 @@
12
- 6826329
+ 682626523
- 2083267
+ 208324836
- 729111
+ 7291046
@@ -40063,37 +40063,37 @@
cil_parameter_in
- 358354
+ 358350id
- 358354
+ 358350cil_parameter_out
- 683899
+ 683893id
- 683899
+ 683893cil_setter
- 1074353
+ 1074343prop
- 1074353
+ 1074343method
- 1074353
+ 1074343
@@ -40107,7 +40107,7 @@
12
- 1074353
+ 1074343
@@ -40123,7 +40123,7 @@
12
- 1074353
+ 1074343
@@ -40133,11 +40133,11 @@
cil_custom_modifiers
- 217995
+ 217993id
- 197796
+ 197794modifier
@@ -40159,7 +40159,7 @@
12
- 177744
+ 1777432
@@ -40180,12 +40180,12 @@
12
- 196349
+ 19634723
- 1447
+ 1446
@@ -40349,11 +40349,11 @@
cil_type_annotation
- 1751904
+ 1751888id
- 1751904
+ 1751888annotation
@@ -40371,7 +40371,7 @@
12
- 1751904
+ 1751888
@@ -40397,15 +40397,15 @@
cil_getter
- 5994363
+ 5994307prop
- 5994363
+ 5994307method
- 5994363
+ 5994307
@@ -40419,7 +40419,7 @@
12
- 5994363
+ 5994307
@@ -40435,7 +40435,7 @@
12
- 5994363
+ 5994307
@@ -40445,15 +40445,15 @@
cil_adder
- 70696
+ 70695event
- 70696
+ 70695method
- 70873
+ 70872
@@ -40467,7 +40467,7 @@
12
- 70696
+ 70695
@@ -40483,7 +40483,7 @@
12
- 70873
+ 70872
@@ -40493,15 +40493,15 @@
cil_remover
- 70696
+ 70695event
- 70696
+ 70695method
- 70873
+ 70872
@@ -40515,7 +40515,7 @@
12
- 70696
+ 70695
@@ -40531,7 +40531,7 @@
12
- 70873
+ 70872
@@ -40589,23 +40589,23 @@
cil_property
- 6002749
+ 6002693id
- 6002749
+ 6002693parent
- 1591435
+ 1591420name
- 1540967
+ 1540952property_type
- 706667
+ 706661
@@ -40619,7 +40619,7 @@
12
- 6002749
+ 6002693
@@ -40635,7 +40635,7 @@
12
- 6002749
+ 6002693
@@ -40651,7 +40651,7 @@
12
- 6002749
+ 6002693
@@ -40667,32 +40667,32 @@
12
- 521629
+ 52162423
- 392402
+ 39239934
- 215484
+ 21548245
- 137258
+ 13725757
- 139502
+ 139501713
- 124442
+ 12444013
@@ -40713,37 +40713,37 @@
12
- 624838
+ 62483223
- 291408
+ 29140534
- 215544
+ 21554245
- 136520
+ 13651857
- 139738
+ 139737713
- 124087
+ 124086132090
- 59297
+ 59296
@@ -40759,27 +40759,27 @@
12
- 615625
+ 61561923
- 481851
+ 48184634
- 202137
+ 20213545
- 101053
+ 10105258
- 125268
+ 1252678
@@ -40800,27 +40800,27 @@
12
- 979206
+ 97919623
- 254760
+ 25475834
- 95118
+ 9511748
- 120248
+ 12024787161
- 91633
+ 91632
@@ -40836,27 +40836,27 @@
12
- 979206
+ 97919623
- 255203
+ 25520134
- 95177
+ 9517648
- 120219
+ 12021883695
- 91161
+ 91160
@@ -40872,17 +40872,17 @@
12
- 1346862
+ 134684923
- 113161
+ 11316031330
- 80943
+ 80942
@@ -40898,17 +40898,17 @@
12
- 410209
+ 41020623
- 125239
+ 12523834
- 46038
+ 460374
@@ -40918,7 +40918,7 @@
734
- 53096
+ 5309534
@@ -40939,12 +40939,12 @@
12
- 430172
+ 43016823
- 118831
+ 1188303
@@ -40959,12 +40959,12 @@
764
- 53007
+ 530066417546
- 4843
+ 4842
@@ -40980,12 +40980,12 @@
12
- 559812
+ 55980623
- 81534
+ 815333
@@ -41005,15 +41005,15 @@
cil_event
- 70696
+ 70695id
- 70696
+ 70695parent
- 30062
+ 30061name
@@ -41021,7 +41021,7 @@
event_type
- 21380
+ 21379
@@ -41035,7 +41035,7 @@
12
- 70696
+ 70695
@@ -41051,7 +41051,7 @@
12
- 70696
+ 70695
@@ -41067,7 +41067,7 @@
12
- 70696
+ 70695
@@ -41083,7 +41083,7 @@
12
- 16478
+ 164772
@@ -41124,7 +41124,7 @@
12
- 16478
+ 164772
@@ -41165,7 +41165,7 @@
12
- 19815
+ 198142
@@ -41273,7 +41273,7 @@
12
- 30121
+ 301202
@@ -41304,7 +41304,7 @@
23
- 4341
+ 43403
@@ -41386,15 +41386,15 @@
cil_local_variable
- 23026507
+ 23026292id
- 23026507
+ 23026292impl
- 6649736
+ 6649674index
@@ -41402,7 +41402,7 @@
var_type
- 2957964
+ 2957937
@@ -41416,7 +41416,7 @@
12
- 23026507
+ 23026292
@@ -41432,7 +41432,7 @@
12
- 23026507
+ 23026292
@@ -41448,7 +41448,7 @@
12
- 23026507
+ 23026292
@@ -41464,37 +41464,37 @@
12
- 2714986
+ 271496123
- 1154972
+ 115496134
- 783477
+ 78346945
- 524995
+ 52499056
- 385197
+ 38519369
- 558778
+ 558773929
- 498801
+ 49879729
@@ -41515,37 +41515,37 @@
12
- 2714986
+ 271496123
- 1154972
+ 115496134
- 783477
+ 78346945
- 524995
+ 52499056
- 385197
+ 38519369
- 558778
+ 558773929
- 498801
+ 49879729
@@ -41566,37 +41566,37 @@
12
- 2973084
+ 297305623
- 1271618
+ 127160634
- 818854
+ 81884745
- 500130
+ 50012657
- 537339
+ 537334716
- 498831
+ 49882616163
- 49877
+ 49876
@@ -41770,27 +41770,27 @@
12
- 1877350
+ 187733323
- 375954
+ 37595034
- 175411
+ 17541047
- 232849
+ 232846729
- 223664
+ 22366229
@@ -41811,27 +41811,27 @@
12
- 1959652
+ 195963423
- 358679
+ 35867535
- 267754
+ 267751512
- 222070
+ 2220681244190
- 149808
+ 149807
@@ -41847,27 +41847,27 @@
12
- 2018536
+ 201851723
- 391103
+ 39109934
- 185275
+ 18527348
- 239434
+ 2394328217
- 123615
+ 123614
@@ -41877,11 +41877,11 @@
cil_function_pointer_calling_conventions
- 39912
+ 39911id
- 39912
+ 39911kind
@@ -41899,7 +41899,7 @@
12
- 39912
+ 39911
@@ -41930,15 +41930,15 @@
cil_handler
- 2378514
+ 2378492id
- 2378514
+ 2378492impl
- 1552395
+ 1552381index
@@ -41950,15 +41950,15 @@
try_start
- 2323145
+ 2323123try_end
- 2349486
+ 2349464handler_start
- 2378514
+ 2378492
@@ -41972,7 +41972,7 @@
12
- 2378514
+ 2378492
@@ -41988,7 +41988,7 @@
12
- 2378514
+ 2378492
@@ -42004,7 +42004,7 @@
12
- 2378514
+ 2378492
@@ -42020,7 +42020,7 @@
12
- 2378514
+ 2378492
@@ -42036,7 +42036,7 @@
12
- 2378514
+ 2378492
@@ -42052,7 +42052,7 @@
12
- 2378514
+ 2378492
@@ -42068,22 +42068,22 @@
12
- 1142805
+ 114279523
- 247407
+ 24740535
- 119658
+ 119656583
- 42524
+ 42523
@@ -42099,22 +42099,22 @@
12
- 1142805
+ 114279523
- 247407
+ 24740535
- 119658
+ 119656583
- 42524
+ 42523
@@ -42130,12 +42130,12 @@
12
- 1453556
+ 145354324
- 98839
+ 98838
@@ -42151,17 +42151,17 @@
12
- 1161321
+ 116131023
- 240615
+ 24061336
- 125918
+ 1259176
@@ -42182,22 +42182,22 @@
12
- 1153171
+ 115316023
- 244070
+ 24406836
- 128989
+ 128988683
- 26164
+ 26163
@@ -42213,22 +42213,22 @@
12
- 1142805
+ 114279523
- 247407
+ 24740535
- 119658
+ 119656583
- 42524
+ 42523
@@ -42766,12 +42766,12 @@
12
- 2279616
+ 227959529
- 43528
+ 43527
@@ -42787,7 +42787,7 @@
12
- 2323145
+ 2323123
@@ -42803,12 +42803,12 @@
12
- 2279616
+ 227959529
- 43528
+ 43527
@@ -42824,7 +42824,7 @@
12
- 2305987
+ 23059662
@@ -42845,7 +42845,7 @@
12
- 2299727
+ 22997052
@@ -42866,12 +42866,12 @@
12
- 2279616
+ 227959529
- 43528
+ 43527
@@ -42887,7 +42887,7 @@
12
- 2326836
+ 23268142
@@ -42908,7 +42908,7 @@
12
- 2349486
+ 2349464
@@ -42924,7 +42924,7 @@
12
- 2326836
+ 23268142
@@ -42945,7 +42945,7 @@
12
- 2347537
+ 23475152
@@ -42966,7 +42966,7 @@
12
- 2349486
+ 2349464
@@ -42982,7 +42982,7 @@
12
- 2326836
+ 23268142
@@ -43003,7 +43003,7 @@
12
- 2378514
+ 2378492
@@ -43019,7 +43019,7 @@
12
- 2378514
+ 2378492
@@ -43035,7 +43035,7 @@
12
- 2378514
+ 2378492
@@ -43051,7 +43051,7 @@
12
- 2378514
+ 2378492
@@ -43067,7 +43067,7 @@
12
- 2378514
+ 2378492
@@ -43083,7 +43083,7 @@
12
- 2378514
+ 2378492
@@ -43141,11 +43141,11 @@
cil_handler_type
- 400819
+ 400815id
- 400819
+ 400815catch_type
@@ -43163,7 +43163,7 @@
12
- 400819
+ 400815
@@ -43224,11 +43224,11 @@
cil_method_stack_size
- 27072292
+ 27072039method
- 27072292
+ 27072039size
@@ -43246,7 +43246,7 @@
12
- 27072292
+ 27072039
@@ -43317,121 +43317,121 @@
cil_public
- 30557526
+ 30557240id
- 30557526
+ 30557240cil_private
- 15498766
+ 15498621id
- 15498766
+ 15498621cil_protected
- 28744228
+ 28743959id
- 28744228
+ 28743959cil_internal
- 986884
+ 986874id
- 986884
+ 986874cil_static
- 14521686
+ 14521550id
- 14521686
+ 14521550cil_sealed
- 6359922
+ 6359863id
- 6359922
+ 6359863cil_virtual
- 11734704
+ 11734594id
- 11734704
+ 11734594cil_abstract
- 2826199
+ 2826172id
- 2826199
+ 2826172cil_class
- 4475041
+ 4475000id
- 4475041
+ 4475000cil_interface
- 367479
+ 367475id
- 367479
+ 367475cil_security
- 48814
+ 48813id
- 48814
+ 48813
@@ -43449,37 +43449,37 @@
cil_specialname
- 12520543
+ 12520426id
- 12520543
+ 12520426cil_newslot
- 7370933
+ 7370864id
- 7370933
+ 7370864cil_base_class
- 4460424
+ 4460382id
- 4460424
+ 4460382base
- 462242
+ 462238
@@ -43493,7 +43493,7 @@
12
- 4460424
+ 4460382
@@ -43509,12 +43509,12 @@
12
- 280600
+ 28059723
- 90068
+ 900673
@@ -43524,7 +43524,7 @@
48
- 38242
+ 382418
@@ -43539,15 +43539,15 @@
cil_base_interface
- 2925894
+ 2925867id
- 1244479
+ 1244468base
- 538638
+ 538633
@@ -43561,32 +43561,32 @@
12
- 703478
+ 70347223
- 199095
+ 19909334
- 95531
+ 9553045
- 46540
+ 4653956
- 123792
+ 123791632
- 76041
+ 76040
@@ -43602,7 +43602,7 @@
12
- 358649
+ 3586462
@@ -43612,12 +43612,12 @@
34
- 31834
+ 3183348
- 43203
+ 432028
@@ -43637,11 +43637,11 @@
cil_enum_underlying_type
- 203849
+ 203848id
- 203849
+ 203848underlying
@@ -43659,7 +43659,7 @@
12
- 203849
+ 203848
@@ -43720,11 +43720,11 @@
cil_type_parameter
- 1773609
+ 1773592unbound
- 1331358
+ 1331346index
@@ -43732,7 +43732,7 @@
param
- 1773609
+ 1773592
@@ -43746,17 +43746,17 @@
12
- 994443
+ 99443423
- 282460
+ 282457343
- 54454
+ 54453
@@ -43772,17 +43772,17 @@
12
- 994443
+ 99443423
- 282460
+ 282457343
- 54454
+ 54453
@@ -43920,7 +43920,7 @@
12
- 1773609
+ 1773592
@@ -43936,7 +43936,7 @@
12
- 1773609
+ 1773592
@@ -43946,11 +43946,11 @@
cil_type_argument
- 11206076
+ 11205971bound
- 8383213
+ 8383135index
@@ -43958,7 +43958,7 @@
t
- 2800094
+ 2800068
@@ -43972,17 +43972,17 @@
12
- 5919148
+ 591909323
- 2202955
+ 2202934343
- 261109
+ 261107
@@ -43998,17 +43998,17 @@
12
- 6030449
+ 603039323
- 2159013
+ 2158993343
- 193750
+ 193748
@@ -44141,32 +44141,32 @@
12
- 1210194
+ 121018323
- 732418
+ 73241134
- 295483
+ 29548046
- 237455
+ 237453612
- 215160
+ 2151581214769
- 109381
+ 109380
@@ -44182,17 +44182,17 @@
12
- 2254043
+ 225402223
- 502079
+ 502075310
- 43971
+ 43970
@@ -44293,19 +44293,19 @@
cil_attribute
- 5874527
+ 5874473attributeid
- 5874527
+ 5874473element
- 5184131
+ 5184082constructor
- 27995
+ 27994
@@ -44319,7 +44319,7 @@
12
- 5874527
+ 5874473
@@ -44335,7 +44335,7 @@
12
- 5874527
+ 5874473
@@ -44351,12 +44351,12 @@
12
- 4807940
+ 480789523520
- 376190
+ 376187
@@ -44372,12 +44372,12 @@
12
- 4812458
+ 481241329
- 371672
+ 371669
@@ -44529,11 +44529,11 @@
cil_attribute_named_argument
- 261818
+ 261816attribute_id
- 161089
+ 161088param
@@ -44541,7 +44541,7 @@
value
- 119569
+ 119568
@@ -44555,7 +44555,7 @@
12
- 97510
+ 975092
@@ -44570,7 +44570,7 @@
46
- 12137
+ 121367
@@ -44591,7 +44591,7 @@
12
- 103711
+ 1037102
@@ -44754,7 +44754,7 @@
12
- 101171
+ 1011702
@@ -44780,7 +44780,7 @@
12
- 112925
+ 1129242
@@ -44795,11 +44795,11 @@
cil_attribute_positional_argument
- 1757367
+ 1757351attribute_id
- 1528150
+ 1528136index
@@ -44807,7 +44807,7 @@
value
- 440478
+ 440474
@@ -44821,12 +44821,12 @@
12
- 1317006
+ 131699423
- 194104
+ 1941033
@@ -44847,12 +44847,12 @@
12
- 1318276
+ 131826423
- 194222
+ 1942213
@@ -44940,12 +44940,12 @@
12
- 324925
+ 32492223
- 75273
+ 752723
@@ -44971,7 +44971,7 @@
12
- 400848
+ 4008452
@@ -44991,19 +44991,19 @@
metadata_handle
- 109731032
+ 109730006entity
- 109393999
+ 109392976location
- 14588
+ 14587handle
- 2756447
+ 2756422
@@ -45017,12 +45017,12 @@
12
- 109222337
+ 1092213162495
- 171661
+ 171659
@@ -45038,12 +45038,12 @@
12
- 109225527
+ 1092245052104
- 168472
+ 168470
@@ -45206,7 +45206,7 @@
23
- 373149
+ 3731453
@@ -45216,57 +45216,57 @@
45
- 360687
+ 36068358
- 210051
+ 210049811
- 237367
+ 2373641115
- 233026
+ 2330241522
- 101939
+ 1019382225
- 223103
+ 2231012539
- 216105
+ 2161033951
- 211143
+ 2111425173
- 210317
+ 21031573137
- 207807
+ 207805137732
- 169801
+ 169799
@@ -45282,62 +45282,62 @@
12
- 373651
+ 37364723
- 362134
+ 36213034
- 205326
+ 20532446
- 242092
+ 24208968
- 233026
+ 233024811
- 101733
+ 1017321113
- 223192
+ 2231901320
- 216134
+ 2161322026
- 210523
+ 2105212637
- 210996
+ 2109943770
- 209903
+ 20990170495
- 167733
+ 167732
From fd809742104647a3cf1892d28cc5ab791549db5b Mon Sep 17 00:00:00 2001
From: Michael Nebel
Date: Thu, 12 Jan 2023 15:00:29 +0100
Subject: [PATCH 239/381] Java: Download databases using the gh api instead of
lgtm.
---
.github/workflows/mad_modelDiff.yml | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/.github/workflows/mad_modelDiff.yml b/.github/workflows/mad_modelDiff.yml
index 2affe5f3bd7..018e53a49c5 100644
--- a/.github/workflows/mad_modelDiff.yml
+++ b/.github/workflows/mad_modelDiff.yml
@@ -40,12 +40,12 @@ jobs:
- name: Download database
env:
SLUG: ${{ matrix.slug }}
+ GH_TOKEN: ${{ github.token }}
run: |
set -x
mkdir lib-dbs
SHORTNAME=${SLUG//[^a-zA-Z0-9_]/}
- projectId=`curl -s https://lgtm.com/api/v1.0/projects/g/${SLUG} | jq .id`
- curl -L "https://lgtm.com/api/v1.0/snapshots/$projectId/java" -o "$SHORTNAME.zip"
+ gh api -H "Accept: application/zip" "/repos/${SLUG}/code-scanning/codeql/databases/java" > "$SHORTNAME.zip"
unzip -q -d "${SHORTNAME}-db" "${SHORTNAME}.zip"
mkdir "lib-dbs/$SHORTNAME/"
mv "${SHORTNAME}-db/"$(ls -1 "${SHORTNAME}"-db)/* "lib-dbs/${SHORTNAME}/"
From 4acd1ababe111d37d3ec00fd004d22f5e8fbe0ec Mon Sep 17 00:00:00 2001
From: Sarita Iyer <66540150+saritai@users.noreply.github.com>
Date: Thu, 12 Jan 2023 15:57:43 -0500
Subject: [PATCH 240/381] Update docs/codeql/CONTRIBUTING.MD
Co-authored-by: Felicity Chapman
---
docs/codeql/CONTRIBUTING.MD | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/docs/codeql/CONTRIBUTING.MD b/docs/codeql/CONTRIBUTING.MD
index 478c2d28ac5..ed07e78b1b9 100644
--- a/docs/codeql/CONTRIBUTING.MD
+++ b/docs/codeql/CONTRIBUTING.MD
@@ -8,7 +8,7 @@ To make changes to the documentation on [codeql.github.com](https://codeql.githu
## Contributing to CodeQL CLI docs on `docs.github.com`
-We are in the process of moving all documentation about the CodeQL CLI from [codeql.github.com](https://codeql.github.com/docs/codeql-cli/) to the public [github/docs](https://github.com/github/docs) repository so that this documentation is published on the [GitHub Docs](https://docs.github.com/en/code-security/code-scanning) site. This includes all articles under "[Using the CodeQL CLI](https://codeql.github.com/docs/codeql-cli/using-the-codeql-cli/)" and "[CodeQL CLI reference](https://codeql.github.com/docs/codeql-cli/codeql-cli-reference/)" categories. This will make it easier for code scanning users to find information about using CodeQL to query their codebases.
+We are in the process of moving all documentation about the CodeQL CLI from [github/codeql](https://github.com/github/codeql/tree/main/docs/codeql) to the public [github/docs](https://github.com/github/docs) repository so that this documentation is published on the [GitHub Docs](https://docs.github.com/en/code-security/code-scanning) site. This includes all articles that are currently published under "[Using the CodeQL CLI](https://codeql.github.com/docs/codeql-cli/using-the-codeql-cli/)" and "[CodeQL CLI reference](https://codeql.github.com/docs/codeql-cli/codeql-cli-reference/)" categories on the CodeQL microsite. This will make it easier for code scanning users to find information about using CodeQL to query their codebases.
**Note**: For a brief time, we will have source files for CodeQL CLI documentation in two locations. During this period we will not accept changes to the old files in the `codeql` repository, only to the new files in the `docs` repository.
From ffb267937acb5585c69460d86eb54d13e177df21 Mon Sep 17 00:00:00 2001
From: Jami Cogswell
Date: Thu, 12 Jan 2023 16:24:05 -0500
Subject: [PATCH 241/381] Java: add endsWith additionalTaintStep to
ConditionalBypassFlowConfig
---
.../java/security/ConditionalBypassQuery.qll | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/java/ql/lib/semmle/code/java/security/ConditionalBypassQuery.qll b/java/ql/lib/semmle/code/java/security/ConditionalBypassQuery.qll
index 3bff0ae0a80..9bff32eac02 100644
--- a/java/ql/lib/semmle/code/java/security/ConditionalBypassQuery.qll
+++ b/java/ql/lib/semmle/code/java/security/ConditionalBypassQuery.qll
@@ -23,6 +23,19 @@ predicate conditionControlsMethod(MethodAccess ma, Expr e) {
)
}
+/**
+ * Holds if `node1` to `node2` is a dataflow step through the
+ * `endsWith` method of the `java.lang.String` class.
+ */
+private predicate endsWithStep(DataFlow::Node node1, DataFlow::Node node2) {
+ exists(MethodAccess ma |
+ ma.getMethod().getDeclaringType() instanceof TypeString and
+ ma.getMethod().getName() = "endsWith" and
+ ma.getQualifier() = node1.asExpr() and
+ ma = node2.asExpr()
+ )
+}
+
/**
* A taint tracking configuration for untrusted data flowing to sensitive conditions.
*/
@@ -32,4 +45,8 @@ class ConditionalBypassFlowConfig extends TaintTracking::Configuration {
override predicate isSource(DataFlow::Node source) { source instanceof RemoteFlowSource }
override predicate isSink(DataFlow::Node sink) { conditionControlsMethod(_, sink.asExpr()) }
+
+ override predicate isAdditionalTaintStep(DataFlow::Node node1, DataFlow::Node node2) {
+ endsWithStep(node1, node2)
+ }
}
From a39b2aaaac8f9904979f9e9b8a582ba3290916d6 Mon Sep 17 00:00:00 2001
From: Jami Cogswell
Date: Thu, 12 Jan 2023 16:24:57 -0500
Subject: [PATCH 242/381] Java: remove endsWith test case
---
java/ql/test/library-tests/dataflow/taint/B.java | 8 ++++----
java/ql/test/library-tests/dataflow/taint/test.expected | 1 -
2 files changed, 4 insertions(+), 5 deletions(-)
diff --git a/java/ql/test/library-tests/dataflow/taint/B.java b/java/ql/test/library-tests/dataflow/taint/B.java
index af659283b13..5bd50862302 100644
--- a/java/ql/test/library-tests/dataflow/taint/B.java
+++ b/java/ql/test/library-tests/dataflow/taint/B.java
@@ -58,19 +58,19 @@ public class B {
// non-whitelisted constructors don't pass taint
StringWrapper herring = new StringWrapper(complex);
sink(herring);
- // toString does not pass taint yet
+ // toString does not pass taint yet
String valueOfObject = String.valueOf(args);
sink(valueOfObject);
-
+
// tainted equality check with constant
boolean cond = "foo" == s;
sink(cond);
// tainted logic with tainted operand
boolean logic = cond && safe();
sink(logic);
- // tainted condition
- sink(concat.endsWith("I'm tainted"));
+
+
// tainted
logic = safe() || cond;
sink(logic);
diff --git a/java/ql/test/library-tests/dataflow/taint/test.expected b/java/ql/test/library-tests/dataflow/taint/test.expected
index 8b7d85321b4..aee1744af9b 100644
--- a/java/ql/test/library-tests/dataflow/taint/test.expected
+++ b/java/ql/test/library-tests/dataflow/taint/test.expected
@@ -18,7 +18,6 @@
| B.java:15:21:15:27 | taint(...) | B.java:51:10:51:21 | fluentConcat |
| B.java:15:21:15:27 | taint(...) | B.java:68:10:68:13 | cond |
| B.java:15:21:15:27 | taint(...) | B.java:71:10:71:14 | logic |
-| B.java:15:21:15:27 | taint(...) | B.java:73:10:73:39 | endsWith(...) |
| B.java:15:21:15:27 | taint(...) | B.java:76:10:76:14 | logic |
| B.java:15:21:15:27 | taint(...) | B.java:79:10:79:14 | logic |
| B.java:15:21:15:27 | taint(...) | B.java:87:10:87:16 | trimmed |
From c3a1d088ace1905fd9b34b23de80300530683989 Mon Sep 17 00:00:00 2001
From: Jami Cogswell
Date: Thu, 12 Jan 2023 16:32:52 -0500
Subject: [PATCH 243/381] Java: update change note
---
java/ql/lib/change-notes/2023-01-03-add-more-top-jdk-models.md | 2 ++
1 file changed, 2 insertions(+)
diff --git a/java/ql/lib/change-notes/2023-01-03-add-more-top-jdk-models.md b/java/ql/lib/change-notes/2023-01-03-add-more-top-jdk-models.md
index a74fb161e58..1272c00953e 100644
--- a/java/ql/lib/change-notes/2023-01-03-add-more-top-jdk-models.md
+++ b/java/ql/lib/change-notes/2023-01-03-add-more-top-jdk-models.md
@@ -2,3 +2,5 @@
category: minorAnalysis
---
* Added more dataflow models for frequently-used JDK APIs.
+* Removed summary model for `java.lang.String#endsWith(String)` and added neutral model for this API.
+* Added additional taint step for `java.lang.String#endsWith(String)` to `ConditionalBypassFlowConfig`.
From edbe95837f0ec4170d553fb820132b626825eca4 Mon Sep 17 00:00:00 2001
From: Robert Marsh
Date: Tue, 13 Dec 2022 11:45:08 -0500
Subject: [PATCH 244/381] Convert RangeAnalysis to trivial parameterized mod
---
.../cpp/semantic/analysis/RangeAnalysis.qll | 1371 +++++++++--------
1 file changed, 689 insertions(+), 682 deletions(-)
diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysis.qll b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysis.qll
index 4953b994c8e..63f2ebe5fa5 100644
--- a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysis.qll
+++ b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysis.qll
@@ -70,262 +70,6 @@ private import ModulusAnalysis
private import experimental.semmle.code.cpp.semantic.Semantic
private import ConstantAnalysis
-cached
-private module RangeAnalysisCache {
- cached
- module RangeAnalysisPublic {
- /**
- * Holds if `b + delta` is a valid bound for `e`.
- * - `upper = true` : `e <= b + delta`
- * - `upper = false` : `e >= b + delta`
- *
- * The reason for the bound is given by `reason` and may be either a condition
- * or `NoReason` if the bound was proven directly without the use of a bounding
- * condition.
- */
- cached
- predicate semBounded(SemExpr e, SemBound b, int delta, boolean upper, SemReason reason) {
- bounded(e, b, delta, upper, _, _, reason) and
- bestBound(e, b, delta, upper)
- }
- }
-
- /**
- * Holds if `guard = boundFlowCond(_, _, _, _, _) or guard = eqFlowCond(_, _, _, _, _)`.
- */
- cached
- predicate possibleReason(SemGuard guard) {
- guard = boundFlowCond(_, _, _, _, _) or guard = semEqFlowCond(_, _, _, _, _)
- }
-}
-
-private import RangeAnalysisCache
-import RangeAnalysisPublic
-
-/**
- * Holds if `b + delta` is a valid bound for `e` and this is the best such delta.
- * - `upper = true` : `e <= b + delta`
- * - `upper = false` : `e >= b + delta`
- */
-private predicate bestBound(SemExpr e, SemBound b, int delta, boolean upper) {
- delta = min(int d | bounded(e, b, d, upper, _, _, _)) and upper = true
- or
- delta = max(int d | bounded(e, b, d, upper, _, _, _)) and upper = false
-}
-
-/**
- * Holds if `comp` corresponds to:
- * - `upper = true` : `v <= e + delta` or `v < e + delta`
- * - `upper = false` : `v >= e + delta` or `v > e + delta`
- */
-private predicate boundCondition(
- SemRelationalExpr comp, SemSsaVariable v, SemExpr e, int delta, boolean upper
-) {
- comp.getLesserOperand() = semSsaRead(v, delta) and e = comp.getGreaterOperand() and upper = true
- or
- comp.getGreaterOperand() = semSsaRead(v, delta) and e = comp.getLesserOperand() and upper = false
- or
- exists(SemSubExpr sub, SemConstantIntegerExpr c, int d |
- // (v - d) - e < c
- comp.getLesserOperand() = sub and
- comp.getGreaterOperand() = c and
- sub.getLeftOperand() = semSsaRead(v, d) and
- sub.getRightOperand() = e and
- upper = true and
- delta = d + c.getIntValue()
- or
- // (v - d) - e > c
- comp.getGreaterOperand() = sub and
- comp.getLesserOperand() = c and
- sub.getLeftOperand() = semSsaRead(v, d) and
- sub.getRightOperand() = e and
- upper = false and
- delta = d + c.getIntValue()
- or
- // e - (v - d) < c
- comp.getLesserOperand() = sub and
- comp.getGreaterOperand() = c and
- sub.getLeftOperand() = e and
- sub.getRightOperand() = semSsaRead(v, d) and
- upper = false and
- delta = d - c.getIntValue()
- or
- // e - (v - d) > c
- comp.getGreaterOperand() = sub and
- comp.getLesserOperand() = c and
- sub.getLeftOperand() = e and
- sub.getRightOperand() = semSsaRead(v, d) and
- upper = true and
- delta = d - c.getIntValue()
- )
-}
-
-/**
- * Holds if `comp` is a comparison between `x` and `y` for which `y - x` has a
- * fixed value modulo some `mod > 1`, such that the comparison can be
- * strengthened by `strengthen` when evaluating to `testIsTrue`.
- */
-private predicate modulusComparison(SemRelationalExpr comp, boolean testIsTrue, int strengthen) {
- exists(
- SemBound b, int v1, int v2, int mod1, int mod2, int mod, boolean resultIsStrict, int d, int k
- |
- // If `x <= y` and `x =(mod) b + v1` and `y =(mod) b + v2` then
- // `0 <= y - x =(mod) v2 - v1`. By choosing `k =(mod) v2 - v1` with
- // `0 <= k < mod` we get `k <= y - x`. If the resulting comparison is
- // strict then the strengthening amount is instead `k - 1` modulo `mod`:
- // `x < y` means `0 <= y - x - 1 =(mod) k - 1` so `k - 1 <= y - x - 1` and
- // thus `k - 1 < y - x` with `0 <= k - 1 < mod`.
- semExprModulus(comp.getLesserOperand(), b, v1, mod1) and
- semExprModulus(comp.getGreaterOperand(), b, v2, mod2) and
- mod = mod1.gcd(mod2) and
- mod != 1 and
- (testIsTrue = true or testIsTrue = false) and
- (
- if comp.isStrict()
- then resultIsStrict = testIsTrue
- else resultIsStrict = testIsTrue.booleanNot()
- ) and
- (
- resultIsStrict = true and d = 1
- or
- resultIsStrict = false and d = 0
- ) and
- (
- testIsTrue = true and k = v2 - v1
- or
- testIsTrue = false and k = v1 - v2
- ) and
- strengthen = (((k - d) % mod) + mod) % mod
- )
-}
-
-/**
- * Gets a condition that tests whether `v` is bounded by `e + delta`.
- *
- * If the condition evaluates to `testIsTrue`:
- * - `upper = true` : `v <= e + delta`
- * - `upper = false` : `v >= e + delta`
- */
-private SemGuard boundFlowCond(
- SemSsaVariable v, SemExpr e, int delta, boolean upper, boolean testIsTrue
-) {
- exists(
- SemRelationalExpr comp, int d1, int d2, int d3, int strengthen, boolean compIsUpper,
- boolean resultIsStrict
- |
- comp = result.asExpr() and
- boundCondition(comp, v, e, d1, compIsUpper) and
- (testIsTrue = true or testIsTrue = false) and
- upper = compIsUpper.booleanXor(testIsTrue.booleanNot()) and
- (
- if comp.isStrict()
- then resultIsStrict = testIsTrue
- else resultIsStrict = testIsTrue.booleanNot()
- ) and
- (
- if
- getTrackedTypeForSsaVariable(v) instanceof SemIntegerType or
- getTrackedTypeForSsaVariable(v) instanceof SemAddressType
- then
- upper = true and strengthen = -1
- or
- upper = false and strengthen = 1
- else strengthen = 0
- ) and
- (
- exists(int k | modulusComparison(comp, testIsTrue, k) and d2 = strengthen * k)
- or
- not modulusComparison(comp, testIsTrue, _) and d2 = 0
- ) and
- // A strict inequality `x < y` can be strengthened to `x <= y - 1`.
- (
- resultIsStrict = true and d3 = strengthen
- or
- resultIsStrict = false and d3 = 0
- ) and
- delta = d1 + d2 + d3
- )
- or
- exists(boolean testIsTrue0 |
- semImplies_v2(result, testIsTrue, boundFlowCond(v, e, delta, upper, testIsTrue0), testIsTrue0)
- )
- or
- result = semEqFlowCond(v, e, delta, true, testIsTrue) and
- (upper = true or upper = false)
- or
- // guard that tests whether `v2` is bounded by `e + delta + d1 - d2` and
- // exists a guard `guardEq` such that `v = v2 - d1 + d2`.
- exists(SemSsaVariable v2, SemGuard guardEq, boolean eqIsTrue, int d1, int d2 |
- guardEq = semEqFlowCond(v, semSsaRead(v2, d1), d2, true, eqIsTrue) and
- result = boundFlowCond(v2, e, delta + d1 - d2, upper, testIsTrue) and
- // guardEq needs to control guard
- guardEq.directlyControls(result.getBasicBlock(), eqIsTrue)
- )
-}
-
-private newtype TSemReason =
- TSemNoReason() or
- TSemCondReason(SemGuard guard) { possibleReason(guard) }
-
-/**
- * A reason for an inferred bound. This can either be `CondReason` if the bound
- * is due to a specific condition, or `NoReason` if the bound is inferred
- * without going through a bounding condition.
- */
-abstract class SemReason extends TSemReason {
- /** Gets a textual representation of this reason. */
- abstract string toString();
-}
-
-/**
- * A reason for an inferred bound that indicates that the bound is inferred
- * without going through a bounding condition.
- */
-class SemNoReason extends SemReason, TSemNoReason {
- override string toString() { result = "NoReason" }
-}
-
-/** A reason for an inferred bound pointing to a condition. */
-class SemCondReason extends SemReason, TSemCondReason {
- /** Gets the condition that is the reason for the bound. */
- SemGuard getCond() { this = TSemCondReason(result) }
-
- override string toString() { result = getCond().toString() }
-}
-
-/**
- * Holds if `e + delta` is a valid bound for `v` at `pos`.
- * - `upper = true` : `v <= e + delta`
- * - `upper = false` : `v >= e + delta`
- */
-private predicate boundFlowStepSsa(
- SemSsaVariable v, SemSsaReadPosition pos, SemExpr e, int delta, boolean upper, SemReason reason
-) {
- semSsaUpdateStep(v, e, delta) and
- pos.hasReadOfVar(v) and
- (upper = true or upper = false) and
- reason = TSemNoReason()
- or
- exists(SemGuard guard, boolean testIsTrue |
- pos.hasReadOfVar(v) and
- guard = boundFlowCond(v, e, delta, upper, testIsTrue) and
- semGuardDirectlyControlsSsaRead(guard, pos, testIsTrue) and
- reason = TSemCondReason(guard)
- )
-}
-
-/** Holds if `v != e + delta` at `pos` and `v` is of integral type. */
-private predicate unequalFlowStepIntegralSsa(
- SemSsaVariable v, SemSsaReadPosition pos, SemExpr e, int delta, SemReason reason
-) {
- getTrackedTypeForSsaVariable(v) instanceof SemIntegerType and
- exists(SemGuard guard, boolean testIsTrue |
- pos.hasReadOfVar(v) and
- guard = semEqFlowCond(v, e, delta, false, testIsTrue) and
- semGuardDirectlyControlsSsaRead(guard, pos, testIsTrue) and
- reason = TSemCondReason(guard)
- )
-}
/**
* An expression that does conversion, boxing, or unboxing
@@ -385,448 +129,711 @@ private class NarrowingCastExpr extends ConvertOrBoxExpr {
int getUpperBound() { typeBound(getTrackedType(this), _, result) }
}
-/** Holds if `e >= 1` as determined by sign analysis. */
-private predicate strictlyPositiveIntegralExpr(SemExpr e) {
- semStrictlyPositive(e) and getTrackedType(e) instanceof SemIntegerType
-}
+signature module RangeSig { }
-/** Holds if `e <= -1` as determined by sign analysis. */
-private predicate strictlyNegativeIntegralExpr(SemExpr e) {
- semStrictlyNegative(e) and getTrackedType(e) instanceof SemIntegerType
-}
+module RangeStage {
+ cached
+ private module RangeAnalysisCache {
+ cached
+ module RangeAnalysisPublic {
+ /**
+ * Holds if `b + delta` is a valid bound for `e`.
+ * - `upper = true` : `e <= b + delta`
+ * - `upper = false` : `e >= b + delta`
+ *
+ * The reason for the bound is given by `reason` and may be either a condition
+ * or `NoReason` if the bound was proven directly without the use of a bounding
+ * condition.
+ */
+ cached
+ predicate semBounded(SemExpr e, SemBound b, int delta, boolean upper, SemReason reason) {
+ bounded(e, b, delta, upper, _, _, reason) and
+ bestBound(e, b, delta, upper)
+ }
+ }
-/**
- * Holds if `e1 + delta` is a valid bound for `e2`.
- * - `upper = true` : `e2 <= e1 + delta`
- * - `upper = false` : `e2 >= e1 + delta`
- */
-private predicate boundFlowStep(SemExpr e2, SemExpr e1, int delta, boolean upper) {
- semValueFlowStep(e2, e1, delta) and
- (upper = true or upper = false)
- or
- e2.(SafeCastExpr).getOperand() = e1 and
- delta = 0 and
- (upper = true or upper = false)
- or
- exists(SemExpr x | e2.(SemAddExpr).hasOperands(e1, x) |
- // `x instanceof ConstantIntegerExpr` is covered by valueFlowStep
- not x instanceof SemConstantIntegerExpr and
- not e1 instanceof SemConstantIntegerExpr and
- if strictlyPositiveIntegralExpr(x)
- then upper = false and delta = 1
- else
- if semPositive(x)
- then upper = false and delta = 0
- else
- if strictlyNegativeIntegralExpr(x)
- then upper = true and delta = -1
- else
- if semNegative(x)
- then upper = true and delta = 0
- else none()
- )
- or
- exists(SemExpr x, SemSubExpr sub |
- e2 = sub and
- sub.getLeftOperand() = e1 and
- sub.getRightOperand() = x
- |
- // `x instanceof ConstantIntegerExpr` is covered by valueFlowStep
- not x instanceof SemConstantIntegerExpr and
- if strictlyPositiveIntegralExpr(x)
- then upper = true and delta = -1
- else
- if semPositive(x)
- then upper = true and delta = 0
- else
- if strictlyNegativeIntegralExpr(x)
- then upper = false and delta = 1
- else
- if semNegative(x)
- then upper = false and delta = 0
- else none()
- )
- or
- e2.(SemRemExpr).getRightOperand() = e1 and
- semPositive(e1) and
- delta = -1 and
- upper = true
- or
- e2.(SemRemExpr).getLeftOperand() = e1 and semPositive(e1) and delta = 0 and upper = true
- or
- e2.(SemBitAndExpr).getAnOperand() = e1 and
- semPositive(e1) and
- delta = 0 and
- upper = true
- or
- e2.(SemBitOrExpr).getAnOperand() = e1 and
- semPositive(e2) and
- delta = 0 and
- upper = false
- or
- Specific::hasBound(e2, e1, delta, upper)
-}
+ /**
+ * Holds if `guard = boundFlowCond(_, _, _, _, _) or guard = eqFlowCond(_, _, _, _, _)`.
+ */
+ cached
+ predicate possibleReason(SemGuard guard) {
+ guard = boundFlowCond(_, _, _, _, _) or guard = semEqFlowCond(_, _, _, _, _)
+ }
+ }
-/** Holds if `e2 = e1 * factor` and `factor > 0`. */
-private predicate boundFlowStepMul(SemExpr e2, SemExpr e1, int factor) {
- exists(SemConstantIntegerExpr c, int k | k = c.getIntValue() and k > 0 |
- e2.(SemMulExpr).hasOperands(e1, c) and factor = k
+ private import RangeAnalysisCache
+ import RangeAnalysisPublic
+
+ /**
+ * Holds if `b + delta` is a valid bound for `e` and this is the best such delta.
+ * - `upper = true` : `e <= b + delta`
+ * - `upper = false` : `e >= b + delta`
+ */
+ private predicate bestBound(SemExpr e, SemBound b, int delta, boolean upper) {
+ delta = min(int d | bounded(e, b, d, upper, _, _, _)) and upper = true
or
- exists(SemShiftLeftExpr e |
- e = e2 and e.getLeftOperand() = e1 and e.getRightOperand() = c and factor = 2.pow(k)
- )
- )
-}
+ delta = max(int d | bounded(e, b, d, upper, _, _, _)) and upper = false
+ }
-/**
- * Holds if `e2 = e1 / factor` and `factor > 0`.
- *
- * This conflates division, right shift, and unsigned right shift and is
- * therefore only valid for non-negative numbers.
- */
-private predicate boundFlowStepDiv(SemExpr e2, SemExpr e1, int factor) {
- exists(SemConstantIntegerExpr c, int k | k = c.getIntValue() and k > 0 |
- exists(SemDivExpr e |
- e = e2 and e.getLeftOperand() = e1 and e.getRightOperand() = c and factor = k
- )
+ /**
+ * Holds if `comp` corresponds to:
+ * - `upper = true` : `v <= e + delta` or `v < e + delta`
+ * - `upper = false` : `v >= e + delta` or `v > e + delta`
+ */
+ private predicate boundCondition(
+ SemRelationalExpr comp, SemSsaVariable v, SemExpr e, int delta, boolean upper
+ ) {
+ comp.getLesserOperand() = semSsaRead(v, delta) and e = comp.getGreaterOperand() and upper = true
or
- exists(SemShiftRightExpr e |
- e = e2 and e.getLeftOperand() = e1 and e.getRightOperand() = c and factor = 2.pow(k)
- )
+ comp.getGreaterOperand() = semSsaRead(v, delta) and
+ e = comp.getLesserOperand() and
+ upper = false
or
- exists(SemShiftRightUnsignedExpr e |
- e = e2 and e.getLeftOperand() = e1 and e.getRightOperand() = c and factor = 2.pow(k)
- )
- )
-}
-
-/**
- * Holds if `b + delta` is a valid bound for `v` at `pos`.
- * - `upper = true` : `v <= b + delta`
- * - `upper = false` : `v >= b + delta`
- */
-private predicate boundedSsa(
- SemSsaVariable v, SemSsaReadPosition pos, SemBound b, int delta, boolean upper,
- boolean fromBackEdge, int origdelta, SemReason reason
-) {
- exists(SemExpr mid, int d1, int d2, SemReason r1, SemReason r2 |
- boundFlowStepSsa(v, pos, mid, d1, upper, r1) and
- bounded(mid, b, d2, upper, fromBackEdge, origdelta, r2) and
- // upper = true: v <= mid + d1 <= b + d1 + d2 = b + delta
- // upper = false: v >= mid + d1 >= b + d1 + d2 = b + delta
- delta = d1 + d2 and
- (if r1 instanceof SemNoReason then reason = r2 else reason = r1)
- )
- or
- exists(int d, SemReason r1, SemReason r2 |
- boundedSsa(v, pos, b, d, upper, fromBackEdge, origdelta, r2) or
- boundedPhi(v, b, d, upper, fromBackEdge, origdelta, r2)
- |
- unequalIntegralSsa(v, pos, b, d, r1) and
- (
- upper = true and delta = d - 1
+ exists(SemSubExpr sub, SemConstantIntegerExpr c, int d |
+ // (v - d) - e < c
+ comp.getLesserOperand() = sub and
+ comp.getGreaterOperand() = c and
+ sub.getLeftOperand() = semSsaRead(v, d) and
+ sub.getRightOperand() = e and
+ upper = true and
+ delta = d + c.getIntValue()
or
- upper = false and delta = d + 1
- ) and
- (
- reason = r1
+ // (v - d) - e > c
+ comp.getGreaterOperand() = sub and
+ comp.getLesserOperand() = c and
+ sub.getLeftOperand() = semSsaRead(v, d) and
+ sub.getRightOperand() = e and
+ upper = false and
+ delta = d + c.getIntValue()
or
- reason = r2 and not r2 instanceof SemNoReason
- )
- )
-}
-
-/**
- * Holds if `v != b + delta` at `pos` and `v` is of integral type.
- */
-private predicate unequalIntegralSsa(
- SemSsaVariable v, SemSsaReadPosition pos, SemBound b, int delta, SemReason reason
-) {
- exists(SemExpr e, int d1, int d2 |
- unequalFlowStepIntegralSsa(v, pos, e, d1, reason) and
- boundedUpper(e, b, d1) and
- boundedLower(e, b, d2) and
- delta = d2 + d1
- )
-}
-
-/**
- * Holds if `b + delta` is an upper bound for `e`.
- *
- * This predicate only exists to prevent a bad standard order in `unequalIntegralSsa`.
- */
-pragma[nomagic]
-private predicate boundedUpper(SemExpr e, SemBound b, int delta) {
- bounded(e, b, delta, true, _, _, _)
-}
-
-/**
- * Holds if `b + delta` is a lower bound for `e`.
- *
- * This predicate only exists to prevent a bad standard order in `unequalIntegralSsa`.
- */
-pragma[nomagic]
-private predicate boundedLower(SemExpr e, SemBound b, int delta) {
- bounded(e, b, delta, false, _, _, _)
-}
-
-/** Weakens a delta to lie in the range `[-1..1]`. */
-bindingset[delta, upper]
-private int weakenDelta(boolean upper, int delta) {
- delta in [-1 .. 1] and result = delta
- or
- upper = true and result = -1 and delta < -1
- or
- upper = false and result = 1 and delta > 1
-}
-
-/**
- * Holds if `b + delta` is a valid bound for `inp` when used as an input to
- * `phi` along `edge`.
- * - `upper = true` : `inp <= b + delta`
- * - `upper = false` : `inp >= b + delta`
- */
-private predicate boundedPhiInp(
- SemSsaPhiNode phi, SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge, SemBound b, int delta,
- boolean upper, boolean fromBackEdge, int origdelta, SemReason reason
-) {
- edge.phiInput(phi, inp) and
- exists(int d, boolean fromBackEdge0 |
- boundedSsa(inp, edge, b, d, upper, fromBackEdge0, origdelta, reason)
- or
- boundedPhi(inp, b, d, upper, fromBackEdge0, origdelta, reason)
- or
- b.(SemSsaBound).getAVariable() = inp and
- d = 0 and
- (upper = true or upper = false) and
- fromBackEdge0 = false and
- origdelta = 0 and
- reason = TSemNoReason()
- |
- if semBackEdge(phi, inp, edge)
- then
- fromBackEdge = true and
- (
- fromBackEdge0 = true and delta = weakenDelta(upper, d - origdelta) + origdelta
- or
- fromBackEdge0 = false and delta = d
- )
- else (
- delta = d and fromBackEdge = fromBackEdge0
- )
- )
-}
-
-/**
- * Holds if `b + delta` is a valid bound for `inp` when used as an input to
- * `phi` along `edge`.
- * - `upper = true` : `inp <= b + delta`
- * - `upper = false` : `inp >= b + delta`
- *
- * Equivalent to `boundedPhiInp(phi, inp, edge, b, delta, upper, _, _, _)`.
- */
-pragma[noinline]
-private predicate boundedPhiInp1(
- SemSsaPhiNode phi, SemBound b, boolean upper, SemSsaVariable inp,
- SemSsaReadPositionPhiInputEdge edge, int delta
-) {
- boundedPhiInp(phi, inp, edge, b, delta, upper, _, _, _)
-}
-
-/**
- * Holds if `phi` is a valid bound for `inp` when used as an input to `phi`
- * along `edge`.
- * - `upper = true` : `inp <= phi`
- * - `upper = false` : `inp >= phi`
- */
-private predicate selfBoundedPhiInp(
- SemSsaPhiNode phi, SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge, boolean upper
-) {
- exists(int d, SemSsaBound phibound |
- phibound.getAVariable() = phi and
- boundedPhiInp(phi, inp, edge, phibound, d, upper, _, _, _) and
- (
- upper = true and d <= 0
+ // e - (v - d) < c
+ comp.getLesserOperand() = sub and
+ comp.getGreaterOperand() = c and
+ sub.getLeftOperand() = e and
+ sub.getRightOperand() = semSsaRead(v, d) and
+ upper = false and
+ delta = d - c.getIntValue()
or
- upper = false and d >= 0
+ // e - (v - d) > c
+ comp.getGreaterOperand() = sub and
+ comp.getLesserOperand() = c and
+ sub.getLeftOperand() = e and
+ sub.getRightOperand() = semSsaRead(v, d) and
+ upper = true and
+ delta = d - c.getIntValue()
)
- )
-}
+ }
-/**
- * Holds if `b + delta` is a valid bound for some input, `inp`, to `phi`, and
- * thus a candidate bound for `phi`.
- * - `upper = true` : `inp <= b + delta`
- * - `upper = false` : `inp >= b + delta`
- */
-pragma[noinline]
-private predicate boundedPhiCand(
- SemSsaPhiNode phi, boolean upper, SemBound b, int delta, boolean fromBackEdge, int origdelta,
- SemReason reason
-) {
- exists(SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge |
- boundedPhiInp(phi, inp, edge, b, delta, upper, fromBackEdge, origdelta, reason)
- )
-}
-
-/**
- * Holds if the candidate bound `b + delta` for `phi` is valid for the phi input
- * `inp` along `edge`.
- */
-private predicate boundedPhiCandValidForEdge(
- SemSsaPhiNode phi, SemBound b, int delta, boolean upper, boolean fromBackEdge, int origdelta,
- SemReason reason, SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge
-) {
- boundedPhiCand(phi, upper, b, delta, fromBackEdge, origdelta, reason) and
- (
- exists(int d | boundedPhiInp1(phi, b, upper, inp, edge, d) | upper = true and d <= delta)
- or
- exists(int d | boundedPhiInp1(phi, b, upper, inp, edge, d) | upper = false and d >= delta)
- or
- selfBoundedPhiInp(phi, inp, edge, upper)
- )
-}
-
-/**
- * Holds if `b + delta` is a valid bound for `phi`.
- * - `upper = true` : `phi <= b + delta`
- * - `upper = false` : `phi >= b + delta`
- */
-private predicate boundedPhi(
- SemSsaPhiNode phi, SemBound b, int delta, boolean upper, boolean fromBackEdge, int origdelta,
- SemReason reason
-) {
- forex(SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge | edge.phiInput(phi, inp) |
- boundedPhiCandValidForEdge(phi, b, delta, upper, fromBackEdge, origdelta, reason, inp, edge)
- )
-}
-
-/**
- * Holds if `e` has an upper (for `upper = true`) or lower
- * (for `upper = false`) bound of `b`.
- */
-private predicate baseBound(SemExpr e, int b, boolean upper) {
- Specific::hasConstantBound(e, b, upper)
- or
- upper = false and
- b = 0 and
- semPositive(e.(SemBitAndExpr).getAnOperand()) and
- // REVIEW: We let the language opt out here to preserve original results.
- not Specific::ignoreZeroLowerBound(e)
-}
-
-/**
- * Holds if the value being cast has an upper (for `upper = true`) or lower
- * (for `upper = false`) bound within the bounds of the resulting type.
- * For `upper = true` this means that the cast will not overflow and for
- * `upper = false` this means that the cast will not underflow.
- */
-private predicate safeNarrowingCast(NarrowingCastExpr cast, boolean upper) {
- exists(int bound | bounded(cast.getOperand(), any(SemZeroBound zb), bound, upper, _, _, _) |
- upper = true and bound <= cast.getUpperBound()
- or
- upper = false and bound >= cast.getLowerBound()
- )
-}
-
-pragma[noinline]
-private predicate boundedCastExpr(
- NarrowingCastExpr cast, SemBound b, int delta, boolean upper, boolean fromBackEdge, int origdelta,
- SemReason reason
-) {
- bounded(cast.getOperand(), b, delta, upper, fromBackEdge, origdelta, reason)
-}
-
-/**
- * Holds if `b + delta` is a valid bound for `e`.
- * - `upper = true` : `e <= b + delta`
- * - `upper = false` : `e >= b + delta`
- */
-private predicate bounded(
- SemExpr e, SemBound b, int delta, boolean upper, boolean fromBackEdge, int origdelta,
- SemReason reason
-) {
- not Specific::ignoreExprBound(e) and
- (
- e = b.getExpr(delta) and
- (upper = true or upper = false) and
- fromBackEdge = false and
- origdelta = delta and
- reason = TSemNoReason()
- or
- baseBound(e, delta, upper) and
- b instanceof SemZeroBound and
- fromBackEdge = false and
- origdelta = delta and
- reason = TSemNoReason()
- or
- exists(SemSsaVariable v, SemSsaReadPositionBlock bb |
- boundedSsa(v, bb, b, delta, upper, fromBackEdge, origdelta, reason) and
- e = v.getAUse() and
- bb.getBlock() = e.getBasicBlock()
- )
- or
- exists(SemExpr mid, int d1, int d2 |
- boundFlowStep(e, mid, d1, upper) and
- // Constants have easy, base-case bounds, so let's not infer any recursive bounds.
- not e instanceof SemConstantIntegerExpr and
- bounded(mid, b, d2, upper, fromBackEdge, origdelta, reason) and
- // upper = true: e <= mid + d1 <= b + d1 + d2 = b + delta
- // upper = false: e >= mid + d1 >= b + d1 + d2 = b + delta
- delta = d1 + d2
- )
- or
- exists(SemSsaPhiNode phi |
- boundedPhi(phi, b, delta, upper, fromBackEdge, origdelta, reason) and
- e = phi.getAUse()
- )
- or
- exists(SemExpr mid, int factor, int d |
- boundFlowStepMul(e, mid, factor) and
- not e instanceof SemConstantIntegerExpr and
- bounded(mid, b, d, upper, fromBackEdge, origdelta, reason) and
- b instanceof SemZeroBound and
- delta = d * factor
- )
- or
- exists(SemExpr mid, int factor, int d |
- boundFlowStepDiv(e, mid, factor) and
- not e instanceof SemConstantIntegerExpr and
- bounded(mid, b, d, upper, fromBackEdge, origdelta, reason) and
- b instanceof SemZeroBound and
- d >= 0 and
- delta = d / factor
- )
- or
- exists(NarrowingCastExpr cast |
- cast = e and
- safeNarrowingCast(cast, upper.booleanNot()) and
- boundedCastExpr(cast, b, delta, upper, fromBackEdge, origdelta, reason)
- )
- or
+ /**
+ * Holds if `comp` is a comparison between `x` and `y` for which `y - x` has a
+ * fixed value modulo some `mod > 1`, such that the comparison can be
+ * strengthened by `strengthen` when evaluating to `testIsTrue`.
+ */
+ private predicate modulusComparison(SemRelationalExpr comp, boolean testIsTrue, int strengthen) {
exists(
- SemConditionalExpr cond, int d1, int d2, boolean fbe1, boolean fbe2, int od1, int od2,
- SemReason r1, SemReason r2
+ SemBound b, int v1, int v2, int mod1, int mod2, int mod, boolean resultIsStrict, int d, int k
|
- cond = e and
- boundedConditionalExpr(cond, b, upper, true, d1, fbe1, od1, r1) and
- boundedConditionalExpr(cond, b, upper, false, d2, fbe2, od2, r2) and
+ // If `x <= y` and `x =(mod) b + v1` and `y =(mod) b + v2` then
+ // `0 <= y - x =(mod) v2 - v1`. By choosing `k =(mod) v2 - v1` with
+ // `0 <= k < mod` we get `k <= y - x`. If the resulting comparison is
+ // strict then the strengthening amount is instead `k - 1` modulo `mod`:
+ // `x < y` means `0 <= y - x - 1 =(mod) k - 1` so `k - 1 <= y - x - 1` and
+ // thus `k - 1 < y - x` with `0 <= k - 1 < mod`.
+ semExprModulus(comp.getLesserOperand(), b, v1, mod1) and
+ semExprModulus(comp.getGreaterOperand(), b, v2, mod2) and
+ mod = mod1.gcd(mod2) and
+ mod != 1 and
+ (testIsTrue = true or testIsTrue = false) and
(
- delta = d1 and fromBackEdge = fbe1 and origdelta = od1 and reason = r1
+ if comp.isStrict()
+ then resultIsStrict = testIsTrue
+ else resultIsStrict = testIsTrue.booleanNot()
+ ) and
+ (
+ resultIsStrict = true and d = 1
or
- delta = d2 and fromBackEdge = fbe2 and origdelta = od2 and reason = r2
- )
- |
- upper = true and delta = d1.maximum(d2)
- or
- upper = false and delta = d1.minimum(d2)
+ resultIsStrict = false and d = 0
+ ) and
+ (
+ testIsTrue = true and k = v2 - v1
+ or
+ testIsTrue = false and k = v1 - v2
+ ) and
+ strengthen = (((k - d) % mod) + mod) % mod
)
- )
-}
+ }
-private predicate boundedConditionalExpr(
- SemConditionalExpr cond, SemBound b, boolean upper, boolean branch, int delta,
- boolean fromBackEdge, int origdelta, SemReason reason
-) {
- bounded(cond.getBranchExpr(branch), b, delta, upper, fromBackEdge, origdelta, reason)
+ /**
+ * Gets a condition that tests whether `v` is bounded by `e + delta`.
+ *
+ * If the condition evaluates to `testIsTrue`:
+ * - `upper = true` : `v <= e + delta`
+ * - `upper = false` : `v >= e + delta`
+ */
+ private SemGuard boundFlowCond(
+ SemSsaVariable v, SemExpr e, int delta, boolean upper, boolean testIsTrue
+ ) {
+ exists(
+ SemRelationalExpr comp, int d1, int d2, int d3, int strengthen, boolean compIsUpper,
+ boolean resultIsStrict
+ |
+ comp = result.asExpr() and
+ boundCondition(comp, v, e, d1, compIsUpper) and
+ (testIsTrue = true or testIsTrue = false) and
+ upper = compIsUpper.booleanXor(testIsTrue.booleanNot()) and
+ (
+ if comp.isStrict()
+ then resultIsStrict = testIsTrue
+ else resultIsStrict = testIsTrue.booleanNot()
+ ) and
+ (
+ if
+ getTrackedTypeForSsaVariable(v) instanceof SemIntegerType or
+ getTrackedTypeForSsaVariable(v) instanceof SemAddressType
+ then
+ upper = true and strengthen = -1
+ or
+ upper = false and strengthen = 1
+ else strengthen = 0
+ ) and
+ (
+ exists(int k | modulusComparison(comp, testIsTrue, k) and d2 = strengthen * k)
+ or
+ not modulusComparison(comp, testIsTrue, _) and d2 = 0
+ ) and
+ // A strict inequality `x < y` can be strengthened to `x <= y - 1`.
+ (
+ resultIsStrict = true and d3 = strengthen
+ or
+ resultIsStrict = false and d3 = 0
+ ) and
+ delta = d1 + d2 + d3
+ )
+ or
+ exists(boolean testIsTrue0 |
+ semImplies_v2(result, testIsTrue, boundFlowCond(v, e, delta, upper, testIsTrue0), testIsTrue0)
+ )
+ or
+ result = semEqFlowCond(v, e, delta, true, testIsTrue) and
+ (upper = true or upper = false)
+ or
+ // guard that tests whether `v2` is bounded by `e + delta + d1 - d2` and
+ // exists a guard `guardEq` such that `v = v2 - d1 + d2`.
+ exists(SemSsaVariable v2, SemGuard guardEq, boolean eqIsTrue, int d1, int d2 |
+ guardEq = semEqFlowCond(v, semSsaRead(v2, d1), d2, true, eqIsTrue) and
+ result = boundFlowCond(v2, e, delta + d1 - d2, upper, testIsTrue) and
+ // guardEq needs to control guard
+ guardEq.directlyControls(result.getBasicBlock(), eqIsTrue)
+ )
+ }
+
+ private newtype TSemReason =
+ TSemNoReason() or
+ TSemCondReason(SemGuard guard) { possibleReason(guard) }
+
+ /**
+ * A reason for an inferred bound. This can either be `CondReason` if the bound
+ * is due to a specific condition, or `NoReason` if the bound is inferred
+ * without going through a bounding condition.
+ */
+ abstract class SemReason extends TSemReason {
+ /** Gets a textual representation of this reason. */
+ abstract string toString();
+ }
+
+ /**
+ * A reason for an inferred bound that indicates that the bound is inferred
+ * without going through a bounding condition.
+ */
+ class SemNoReason extends SemReason, TSemNoReason {
+ override string toString() { result = "NoReason" }
+ }
+
+ /** A reason for an inferred bound pointing to a condition. */
+ class SemCondReason extends SemReason, TSemCondReason {
+ /** Gets the condition that is the reason for the bound. */
+ SemGuard getCond() { this = TSemCondReason(result) }
+
+ override string toString() { result = getCond().toString() }
+ }
+
+ /**
+ * Holds if `e + delta` is a valid bound for `v` at `pos`.
+ * - `upper = true` : `v <= e + delta`
+ * - `upper = false` : `v >= e + delta`
+ */
+ private predicate boundFlowStepSsa(
+ SemSsaVariable v, SemSsaReadPosition pos, SemExpr e, int delta, boolean upper, SemReason reason
+ ) {
+ semSsaUpdateStep(v, e, delta) and
+ pos.hasReadOfVar(v) and
+ (upper = true or upper = false) and
+ reason = TSemNoReason()
+ or
+ exists(SemGuard guard, boolean testIsTrue |
+ pos.hasReadOfVar(v) and
+ guard = boundFlowCond(v, e, delta, upper, testIsTrue) and
+ semGuardDirectlyControlsSsaRead(guard, pos, testIsTrue) and
+ reason = TSemCondReason(guard)
+ )
+ }
+
+ /** Holds if `v != e + delta` at `pos` and `v` is of integral type. */
+ private predicate unequalFlowStepIntegralSsa(
+ SemSsaVariable v, SemSsaReadPosition pos, SemExpr e, int delta, SemReason reason
+ ) {
+ getTrackedTypeForSsaVariable(v) instanceof SemIntegerType and
+ exists(SemGuard guard, boolean testIsTrue |
+ pos.hasReadOfVar(v) and
+ guard = semEqFlowCond(v, e, delta, false, testIsTrue) and
+ semGuardDirectlyControlsSsaRead(guard, pos, testIsTrue) and
+ reason = TSemCondReason(guard)
+ )
+ }
+
+ /** Holds if `e >= 1` as determined by sign analysis. */
+ private predicate strictlyPositiveIntegralExpr(SemExpr e) {
+ semStrictlyPositive(e) and getTrackedType(e) instanceof SemIntegerType
+ }
+
+ /** Holds if `e <= -1` as determined by sign analysis. */
+ private predicate strictlyNegativeIntegralExpr(SemExpr e) {
+ semStrictlyNegative(e) and getTrackedType(e) instanceof SemIntegerType
+ }
+
+ /**
+ * Holds if `e1 + delta` is a valid bound for `e2`.
+ * - `upper = true` : `e2 <= e1 + delta`
+ * - `upper = false` : `e2 >= e1 + delta`
+ */
+ private predicate boundFlowStep(SemExpr e2, SemExpr e1, int delta, boolean upper) {
+ semValueFlowStep(e2, e1, delta) and
+ (upper = true or upper = false)
+ or
+ e2.(SafeCastExpr).getOperand() = e1 and
+ delta = 0 and
+ (upper = true or upper = false)
+ or
+ exists(SemExpr x | e2.(SemAddExpr).hasOperands(e1, x) |
+ // `x instanceof ConstantIntegerExpr` is covered by valueFlowStep
+ not x instanceof SemConstantIntegerExpr and
+ not e1 instanceof SemConstantIntegerExpr and
+ if strictlyPositiveIntegralExpr(x)
+ then upper = false and delta = 1
+ else
+ if semPositive(x)
+ then upper = false and delta = 0
+ else
+ if strictlyNegativeIntegralExpr(x)
+ then upper = true and delta = -1
+ else
+ if semNegative(x)
+ then upper = true and delta = 0
+ else none()
+ )
+ or
+ exists(SemExpr x, SemSubExpr sub |
+ e2 = sub and
+ sub.getLeftOperand() = e1 and
+ sub.getRightOperand() = x
+ |
+ // `x instanceof ConstantIntegerExpr` is covered by valueFlowStep
+ not x instanceof SemConstantIntegerExpr and
+ if strictlyPositiveIntegralExpr(x)
+ then upper = true and delta = -1
+ else
+ if semPositive(x)
+ then upper = true and delta = 0
+ else
+ if strictlyNegativeIntegralExpr(x)
+ then upper = false and delta = 1
+ else
+ if semNegative(x)
+ then upper = false and delta = 0
+ else none()
+ )
+ or
+ e2.(SemRemExpr).getRightOperand() = e1 and
+ semPositive(e1) and
+ delta = -1 and
+ upper = true
+ or
+ e2.(SemRemExpr).getLeftOperand() = e1 and semPositive(e1) and delta = 0 and upper = true
+ or
+ e2.(SemBitAndExpr).getAnOperand() = e1 and
+ semPositive(e1) and
+ delta = 0 and
+ upper = true
+ or
+ e2.(SemBitOrExpr).getAnOperand() = e1 and
+ semPositive(e2) and
+ delta = 0 and
+ upper = false
+ or
+ Specific::hasBound(e2, e1, delta, upper)
+ }
+
+ /** Holds if `e2 = e1 * factor` and `factor > 0`. */
+ private predicate boundFlowStepMul(SemExpr e2, SemExpr e1, int factor) {
+ exists(SemConstantIntegerExpr c, int k | k = c.getIntValue() and k > 0 |
+ e2.(SemMulExpr).hasOperands(e1, c) and factor = k
+ or
+ exists(SemShiftLeftExpr e |
+ e = e2 and e.getLeftOperand() = e1 and e.getRightOperand() = c and factor = 2.pow(k)
+ )
+ )
+ }
+
+ /**
+ * Holds if `e2 = e1 / factor` and `factor > 0`.
+ *
+ * This conflates division, right shift, and unsigned right shift and is
+ * therefore only valid for non-negative numbers.
+ */
+ private predicate boundFlowStepDiv(SemExpr e2, SemExpr e1, int factor) {
+ exists(SemConstantIntegerExpr c, int k | k = c.getIntValue() and k > 0 |
+ exists(SemDivExpr e |
+ e = e2 and e.getLeftOperand() = e1 and e.getRightOperand() = c and factor = k
+ )
+ or
+ exists(SemShiftRightExpr e |
+ e = e2 and e.getLeftOperand() = e1 and e.getRightOperand() = c and factor = 2.pow(k)
+ )
+ or
+ exists(SemShiftRightUnsignedExpr e |
+ e = e2 and e.getLeftOperand() = e1 and e.getRightOperand() = c and factor = 2.pow(k)
+ )
+ )
+ }
+
+ /**
+ * Holds if `b + delta` is a valid bound for `v` at `pos`.
+ * - `upper = true` : `v <= b + delta`
+ * - `upper = false` : `v >= b + delta`
+ */
+ private predicate boundedSsa(
+ SemSsaVariable v, SemSsaReadPosition pos, SemBound b, int delta, boolean upper,
+ boolean fromBackEdge, int origdelta, SemReason reason
+ ) {
+ exists(SemExpr mid, int d1, int d2, SemReason r1, SemReason r2 |
+ boundFlowStepSsa(v, pos, mid, d1, upper, r1) and
+ bounded(mid, b, d2, upper, fromBackEdge, origdelta, r2) and
+ // upper = true: v <= mid + d1 <= b + d1 + d2 = b + delta
+ // upper = false: v >= mid + d1 >= b + d1 + d2 = b + delta
+ delta = d1 + d2 and
+ (if r1 instanceof SemNoReason then reason = r2 else reason = r1)
+ )
+ or
+ exists(int d, SemReason r1, SemReason r2 |
+ boundedSsa(v, pos, b, d, upper, fromBackEdge, origdelta, r2) or
+ boundedPhi(v, b, d, upper, fromBackEdge, origdelta, r2)
+ |
+ unequalIntegralSsa(v, pos, b, d, r1) and
+ (
+ upper = true and delta = d - 1
+ or
+ upper = false and delta = d + 1
+ ) and
+ (
+ reason = r1
+ or
+ reason = r2 and not r2 instanceof SemNoReason
+ )
+ )
+ }
+
+ /**
+ * Holds if `v != b + delta` at `pos` and `v` is of integral type.
+ */
+ private predicate unequalIntegralSsa(
+ SemSsaVariable v, SemSsaReadPosition pos, SemBound b, int delta, SemReason reason
+ ) {
+ exists(SemExpr e, int d1, int d2 |
+ unequalFlowStepIntegralSsa(v, pos, e, d1, reason) and
+ boundedUpper(e, b, d1) and
+ boundedLower(e, b, d2) and
+ delta = d2 + d1
+ )
+ }
+
+ /**
+ * Holds if `b + delta` is an upper bound for `e`.
+ *
+ * This predicate only exists to prevent a bad standard order in `unequalIntegralSsa`.
+ */
+ pragma[nomagic]
+ private predicate boundedUpper(SemExpr e, SemBound b, int delta) {
+ bounded(e, b, delta, true, _, _, _)
+ }
+
+ /**
+ * Holds if `b + delta` is a lower bound for `e`.
+ *
+ * This predicate only exists to prevent a bad standard order in `unequalIntegralSsa`.
+ */
+ pragma[nomagic]
+ private predicate boundedLower(SemExpr e, SemBound b, int delta) {
+ bounded(e, b, delta, false, _, _, _)
+ }
+
+ /** Weakens a delta to lie in the range `[-1..1]`. */
+ bindingset[delta, upper]
+ private int weakenDelta(boolean upper, int delta) {
+ delta in [-1 .. 1] and result = delta
+ or
+ upper = true and result = -1 and delta < -1
+ or
+ upper = false and result = 1 and delta > 1
+ }
+
+ /**
+ * Holds if `b + delta` is a valid bound for `inp` when used as an input to
+ * `phi` along `edge`.
+ * - `upper = true` : `inp <= b + delta`
+ * - `upper = false` : `inp >= b + delta`
+ */
+ private predicate boundedPhiInp(
+ SemSsaPhiNode phi, SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge, SemBound b,
+ int delta, boolean upper, boolean fromBackEdge, int origdelta, SemReason reason
+ ) {
+ edge.phiInput(phi, inp) and
+ exists(int d, boolean fromBackEdge0 |
+ boundedSsa(inp, edge, b, d, upper, fromBackEdge0, origdelta, reason)
+ or
+ boundedPhi(inp, b, d, upper, fromBackEdge0, origdelta, reason)
+ or
+ b.(SemSsaBound).getAVariable() = inp and
+ d = 0 and
+ (upper = true or upper = false) and
+ fromBackEdge0 = false and
+ origdelta = 0 and
+ reason = TSemNoReason()
+ |
+ if semBackEdge(phi, inp, edge)
+ then
+ fromBackEdge = true and
+ (
+ fromBackEdge0 = true and delta = weakenDelta(upper, d - origdelta) + origdelta
+ or
+ fromBackEdge0 = false and delta = d
+ )
+ else (
+ delta = d and fromBackEdge = fromBackEdge0
+ )
+ )
+ }
+
+ /**
+ * Holds if `b + delta` is a valid bound for `inp` when used as an input to
+ * `phi` along `edge`.
+ * - `upper = true` : `inp <= b + delta`
+ * - `upper = false` : `inp >= b + delta`
+ *
+ * Equivalent to `boundedPhiInp(phi, inp, edge, b, delta, upper, _, _, _)`.
+ */
+ pragma[noinline]
+ private predicate boundedPhiInp1(
+ SemSsaPhiNode phi, SemBound b, boolean upper, SemSsaVariable inp,
+ SemSsaReadPositionPhiInputEdge edge, int delta
+ ) {
+ boundedPhiInp(phi, inp, edge, b, delta, upper, _, _, _)
+ }
+
+ /**
+ * Holds if `phi` is a valid bound for `inp` when used as an input to `phi`
+ * along `edge`.
+ * - `upper = true` : `inp <= phi`
+ * - `upper = false` : `inp >= phi`
+ */
+ private predicate selfBoundedPhiInp(
+ SemSsaPhiNode phi, SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge, boolean upper
+ ) {
+ exists(int d, SemSsaBound phibound |
+ phibound.getAVariable() = phi and
+ boundedPhiInp(phi, inp, edge, phibound, d, upper, _, _, _) and
+ (
+ upper = true and d <= 0
+ or
+ upper = false and d >= 0
+ )
+ )
+ }
+
+ /**
+ * Holds if `b + delta` is a valid bound for some input, `inp`, to `phi`, and
+ * thus a candidate bound for `phi`.
+ * - `upper = true` : `inp <= b + delta`
+ * - `upper = false` : `inp >= b + delta`
+ */
+ pragma[noinline]
+ private predicate boundedPhiCand(
+ SemSsaPhiNode phi, boolean upper, SemBound b, int delta, boolean fromBackEdge, int origdelta,
+ SemReason reason
+ ) {
+ exists(SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge |
+ boundedPhiInp(phi, inp, edge, b, delta, upper, fromBackEdge, origdelta, reason)
+ )
+ }
+
+ /**
+ * Holds if the candidate bound `b + delta` for `phi` is valid for the phi input
+ * `inp` along `edge`.
+ */
+ private predicate boundedPhiCandValidForEdge(
+ SemSsaPhiNode phi, SemBound b, int delta, boolean upper, boolean fromBackEdge, int origdelta,
+ SemReason reason, SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge
+ ) {
+ boundedPhiCand(phi, upper, b, delta, fromBackEdge, origdelta, reason) and
+ (
+ exists(int d | boundedPhiInp1(phi, b, upper, inp, edge, d) | upper = true and d <= delta)
+ or
+ exists(int d | boundedPhiInp1(phi, b, upper, inp, edge, d) | upper = false and d >= delta)
+ or
+ selfBoundedPhiInp(phi, inp, edge, upper)
+ )
+ }
+
+ /**
+ * Holds if `b + delta` is a valid bound for `phi`.
+ * - `upper = true` : `phi <= b + delta`
+ * - `upper = false` : `phi >= b + delta`
+ */
+ private predicate boundedPhi(
+ SemSsaPhiNode phi, SemBound b, int delta, boolean upper, boolean fromBackEdge, int origdelta,
+ SemReason reason
+ ) {
+ forex(SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge | edge.phiInput(phi, inp) |
+ boundedPhiCandValidForEdge(phi, b, delta, upper, fromBackEdge, origdelta, reason, inp, edge)
+ )
+ }
+
+ /**
+ * Holds if `e` has an upper (for `upper = true`) or lower
+ * (for `upper = false`) bound of `b`.
+ */
+ private predicate baseBound(SemExpr e, int b, boolean upper) {
+ Specific::hasConstantBound(e, b, upper)
+ or
+ upper = false and
+ b = 0 and
+ semPositive(e.(SemBitAndExpr).getAnOperand()) and
+ // REVIEW: We let the language opt out here to preserve original results.
+ not Specific::ignoreZeroLowerBound(e)
+ }
+
+ /**
+ * Holds if the value being cast has an upper (for `upper = true`) or lower
+ * (for `upper = false`) bound within the bounds of the resulting type.
+ * For `upper = true` this means that the cast will not overflow and for
+ * `upper = false` this means that the cast will not underflow.
+ */
+ private predicate safeNarrowingCast(NarrowingCastExpr cast, boolean upper) {
+ exists(int bound | bounded(cast.getOperand(), any(SemZeroBound zb), bound, upper, _, _, _) |
+ upper = true and bound <= cast.getUpperBound()
+ or
+ upper = false and bound >= cast.getLowerBound()
+ )
+ }
+
+ pragma[noinline]
+ private predicate boundedCastExpr(
+ NarrowingCastExpr cast, SemBound b, int delta, boolean upper, boolean fromBackEdge,
+ int origdelta, SemReason reason
+ ) {
+ bounded(cast.getOperand(), b, delta, upper, fromBackEdge, origdelta, reason)
+ }
+
+ /**
+ * Holds if `b + delta` is a valid bound for `e`.
+ * - `upper = true` : `e <= b + delta`
+ * - `upper = false` : `e >= b + delta`
+ */
+ private predicate bounded(
+ SemExpr e, SemBound b, int delta, boolean upper, boolean fromBackEdge, int origdelta,
+ SemReason reason
+ ) {
+ not Specific::ignoreExprBound(e) and
+ (
+ e = b.getExpr(delta) and
+ (upper = true or upper = false) and
+ fromBackEdge = false and
+ origdelta = delta and
+ reason = TSemNoReason()
+ or
+ baseBound(e, delta, upper) and
+ b instanceof SemZeroBound and
+ fromBackEdge = false and
+ origdelta = delta and
+ reason = TSemNoReason()
+ or
+ exists(SemSsaVariable v, SemSsaReadPositionBlock bb |
+ boundedSsa(v, bb, b, delta, upper, fromBackEdge, origdelta, reason) and
+ e = v.getAUse() and
+ bb.getBlock() = e.getBasicBlock()
+ )
+ or
+ exists(SemExpr mid, int d1, int d2 |
+ boundFlowStep(e, mid, d1, upper) and
+ // Constants have easy, base-case bounds, so let's not infer any recursive bounds.
+ not e instanceof SemConstantIntegerExpr and
+ bounded(mid, b, d2, upper, fromBackEdge, origdelta, reason) and
+ // upper = true: e <= mid + d1 <= b + d1 + d2 = b + delta
+ // upper = false: e >= mid + d1 >= b + d1 + d2 = b + delta
+ delta = d1 + d2
+ )
+ or
+ exists(SemSsaPhiNode phi |
+ boundedPhi(phi, b, delta, upper, fromBackEdge, origdelta, reason) and
+ e = phi.getAUse()
+ )
+ or
+ exists(SemExpr mid, int factor, int d |
+ boundFlowStepMul(e, mid, factor) and
+ not e instanceof SemConstantIntegerExpr and
+ bounded(mid, b, d, upper, fromBackEdge, origdelta, reason) and
+ b instanceof SemZeroBound and
+ delta = d * factor
+ )
+ or
+ exists(SemExpr mid, int factor, int d |
+ boundFlowStepDiv(e, mid, factor) and
+ not e instanceof SemConstantIntegerExpr and
+ bounded(mid, b, d, upper, fromBackEdge, origdelta, reason) and
+ b instanceof SemZeroBound and
+ d >= 0 and
+ delta = d / factor
+ )
+ or
+ exists(NarrowingCastExpr cast |
+ cast = e and
+ safeNarrowingCast(cast, upper.booleanNot()) and
+ boundedCastExpr(cast, b, delta, upper, fromBackEdge, origdelta, reason)
+ )
+ or
+ exists(
+ SemConditionalExpr cond, int d1, int d2, boolean fbe1, boolean fbe2, int od1, int od2,
+ SemReason r1, SemReason r2
+ |
+ cond = e and
+ boundedConditionalExpr(cond, b, upper, true, d1, fbe1, od1, r1) and
+ boundedConditionalExpr(cond, b, upper, false, d2, fbe2, od2, r2) and
+ (
+ delta = d1 and fromBackEdge = fbe1 and origdelta = od1 and reason = r1
+ or
+ delta = d2 and fromBackEdge = fbe2 and origdelta = od2 and reason = r2
+ )
+ |
+ upper = true and delta = d1.maximum(d2)
+ or
+ upper = false and delta = d1.minimum(d2)
+ )
+ )
+ }
+
+ private predicate boundedConditionalExpr(
+ SemConditionalExpr cond, SemBound b, boolean upper, boolean branch, int delta,
+ boolean fromBackEdge, int origdelta, SemReason reason
+ ) {
+ bounded(cond.getBranchExpr(branch), b, delta, upper, fromBackEdge, origdelta, reason)
+ }
}
From eebada46b1a07a74598be3c346d60b2038343e7c Mon Sep 17 00:00:00 2001
From: Robert Marsh
Date: Tue, 13 Dec 2022 11:46:42 -0500
Subject: [PATCH 245/381] C++: rename to RagneAnalysisStage.qll
---
.../analysis/{RangeAnalysis.qll => RangeAnalysisStage.qll} | 0
1 file changed, 0 insertions(+), 0 deletions(-)
rename cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/{RangeAnalysis.qll => RangeAnalysisStage.qll} (100%)
diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysis.qll b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisStage.qll
similarity index 100%
rename from cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysis.qll
rename to cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisStage.qll
From b8c43d7a71302f5cdebe3cc044deef13ca6fa346 Mon Sep 17 00:00:00 2001
From: Robert Marsh
Date: Wed, 14 Dec 2022 16:32:31 -0500
Subject: [PATCH 246/381] C++: convert RangeAnalysis to float
---
.../semantic/analysis/RangeAnalysisStage.qll | 184 +++++++++++-------
1 file changed, 110 insertions(+), 74 deletions(-)
diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisStage.qll b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisStage.qll
index 63f2ebe5fa5..df49be67643 100644
--- a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisStage.qll
+++ b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisStage.qll
@@ -64,13 +64,12 @@
*/
private import RangeAnalysisSpecific as Specific
-private import RangeUtils
+private import RangeUtils as Utils
private import SignAnalysisCommon
private import ModulusAnalysis
private import experimental.semmle.code.cpp.semantic.Semantic
private import ConstantAnalysis
-
/**
* An expression that does conversion, boxing, or unboxing
*/
@@ -89,8 +88,8 @@ private class ConvertOrBoxExpr extends SemUnaryExpr {
*/
private class SafeCastExpr extends ConvertOrBoxExpr {
SafeCastExpr() {
- conversionCannotOverflow(getTrackedType(pragma[only_bind_into](getOperand())),
- getTrackedType(this))
+ conversionCannotOverflow(Utils::getTrackedType(pragma[only_bind_into](getOperand())),
+ Utils::getTrackedType(this))
}
}
@@ -119,19 +118,49 @@ private predicate typeBound(SemIntegerType typ, int lowerbound, int upperbound)
private class NarrowingCastExpr extends ConvertOrBoxExpr {
NarrowingCastExpr() {
not this instanceof SafeCastExpr and
- typeBound(getTrackedType(this), _, _)
+ typeBound(Utils::getTrackedType(this), _, _)
}
/** Gets the lower bound of the resulting type. */
- int getLowerBound() { typeBound(getTrackedType(this), result, _) }
+ int getLowerBound() { typeBound(Utils::getTrackedType(this), result, _) }
/** Gets the upper bound of the resulting type. */
- int getUpperBound() { typeBound(getTrackedType(this), _, result) }
+ int getUpperBound() { typeBound(Utils::getTrackedType(this), _, result) }
}
-signature module RangeSig { }
+signature module DeltaSig {
+ class Delta;
-module RangeStage {
+ bindingset[d]
+ bindingset[result]
+ float toFloat(Delta d);
+
+ bindingset[d]
+ bindingset[result]
+ int toInt(Delta d);
+
+ bindingset[n]
+ bindingset[result]
+ Delta fromInt(int n);
+
+ bindingset[f]
+ bindingset[result]
+ Delta fromFloat(float f);
+}
+
+signature module UtilSig {
+ SemExpr semSsaRead(SemSsaVariable v, DeltaParam::Delta delta);
+
+ SemGuard semEqFlowCond(
+ SemSsaVariable v, SemExpr e, DeltaParam::Delta delta, boolean isEq, boolean testIsTrue
+ );
+
+ predicate semSsaUpdateStep(SemSsaExplicitUpdate v, SemExpr e, DeltaParam::Delta delta);
+
+ predicate semValueFlowStep(SemExpr e2, SemExpr e1, DeltaParam::Delta delta);
+}
+
+module RangeStage UtilParam> {
cached
private module RangeAnalysisCache {
cached
@@ -146,7 +175,7 @@ module RangeStage {
* condition.
*/
cached
- predicate semBounded(SemExpr e, SemBound b, int delta, boolean upper, SemReason reason) {
+ predicate semBounded(SemExpr e, SemBound b, float delta, boolean upper, SemReason reason) {
bounded(e, b, delta, upper, _, _, reason) and
bestBound(e, b, delta, upper)
}
@@ -157,7 +186,7 @@ module RangeStage {
*/
cached
predicate possibleReason(SemGuard guard) {
- guard = boundFlowCond(_, _, _, _, _) or guard = semEqFlowCond(_, _, _, _, _)
+ guard = boundFlowCond(_, _, _, _, _) or guard = UtilParam::semEqFlowCond(_, _, _, _, _)
}
}
@@ -169,10 +198,12 @@ module RangeStage {
* - `upper = true` : `e <= b + delta`
* - `upper = false` : `e >= b + delta`
*/
- private predicate bestBound(SemExpr e, SemBound b, int delta, boolean upper) {
- delta = min(int d | bounded(e, b, d, upper, _, _, _)) and upper = true
+ private predicate bestBound(SemExpr e, SemBound b, float delta, boolean upper) {
+ delta = min(float d | bounded(e, b, d, upper, _, _, _)) and
+ upper = true
or
- delta = max(int d | bounded(e, b, d, upper, _, _, _)) and upper = false
+ delta = max(float d | bounded(e, b, d, upper, _, _, _)) and
+ upper = false
}
/**
@@ -181,19 +212,21 @@ module RangeStage {
* - `upper = false` : `v >= e + delta` or `v > e + delta`
*/
private predicate boundCondition(
- SemRelationalExpr comp, SemSsaVariable v, SemExpr e, int delta, boolean upper
+ SemRelationalExpr comp, SemSsaVariable v, SemExpr e, float delta, boolean upper
) {
- comp.getLesserOperand() = semSsaRead(v, delta) and e = comp.getGreaterOperand() and upper = true
+ comp.getLesserOperand() = UtilParam::semSsaRead(v, D::fromFloat(delta)) and
+ e = comp.getGreaterOperand() and
+ upper = true
or
- comp.getGreaterOperand() = semSsaRead(v, delta) and
+ comp.getGreaterOperand() = UtilParam::semSsaRead(v, D::fromFloat(delta)) and
e = comp.getLesserOperand() and
upper = false
or
- exists(SemSubExpr sub, SemConstantIntegerExpr c, int d |
+ exists(SemSubExpr sub, SemConstantIntegerExpr c, float d |
// (v - d) - e < c
comp.getLesserOperand() = sub and
comp.getGreaterOperand() = c and
- sub.getLeftOperand() = semSsaRead(v, d) and
+ sub.getLeftOperand() = UtilParam::semSsaRead(v, D::fromFloat(d)) and
sub.getRightOperand() = e and
upper = true and
delta = d + c.getIntValue()
@@ -201,7 +234,7 @@ module RangeStage {
// (v - d) - e > c
comp.getGreaterOperand() = sub and
comp.getLesserOperand() = c and
- sub.getLeftOperand() = semSsaRead(v, d) and
+ sub.getLeftOperand() = UtilParam::semSsaRead(v, D::fromFloat(d)) and
sub.getRightOperand() = e and
upper = false and
delta = d + c.getIntValue()
@@ -210,7 +243,7 @@ module RangeStage {
comp.getLesserOperand() = sub and
comp.getGreaterOperand() = c and
sub.getLeftOperand() = e and
- sub.getRightOperand() = semSsaRead(v, d) and
+ sub.getRightOperand() = UtilParam::semSsaRead(v, D::fromFloat(d)) and
upper = false and
delta = d - c.getIntValue()
or
@@ -218,7 +251,7 @@ module RangeStage {
comp.getGreaterOperand() = sub and
comp.getLesserOperand() = c and
sub.getLeftOperand() = e and
- sub.getRightOperand() = semSsaRead(v, d) and
+ sub.getRightOperand() = UtilParam::semSsaRead(v, D::fromFloat(d)) and
upper = true and
delta = d - c.getIntValue()
)
@@ -271,10 +304,10 @@ module RangeStage {
* - `upper = false` : `v >= e + delta`
*/
private SemGuard boundFlowCond(
- SemSsaVariable v, SemExpr e, int delta, boolean upper, boolean testIsTrue
+ SemSsaVariable v, SemExpr e, float delta, boolean upper, boolean testIsTrue
) {
exists(
- SemRelationalExpr comp, int d1, int d2, int d3, int strengthen, boolean compIsUpper,
+ SemRelationalExpr comp, float d1, float d2, float d3, int strengthen, boolean compIsUpper,
boolean resultIsStrict
|
comp = result.asExpr() and
@@ -288,8 +321,8 @@ module RangeStage {
) and
(
if
- getTrackedTypeForSsaVariable(v) instanceof SemIntegerType or
- getTrackedTypeForSsaVariable(v) instanceof SemAddressType
+ Utils::getTrackedTypeForSsaVariable(v) instanceof SemIntegerType or
+ Utils::getTrackedTypeForSsaVariable(v) instanceof SemAddressType
then
upper = true and strengthen = -1
or
@@ -314,13 +347,15 @@ module RangeStage {
semImplies_v2(result, testIsTrue, boundFlowCond(v, e, delta, upper, testIsTrue0), testIsTrue0)
)
or
- result = semEqFlowCond(v, e, delta, true, testIsTrue) and
+ result = UtilParam::semEqFlowCond(v, e, D::fromFloat(delta), true, testIsTrue) and
(upper = true or upper = false)
or
// guard that tests whether `v2` is bounded by `e + delta + d1 - d2` and
// exists a guard `guardEq` such that `v = v2 - d1 + d2`.
- exists(SemSsaVariable v2, SemGuard guardEq, boolean eqIsTrue, int d1, int d2 |
- guardEq = semEqFlowCond(v, semSsaRead(v2, d1), d2, true, eqIsTrue) and
+ exists(SemSsaVariable v2, SemGuard guardEq, boolean eqIsTrue, float d1, float d2 |
+ guardEq =
+ UtilParam::semEqFlowCond(v, UtilParam::semSsaRead(v2, D::fromFloat(d1)), D::fromFloat(d2),
+ true, eqIsTrue) and
result = boundFlowCond(v2, e, delta + d1 - d2, upper, testIsTrue) and
// guardEq needs to control guard
guardEq.directlyControls(result.getBasicBlock(), eqIsTrue)
@@ -363,9 +398,10 @@ module RangeStage {
* - `upper = false` : `v >= e + delta`
*/
private predicate boundFlowStepSsa(
- SemSsaVariable v, SemSsaReadPosition pos, SemExpr e, int delta, boolean upper, SemReason reason
+ SemSsaVariable v, SemSsaReadPosition pos, SemExpr e, float delta, boolean upper,
+ SemReason reason
) {
- semSsaUpdateStep(v, e, delta) and
+ UtilParam::semSsaUpdateStep(v, e, D::fromFloat(delta)) and
pos.hasReadOfVar(v) and
(upper = true or upper = false) and
reason = TSemNoReason()
@@ -380,12 +416,12 @@ module RangeStage {
/** Holds if `v != e + delta` at `pos` and `v` is of integral type. */
private predicate unequalFlowStepIntegralSsa(
- SemSsaVariable v, SemSsaReadPosition pos, SemExpr e, int delta, SemReason reason
+ SemSsaVariable v, SemSsaReadPosition pos, SemExpr e, float delta, SemReason reason
) {
- getTrackedTypeForSsaVariable(v) instanceof SemIntegerType and
+ Utils::getTrackedTypeForSsaVariable(v) instanceof SemIntegerType and
exists(SemGuard guard, boolean testIsTrue |
pos.hasReadOfVar(v) and
- guard = semEqFlowCond(v, e, delta, false, testIsTrue) and
+ guard = UtilParam::semEqFlowCond(v, e, D::fromFloat(delta), false, testIsTrue) and
semGuardDirectlyControlsSsaRead(guard, pos, testIsTrue) and
reason = TSemCondReason(guard)
)
@@ -393,12 +429,12 @@ module RangeStage {
/** Holds if `e >= 1` as determined by sign analysis. */
private predicate strictlyPositiveIntegralExpr(SemExpr e) {
- semStrictlyPositive(e) and getTrackedType(e) instanceof SemIntegerType
+ semStrictlyPositive(e) and Utils::getTrackedType(e) instanceof SemIntegerType
}
/** Holds if `e <= -1` as determined by sign analysis. */
private predicate strictlyNegativeIntegralExpr(SemExpr e) {
- semStrictlyNegative(e) and getTrackedType(e) instanceof SemIntegerType
+ semStrictlyNegative(e) and Utils::getTrackedType(e) instanceof SemIntegerType
}
/**
@@ -406,8 +442,8 @@ module RangeStage {
* - `upper = true` : `e2 <= e1 + delta`
* - `upper = false` : `e2 >= e1 + delta`
*/
- private predicate boundFlowStep(SemExpr e2, SemExpr e1, int delta, boolean upper) {
- semValueFlowStep(e2, e1, delta) and
+ private predicate boundFlowStep(SemExpr e2, SemExpr e1, float delta, boolean upper) {
+ UtilParam::semValueFlowStep(e2, e1, D::fromFloat(delta)) and
(upper = true or upper = false)
or
e2.(SafeCastExpr).getOperand() = e1 and
@@ -474,7 +510,7 @@ module RangeStage {
}
/** Holds if `e2 = e1 * factor` and `factor > 0`. */
- private predicate boundFlowStepMul(SemExpr e2, SemExpr e1, int factor) {
+ private predicate boundFlowStepMul(SemExpr e2, SemExpr e1, float factor) {
exists(SemConstantIntegerExpr c, int k | k = c.getIntValue() and k > 0 |
e2.(SemMulExpr).hasOperands(e1, c) and factor = k
or
@@ -490,8 +526,8 @@ module RangeStage {
* This conflates division, right shift, and unsigned right shift and is
* therefore only valid for non-negative numbers.
*/
- private predicate boundFlowStepDiv(SemExpr e2, SemExpr e1, int factor) {
- exists(SemConstantIntegerExpr c, int k | k = c.getIntValue() and k > 0 |
+ private predicate boundFlowStepDiv(SemExpr e2, SemExpr e1, float factor) {
+ exists(SemConstantIntegerExpr c, float k | k = c.getIntValue() and k > 0 |
exists(SemDivExpr e |
e = e2 and e.getLeftOperand() = e1 and e.getRightOperand() = c and factor = k
)
@@ -512,10 +548,10 @@ module RangeStage {
* - `upper = false` : `v >= b + delta`
*/
private predicate boundedSsa(
- SemSsaVariable v, SemSsaReadPosition pos, SemBound b, int delta, boolean upper,
- boolean fromBackEdge, int origdelta, SemReason reason
+ SemSsaVariable v, SemSsaReadPosition pos, SemBound b, float delta, boolean upper,
+ boolean fromBackEdge, float origdelta, SemReason reason
) {
- exists(SemExpr mid, int d1, int d2, SemReason r1, SemReason r2 |
+ exists(SemExpr mid, float d1, float d2, SemReason r1, SemReason r2 |
boundFlowStepSsa(v, pos, mid, d1, upper, r1) and
bounded(mid, b, d2, upper, fromBackEdge, origdelta, r2) and
// upper = true: v <= mid + d1 <= b + d1 + d2 = b + delta
@@ -524,7 +560,7 @@ module RangeStage {
(if r1 instanceof SemNoReason then reason = r2 else reason = r1)
)
or
- exists(int d, SemReason r1, SemReason r2 |
+ exists(float d, SemReason r1, SemReason r2 |
boundedSsa(v, pos, b, d, upper, fromBackEdge, origdelta, r2) or
boundedPhi(v, b, d, upper, fromBackEdge, origdelta, r2)
|
@@ -546,9 +582,9 @@ module RangeStage {
* Holds if `v != b + delta` at `pos` and `v` is of integral type.
*/
private predicate unequalIntegralSsa(
- SemSsaVariable v, SemSsaReadPosition pos, SemBound b, int delta, SemReason reason
+ SemSsaVariable v, SemSsaReadPosition pos, SemBound b, float delta, SemReason reason
) {
- exists(SemExpr e, int d1, int d2 |
+ exists(SemExpr e, float d1, float d2 |
unequalFlowStepIntegralSsa(v, pos, e, d1, reason) and
boundedUpper(e, b, d1) and
boundedLower(e, b, d2) and
@@ -562,7 +598,7 @@ module RangeStage {
* This predicate only exists to prevent a bad standard order in `unequalIntegralSsa`.
*/
pragma[nomagic]
- private predicate boundedUpper(SemExpr e, SemBound b, int delta) {
+ private predicate boundedUpper(SemExpr e, SemBound b, float delta) {
bounded(e, b, delta, true, _, _, _)
}
@@ -572,13 +608,13 @@ module RangeStage {
* This predicate only exists to prevent a bad standard order in `unequalIntegralSsa`.
*/
pragma[nomagic]
- private predicate boundedLower(SemExpr e, SemBound b, int delta) {
+ private predicate boundedLower(SemExpr e, SemBound b, float delta) {
bounded(e, b, delta, false, _, _, _)
}
/** Weakens a delta to lie in the range `[-1..1]`. */
bindingset[delta, upper]
- private int weakenDelta(boolean upper, int delta) {
+ private float weakenDelta(boolean upper, float delta) {
delta in [-1 .. 1] and result = delta
or
upper = true and result = -1 and delta < -1
@@ -594,10 +630,10 @@ module RangeStage {
*/
private predicate boundedPhiInp(
SemSsaPhiNode phi, SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge, SemBound b,
- int delta, boolean upper, boolean fromBackEdge, int origdelta, SemReason reason
+ float delta, boolean upper, boolean fromBackEdge, float origdelta, SemReason reason
) {
edge.phiInput(phi, inp) and
- exists(int d, boolean fromBackEdge0 |
+ exists(float d, boolean fromBackEdge0 |
boundedSsa(inp, edge, b, d, upper, fromBackEdge0, origdelta, reason)
or
boundedPhi(inp, b, d, upper, fromBackEdge0, origdelta, reason)
@@ -634,7 +670,7 @@ module RangeStage {
pragma[noinline]
private predicate boundedPhiInp1(
SemSsaPhiNode phi, SemBound b, boolean upper, SemSsaVariable inp,
- SemSsaReadPositionPhiInputEdge edge, int delta
+ SemSsaReadPositionPhiInputEdge edge, float delta
) {
boundedPhiInp(phi, inp, edge, b, delta, upper, _, _, _)
}
@@ -648,7 +684,7 @@ module RangeStage {
private predicate selfBoundedPhiInp(
SemSsaPhiNode phi, SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge, boolean upper
) {
- exists(int d, SemSsaBound phibound |
+ exists(float d, SemSsaBound phibound |
phibound.getAVariable() = phi and
boundedPhiInp(phi, inp, edge, phibound, d, upper, _, _, _) and
(
@@ -667,8 +703,8 @@ module RangeStage {
*/
pragma[noinline]
private predicate boundedPhiCand(
- SemSsaPhiNode phi, boolean upper, SemBound b, int delta, boolean fromBackEdge, int origdelta,
- SemReason reason
+ SemSsaPhiNode phi, boolean upper, SemBound b, float delta, boolean fromBackEdge,
+ float origdelta, SemReason reason
) {
exists(SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge |
boundedPhiInp(phi, inp, edge, b, delta, upper, fromBackEdge, origdelta, reason)
@@ -680,14 +716,14 @@ module RangeStage {
* `inp` along `edge`.
*/
private predicate boundedPhiCandValidForEdge(
- SemSsaPhiNode phi, SemBound b, int delta, boolean upper, boolean fromBackEdge, int origdelta,
- SemReason reason, SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge
+ SemSsaPhiNode phi, SemBound b, float delta, boolean upper, boolean fromBackEdge,
+ float origdelta, SemReason reason, SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge
) {
boundedPhiCand(phi, upper, b, delta, fromBackEdge, origdelta, reason) and
(
- exists(int d | boundedPhiInp1(phi, b, upper, inp, edge, d) | upper = true and d <= delta)
+ exists(float d | boundedPhiInp1(phi, b, upper, inp, edge, d) | upper = true and d <= delta)
or
- exists(int d | boundedPhiInp1(phi, b, upper, inp, edge, d) | upper = false and d >= delta)
+ exists(float d | boundedPhiInp1(phi, b, upper, inp, edge, d) | upper = false and d >= delta)
or
selfBoundedPhiInp(phi, inp, edge, upper)
)
@@ -699,8 +735,8 @@ module RangeStage {
* - `upper = false` : `phi >= b + delta`
*/
private predicate boundedPhi(
- SemSsaPhiNode phi, SemBound b, int delta, boolean upper, boolean fromBackEdge, int origdelta,
- SemReason reason
+ SemSsaPhiNode phi, SemBound b, float delta, boolean upper, boolean fromBackEdge,
+ float origdelta, SemReason reason
) {
forex(SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge | edge.phiInput(phi, inp) |
boundedPhiCandValidForEdge(phi, b, delta, upper, fromBackEdge, origdelta, reason, inp, edge)
@@ -711,7 +747,7 @@ module RangeStage {
* Holds if `e` has an upper (for `upper = true`) or lower
* (for `upper = false`) bound of `b`.
*/
- private predicate baseBound(SemExpr e, int b, boolean upper) {
+ private predicate baseBound(SemExpr e, float b, boolean upper) {
Specific::hasConstantBound(e, b, upper)
or
upper = false and
@@ -728,7 +764,7 @@ module RangeStage {
* `upper = false` this means that the cast will not underflow.
*/
private predicate safeNarrowingCast(NarrowingCastExpr cast, boolean upper) {
- exists(int bound | bounded(cast.getOperand(), any(SemZeroBound zb), bound, upper, _, _, _) |
+ exists(float bound | bounded(cast.getOperand(), any(SemZeroBound zb), bound, upper, _, _, _) |
upper = true and bound <= cast.getUpperBound()
or
upper = false and bound >= cast.getLowerBound()
@@ -737,8 +773,8 @@ module RangeStage {
pragma[noinline]
private predicate boundedCastExpr(
- NarrowingCastExpr cast, SemBound b, int delta, boolean upper, boolean fromBackEdge,
- int origdelta, SemReason reason
+ NarrowingCastExpr cast, SemBound b, float delta, boolean upper, boolean fromBackEdge,
+ float origdelta, SemReason reason
) {
bounded(cast.getOperand(), b, delta, upper, fromBackEdge, origdelta, reason)
}
@@ -749,7 +785,7 @@ module RangeStage {
* - `upper = false` : `e >= b + delta`
*/
private predicate bounded(
- SemExpr e, SemBound b, int delta, boolean upper, boolean fromBackEdge, int origdelta,
+ SemExpr e, SemBound b, float delta, boolean upper, boolean fromBackEdge, float origdelta,
SemReason reason
) {
not Specific::ignoreExprBound(e) and
@@ -772,7 +808,7 @@ module RangeStage {
bb.getBlock() = e.getBasicBlock()
)
or
- exists(SemExpr mid, int d1, int d2 |
+ exists(SemExpr mid, float d1, float d2 |
boundFlowStep(e, mid, d1, upper) and
// Constants have easy, base-case bounds, so let's not infer any recursive bounds.
not e instanceof SemConstantIntegerExpr and
@@ -787,7 +823,7 @@ module RangeStage {
e = phi.getAUse()
)
or
- exists(SemExpr mid, int factor, int d |
+ exists(SemExpr mid, float factor, float d |
boundFlowStepMul(e, mid, factor) and
not e instanceof SemConstantIntegerExpr and
bounded(mid, b, d, upper, fromBackEdge, origdelta, reason) and
@@ -795,7 +831,7 @@ module RangeStage {
delta = d * factor
)
or
- exists(SemExpr mid, int factor, int d |
+ exists(SemExpr mid, float factor, float d |
boundFlowStepDiv(e, mid, factor) and
not e instanceof SemConstantIntegerExpr and
bounded(mid, b, d, upper, fromBackEdge, origdelta, reason) and
@@ -811,8 +847,8 @@ module RangeStage {
)
or
exists(
- SemConditionalExpr cond, int d1, int d2, boolean fbe1, boolean fbe2, int od1, int od2,
- SemReason r1, SemReason r2
+ SemConditionalExpr cond, float d1, float d2, boolean fbe1, boolean fbe2, float od1,
+ float od2, SemReason r1, SemReason r2
|
cond = e and
boundedConditionalExpr(cond, b, upper, true, d1, fbe1, od1, r1) and
@@ -831,8 +867,8 @@ module RangeStage {
}
private predicate boundedConditionalExpr(
- SemConditionalExpr cond, SemBound b, boolean upper, boolean branch, int delta,
- boolean fromBackEdge, int origdelta, SemReason reason
+ SemConditionalExpr cond, SemBound b, boolean upper, boolean branch, float delta,
+ boolean fromBackEdge, float origdelta, SemReason reason
) {
bounded(cond.getBranchExpr(branch), b, delta, upper, fromBackEdge, origdelta, reason)
}
From c10733f9264dadb79154f9b5afb80c73ff7ef9b7 Mon Sep 17 00:00:00 2001
From: Robert Marsh
Date: Thu, 15 Dec 2022 15:27:48 -0500
Subject: [PATCH 247/381] C++: fix float binding issue in range analysis
---
.../cpp/semantic/analysis/RangeAnalysisStage.qll | 15 ++++-----------
1 file changed, 4 insertions(+), 11 deletions(-)
diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisStage.qll b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisStage.qll
index df49be67643..e0b59c3dddf 100644
--- a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisStage.qll
+++ b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisStage.qll
@@ -131,20 +131,12 @@ private class NarrowingCastExpr extends ConvertOrBoxExpr {
signature module DeltaSig {
class Delta;
- bindingset[d]
- bindingset[result]
float toFloat(Delta d);
- bindingset[d]
- bindingset[result]
int toInt(Delta d);
- bindingset[n]
- bindingset[result]
Delta fromInt(int n);
- bindingset[f]
- bindingset[result]
Delta fromFloat(float f);
}
@@ -352,13 +344,14 @@ module RangeStage UtilParam> {
or
// guard that tests whether `v2` is bounded by `e + delta + d1 - d2` and
// exists a guard `guardEq` such that `v = v2 - d1 + d2`.
- exists(SemSsaVariable v2, SemGuard guardEq, boolean eqIsTrue, float d1, float d2 |
+ exists(SemSsaVariable v2, SemGuard guardEq, boolean eqIsTrue, float d1, float d2, float oldDelta |
guardEq =
UtilParam::semEqFlowCond(v, UtilParam::semSsaRead(v2, D::fromFloat(d1)), D::fromFloat(d2),
true, eqIsTrue) and
- result = boundFlowCond(v2, e, delta + d1 - d2, upper, testIsTrue) and
+ result = boundFlowCond(v2, e, oldDelta, upper, testIsTrue) and
// guardEq needs to control guard
- guardEq.directlyControls(result.getBasicBlock(), eqIsTrue)
+ guardEq.directlyControls(result.getBasicBlock(), eqIsTrue) and
+ delta = oldDelta - d1 + d2
)
}
From c062d5e206a1c90333ba23cc9b7abd88bd09700a Mon Sep 17 00:00:00 2001
From: Robert Marsh
Date: Thu, 15 Dec 2022 16:21:32 -0500
Subject: [PATCH 248/381] C++: move language specific predicates to LangParam
---
.../semantic/analysis/RangeAnalysisStage.qll | 63 +++++++++++++------
1 file changed, 45 insertions(+), 18 deletions(-)
diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisStage.qll b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisStage.qll
index e0b59c3dddf..3e5d4ec853c 100644
--- a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisStage.qll
+++ b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisStage.qll
@@ -63,7 +63,6 @@
* back-edge as a precise bound might require traversing a loop once).
*/
-private import RangeAnalysisSpecific as Specific
private import RangeUtils as Utils
private import SignAnalysisCommon
private import ModulusAnalysis
@@ -150,9 +149,35 @@ signature module UtilSig {
predicate semSsaUpdateStep(SemSsaExplicitUpdate v, SemExpr e, DeltaParam::Delta delta);
predicate semValueFlowStep(SemExpr e2, SemExpr e1, DeltaParam::Delta delta);
+
+ /**
+ * Holds if `e >= bound` (if `upper = false`) or `e <= bound` (if `upper = true`).
+ */
+ predicate hasConstantBound(SemExpr e, int bound, boolean upper);
+
+ /**
+ * Holds if `e >= bound + delta` (if `upper = false`) or `e <= bound + delta` (if `upper = true`).
+ */
+ predicate hasBound(SemExpr e, SemExpr bound, int delta, boolean upper);
+
+ /**
+ * Ignore the bound on this expression.
+ *
+ * This predicate is to keep the results identical to the original Java implementation. It should be
+ * removed once we have the new implementation matching the old results exactly.
+ */
+ predicate ignoreExprBound(SemExpr e);
+
+ /**
+ * Ignore any inferred zero lower bound on this expression.
+ *
+ * This predicate is to keep the results identical to the original Java implementation. It should be
+ * removed once we have the new implementation matching the old results exactly.
+ */
+ predicate ignoreZeroLowerBound(SemExpr e);
}
-module RangeStage UtilParam> {
+module RangeStage LangParam> {
cached
private module RangeAnalysisCache {
cached
@@ -178,7 +203,7 @@ module RangeStage UtilParam> {
*/
cached
predicate possibleReason(SemGuard guard) {
- guard = boundFlowCond(_, _, _, _, _) or guard = UtilParam::semEqFlowCond(_, _, _, _, _)
+ guard = boundFlowCond(_, _, _, _, _) or guard = LangParam::semEqFlowCond(_, _, _, _, _)
}
}
@@ -206,11 +231,11 @@ module RangeStage UtilParam> {
private predicate boundCondition(
SemRelationalExpr comp, SemSsaVariable v, SemExpr e, float delta, boolean upper
) {
- comp.getLesserOperand() = UtilParam::semSsaRead(v, D::fromFloat(delta)) and
+ comp.getLesserOperand() = LangParam::semSsaRead(v, D::fromFloat(delta)) and
e = comp.getGreaterOperand() and
upper = true
or
- comp.getGreaterOperand() = UtilParam::semSsaRead(v, D::fromFloat(delta)) and
+ comp.getGreaterOperand() = LangParam::semSsaRead(v, D::fromFloat(delta)) and
e = comp.getLesserOperand() and
upper = false
or
@@ -218,7 +243,7 @@ module RangeStage UtilParam> {
// (v - d) - e < c
comp.getLesserOperand() = sub and
comp.getGreaterOperand() = c and
- sub.getLeftOperand() = UtilParam::semSsaRead(v, D::fromFloat(d)) and
+ sub.getLeftOperand() = LangParam::semSsaRead(v, D::fromFloat(d)) and
sub.getRightOperand() = e and
upper = true and
delta = d + c.getIntValue()
@@ -226,7 +251,7 @@ module RangeStage UtilParam> {
// (v - d) - e > c
comp.getGreaterOperand() = sub and
comp.getLesserOperand() = c and
- sub.getLeftOperand() = UtilParam::semSsaRead(v, D::fromFloat(d)) and
+ sub.getLeftOperand() = LangParam::semSsaRead(v, D::fromFloat(d)) and
sub.getRightOperand() = e and
upper = false and
delta = d + c.getIntValue()
@@ -235,7 +260,7 @@ module RangeStage UtilParam> {
comp.getLesserOperand() = sub and
comp.getGreaterOperand() = c and
sub.getLeftOperand() = e and
- sub.getRightOperand() = UtilParam::semSsaRead(v, D::fromFloat(d)) and
+ sub.getRightOperand() = LangParam::semSsaRead(v, D::fromFloat(d)) and
upper = false and
delta = d - c.getIntValue()
or
@@ -243,7 +268,7 @@ module RangeStage UtilParam> {
comp.getGreaterOperand() = sub and
comp.getLesserOperand() = c and
sub.getLeftOperand() = e and
- sub.getRightOperand() = UtilParam::semSsaRead(v, D::fromFloat(d)) and
+ sub.getRightOperand() = LangParam::semSsaRead(v, D::fromFloat(d)) and
upper = true and
delta = d - c.getIntValue()
)
@@ -339,14 +364,16 @@ module RangeStage UtilParam> {
semImplies_v2(result, testIsTrue, boundFlowCond(v, e, delta, upper, testIsTrue0), testIsTrue0)
)
or
- result = UtilParam::semEqFlowCond(v, e, D::fromFloat(delta), true, testIsTrue) and
+ result = LangParam::semEqFlowCond(v, e, D::fromFloat(delta), true, testIsTrue) and
(upper = true or upper = false)
or
// guard that tests whether `v2` is bounded by `e + delta + d1 - d2` and
// exists a guard `guardEq` such that `v = v2 - d1 + d2`.
- exists(SemSsaVariable v2, SemGuard guardEq, boolean eqIsTrue, float d1, float d2, float oldDelta |
+ exists(
+ SemSsaVariable v2, SemGuard guardEq, boolean eqIsTrue, float d1, float d2, float oldDelta
+ |
guardEq =
- UtilParam::semEqFlowCond(v, UtilParam::semSsaRead(v2, D::fromFloat(d1)), D::fromFloat(d2),
+ LangParam::semEqFlowCond(v, LangParam::semSsaRead(v2, D::fromFloat(d1)), D::fromFloat(d2),
true, eqIsTrue) and
result = boundFlowCond(v2, e, oldDelta, upper, testIsTrue) and
// guardEq needs to control guard
@@ -394,7 +421,7 @@ module RangeStage UtilParam> {
SemSsaVariable v, SemSsaReadPosition pos, SemExpr e, float delta, boolean upper,
SemReason reason
) {
- UtilParam::semSsaUpdateStep(v, e, D::fromFloat(delta)) and
+ LangParam::semSsaUpdateStep(v, e, D::fromFloat(delta)) and
pos.hasReadOfVar(v) and
(upper = true or upper = false) and
reason = TSemNoReason()
@@ -414,7 +441,7 @@ module RangeStage UtilParam> {
Utils::getTrackedTypeForSsaVariable(v) instanceof SemIntegerType and
exists(SemGuard guard, boolean testIsTrue |
pos.hasReadOfVar(v) and
- guard = UtilParam::semEqFlowCond(v, e, D::fromFloat(delta), false, testIsTrue) and
+ guard = LangParam::semEqFlowCond(v, e, D::fromFloat(delta), false, testIsTrue) and
semGuardDirectlyControlsSsaRead(guard, pos, testIsTrue) and
reason = TSemCondReason(guard)
)
@@ -436,7 +463,7 @@ module RangeStage UtilParam> {
* - `upper = false` : `e2 >= e1 + delta`
*/
private predicate boundFlowStep(SemExpr e2, SemExpr e1, float delta, boolean upper) {
- UtilParam::semValueFlowStep(e2, e1, D::fromFloat(delta)) and
+ LangParam::semValueFlowStep(e2, e1, D::fromFloat(delta)) and
(upper = true or upper = false)
or
e2.(SafeCastExpr).getOperand() = e1 and
@@ -499,7 +526,7 @@ module RangeStage UtilParam> {
delta = 0 and
upper = false
or
- Specific::hasBound(e2, e1, delta, upper)
+ LangParam::hasBound(e2, e1, delta, upper)
}
/** Holds if `e2 = e1 * factor` and `factor > 0`. */
@@ -741,13 +768,13 @@ module RangeStage UtilParam> {
* (for `upper = false`) bound of `b`.
*/
private predicate baseBound(SemExpr e, float b, boolean upper) {
- Specific::hasConstantBound(e, b, upper)
+ LangParam::hasConstantBound(e, b, upper)
or
upper = false and
b = 0 and
semPositive(e.(SemBitAndExpr).getAnOperand()) and
// REVIEW: We let the language opt out here to preserve original results.
- not Specific::ignoreZeroLowerBound(e)
+ not LangParam::ignoreZeroLowerBound(e)
}
/**
From fb1ef07e9f52193448dc4f949ec69e3d1a04fdf4 Mon Sep 17 00:00:00 2001
From: Robert Marsh
Date: Fri, 16 Dec 2022 16:00:10 -0500
Subject: [PATCH 249/381] C++: more parameterized modules in range analysis
This makes the modulus analysis and sign analysis into parameterized
modules which are instantiated in the main range analysis module, and
makes RangeAnalysisSpecific and RangeUtils into parameters to the main
range analysis.
Some classes also need to be moved and made into `instanceof` extensions
because they'd otherwise be extending across parameterized module
boundaries.
---
.../code/cpp/semantic/analysis/FloatDelta.qll | 22 +
.../cpp/semantic/analysis/ModulusAnalysis.qll | 599 ++++++------
.../cpp/semantic/analysis/RangeAnalysis.qll | 6 +
.../analysis/RangeAnalysisSpecific.qll | 148 +--
.../semantic/analysis/RangeAnalysisStage.qll | 238 +++--
.../code/cpp/semantic/analysis/RangeUtils.qll | 243 ++---
.../semantic/analysis/SignAnalysisCommon.qll | 916 +++++++++---------
7 files changed, 1157 insertions(+), 1015 deletions(-)
create mode 100644 cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/FloatDelta.qll
create mode 100644 cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysis.qll
diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/FloatDelta.qll b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/FloatDelta.qll
new file mode 100644
index 00000000000..1fe1f59eef8
--- /dev/null
+++ b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/FloatDelta.qll
@@ -0,0 +1,22 @@
+private import RangeAnalysisStage
+
+module FloatDelta implements DeltaSig {
+ class Delta = float;
+
+ bindingset[d]
+ bindingset[result]
+ float toFloat(Delta d) {result = d}
+
+ bindingset[d]
+ bindingset[result]
+ int toInt(Delta d) {result = d}
+
+
+ bindingset[n]
+ bindingset[result] Delta fromInt(int n) {result = n}
+
+
+ bindingset[f]
+ bindingset[result] Delta fromFloat(float f) {result = f}
+ }
+
\ No newline at end of file
diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/ModulusAnalysis.qll b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/ModulusAnalysis.qll
index 8f26e85edbd..852dd40aad0 100644
--- a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/ModulusAnalysis.qll
+++ b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/ModulusAnalysis.qll
@@ -14,321 +14,326 @@ private import ModulusAnalysisSpecific::Private
private import experimental.semmle.code.cpp.semantic.Semantic
private import ConstantAnalysis
private import RangeUtils
+private import RangeAnalysisStage
-/**
- * Holds if `e + delta` equals `v` at `pos`.
- */
-private predicate valueFlowStepSsa(SemSsaVariable v, SemSsaReadPosition pos, SemExpr e, int delta) {
- semSsaUpdateStep(v, e, delta) and pos.hasReadOfVar(v)
- or
- exists(SemGuard guard, boolean testIsTrue |
- pos.hasReadOfVar(v) and
- guard = semEqFlowCond(v, e, delta, true, testIsTrue) and
- semGuardDirectlyControlsSsaRead(guard, pos, testIsTrue)
- )
-}
-
-/**
- * Holds if `add` is the addition of `larg` and `rarg`, neither of which are
- * `ConstantIntegerExpr`s.
- */
-private predicate nonConstAddition(SemExpr add, SemExpr larg, SemExpr rarg) {
- exists(SemAddExpr a | a = add |
- larg = a.getLeftOperand() and
- rarg = a.getRightOperand()
- ) and
- not larg instanceof SemConstantIntegerExpr and
- not rarg instanceof SemConstantIntegerExpr
-}
-
-/**
- * Holds if `sub` is the subtraction of `larg` and `rarg`, where `rarg` is not
- * a `ConstantIntegerExpr`.
- */
-private predicate nonConstSubtraction(SemExpr sub, SemExpr larg, SemExpr rarg) {
- exists(SemSubExpr s | s = sub |
- larg = s.getLeftOperand() and
- rarg = s.getRightOperand()
- ) and
- not rarg instanceof SemConstantIntegerExpr
-}
-
-/** Gets an expression that is the remainder modulo `mod` of `arg`. */
-private SemExpr modExpr(SemExpr arg, int mod) {
- exists(SemRemExpr rem |
- result = rem and
- arg = rem.getLeftOperand() and
- rem.getRightOperand().(SemConstantIntegerExpr).getIntValue() = mod and
- mod >= 2
- )
- or
- exists(SemConstantIntegerExpr c |
- mod = 2.pow([1 .. 30]) and
- c.getIntValue() = mod - 1 and
- result.(SemBitAndExpr).hasOperands(arg, c)
- )
-}
-
-/**
- * Gets a guard that tests whether `v` is congruent with `val` modulo `mod` on
- * its `testIsTrue` branch.
- */
-private SemGuard moduloCheck(SemSsaVariable v, int val, int mod, boolean testIsTrue) {
- exists(SemExpr rem, SemConstantIntegerExpr c, int r, boolean polarity |
- result.isEquality(rem, c, polarity) and
- c.getIntValue() = r and
- rem = modExpr(v.getAUse(), mod) and
- (
- testIsTrue = polarity and val = r
- or
- testIsTrue = polarity.booleanNot() and
- mod = 2 and
- val = 1 - r and
- (r = 0 or r = 1)
- )
- )
-}
-
-/**
- * Holds if a guard ensures that `v` at `pos` is congruent with `val` modulo `mod`.
- */
-private predicate moduloGuardedRead(SemSsaVariable v, SemSsaReadPosition pos, int val, int mod) {
- exists(SemGuard guard, boolean testIsTrue |
- pos.hasReadOfVar(v) and
- guard = moduloCheck(v, val, mod, testIsTrue) and
- semGuardControlsSsaRead(guard, pos, testIsTrue)
- )
-}
-
-/** Holds if `factor` is a power of 2 that divides `mask`. */
-bindingset[mask]
-private predicate andmaskFactor(int mask, int factor) {
- mask % factor = 0 and
- factor = 2.pow([1 .. 30])
-}
-
-/** Holds if `e` is evenly divisible by `factor`. */
-private predicate evenlyDivisibleExpr(SemExpr e, int factor) {
- exists(SemConstantIntegerExpr c, int k | k = c.getIntValue() |
- e.(SemMulExpr).getAnOperand() = c and factor = k.abs() and factor >= 2
- or
- e.(SemShiftLeftExpr).getRightOperand() = c and factor = 2.pow(k) and k > 0
- or
- e.(SemBitAndExpr).getAnOperand() = c and factor = max(int f | andmaskFactor(k, f))
- )
-}
-
-/**
- * Holds if `rix` is the number of input edges to `phi`.
- */
-private predicate maxPhiInputRank(SemSsaPhiNode phi, int rix) {
- rix = max(int r | rankedPhiInput(phi, _, _, r))
-}
-
-/**
- * Gets the remainder of `val` modulo `mod`.
- *
- * For `mod = 0` the result equals `val` and for `mod > 1` the result is within
- * the range `[0 .. mod-1]`.
- */
-bindingset[val, mod]
-private int remainder(int val, int mod) {
- mod = 0 and result = val
- or
- mod > 1 and result = ((val % mod) + mod) % mod
-}
-
-/**
- * Holds if `inp` is an input to `phi` and equals `phi` modulo `mod` along `edge`.
- */
-private predicate phiSelfModulus(
- SemSsaPhiNode phi, SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge, int mod
-) {
- exists(SemSsaBound phibound, int v, int m |
- edge.phiInput(phi, inp) and
- phibound.getAVariable() = phi and
- ssaModulus(inp, edge, phibound, v, m) and
- mod = m.gcd(v) and
- mod != 1
- )
-}
-
-/**
- * Holds if `b + val` modulo `mod` is a candidate congruence class for `phi`.
- */
-private predicate phiModulusInit(SemSsaPhiNode phi, SemBound b, int val, int mod) {
- exists(SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge |
- edge.phiInput(phi, inp) and
- ssaModulus(inp, edge, b, val, mod)
- )
-}
-
-/**
- * Holds if all inputs to `phi` numbered `1` to `rix` are equal to `b + val` modulo `mod`.
- */
-pragma[nomagic]
-private predicate phiModulusRankStep(SemSsaPhiNode phi, SemBound b, int val, int mod, int rix) {
- /*
- * base case. If any phi input is equal to `b + val` modulo `mod`, that's a potential congruence
- * class for the phi node.
+module ModulusAnalysis U> {
+ /**
+ * Holds if `e + delta` equals `v` at `pos`.
*/
+ private predicate valueFlowStepSsa(SemSsaVariable v, SemSsaReadPosition pos, SemExpr e, int delta) {
+ U::semSsaUpdateStep(v, e, D::fromInt(delta)) and pos.hasReadOfVar(v)
+ or
+ exists(SemGuard guard, boolean testIsTrue |
+ pos.hasReadOfVar(v) and
+ guard = U::semEqFlowCond(v, e, D::fromInt(delta), true, testIsTrue) and
+ semGuardDirectlyControlsSsaRead(guard, pos, testIsTrue)
+ )
+ }
- rix = 0 and
- phiModulusInit(phi, b, val, mod)
- or
- exists(SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge, int v1, int m1 |
- mod != 1 and
- val = remainder(v1, mod)
- |
+ /**
+ * Holds if `add` is the addition of `larg` and `rarg`, neither of which are
+ * `ConstantIntegerExpr`s.
+ */
+ private predicate nonConstAddition(SemExpr add, SemExpr larg, SemExpr rarg) {
+ exists(SemAddExpr a | a = add |
+ larg = a.getLeftOperand() and
+ rarg = a.getRightOperand()
+ ) and
+ not larg instanceof SemConstantIntegerExpr and
+ not rarg instanceof SemConstantIntegerExpr
+ }
+
+ /**
+ * Holds if `sub` is the subtraction of `larg` and `rarg`, where `rarg` is not
+ * a `ConstantIntegerExpr`.
+ */
+ private predicate nonConstSubtraction(SemExpr sub, SemExpr larg, SemExpr rarg) {
+ exists(SemSubExpr s | s = sub |
+ larg = s.getLeftOperand() and
+ rarg = s.getRightOperand()
+ ) and
+ not rarg instanceof SemConstantIntegerExpr
+ }
+
+ /** Gets an expression that is the remainder modulo `mod` of `arg`. */
+ private SemExpr modExpr(SemExpr arg, int mod) {
+ exists(SemRemExpr rem |
+ result = rem and
+ arg = rem.getLeftOperand() and
+ rem.getRightOperand().(SemConstantIntegerExpr).getIntValue() = mod and
+ mod >= 2
+ )
+ or
+ exists(SemConstantIntegerExpr c |
+ mod = 2.pow([1 .. 30]) and
+ c.getIntValue() = mod - 1 and
+ result.(SemBitAndExpr).hasOperands(arg, c)
+ )
+ }
+
+ /**
+ * Gets a guard that tests whether `v` is congruent with `val` modulo `mod` on
+ * its `testIsTrue` branch.
+ */
+ private SemGuard moduloCheck(SemSsaVariable v, int val, int mod, boolean testIsTrue) {
+ exists(SemExpr rem, SemConstantIntegerExpr c, int r, boolean polarity |
+ result.isEquality(rem, c, polarity) and
+ c.getIntValue() = r and
+ rem = modExpr(v.getAUse(), mod) and
+ (
+ testIsTrue = polarity and val = r
+ or
+ testIsTrue = polarity.booleanNot() and
+ mod = 2 and
+ val = 1 - r and
+ (r = 0 or r = 1)
+ )
+ )
+ }
+
+ /**
+ * Holds if a guard ensures that `v` at `pos` is congruent with `val` modulo `mod`.
+ */
+ private predicate moduloGuardedRead(SemSsaVariable v, SemSsaReadPosition pos, int val, int mod) {
+ exists(SemGuard guard, boolean testIsTrue |
+ pos.hasReadOfVar(v) and
+ guard = moduloCheck(v, val, mod, testIsTrue) and
+ semGuardControlsSsaRead(guard, pos, testIsTrue)
+ )
+ }
+
+ /** Holds if `factor` is a power of 2 that divides `mask`. */
+ bindingset[mask]
+ private predicate andmaskFactor(int mask, int factor) {
+ mask % factor = 0 and
+ factor = 2.pow([1 .. 30])
+ }
+
+ /** Holds if `e` is evenly divisible by `factor`. */
+ private predicate evenlyDivisibleExpr(SemExpr e, int factor) {
+ exists(SemConstantIntegerExpr c, int k | k = c.getIntValue() |
+ e.(SemMulExpr).getAnOperand() = c and factor = k.abs() and factor >= 2
+ or
+ e.(SemShiftLeftExpr).getRightOperand() = c and factor = 2.pow(k) and k > 0
+ or
+ e.(SemBitAndExpr).getAnOperand() = c and factor = max(int f | andmaskFactor(k, f))
+ )
+ }
+
+ /**
+ * Holds if `rix` is the number of input edges to `phi`.
+ */
+ private predicate maxPhiInputRank(SemSsaPhiNode phi, int rix) {
+ rix = max(int r | rankedPhiInput(phi, _, _, r))
+ }
+
+ /**
+ * Gets the remainder of `val` modulo `mod`.
+ *
+ * For `mod = 0` the result equals `val` and for `mod > 1` the result is within
+ * the range `[0 .. mod-1]`.
+ */
+ bindingset[val, mod]
+ private int remainder(int val, int mod) {
+ mod = 0 and result = val
+ or
+ mod > 1 and result = ((val % mod) + mod) % mod
+ }
+
+ /**
+ * Holds if `inp` is an input to `phi` and equals `phi` modulo `mod` along `edge`.
+ */
+ private predicate phiSelfModulus(
+ SemSsaPhiNode phi, SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge, int mod
+ ) {
+ exists(SemSsaBound phibound, int v, int m |
+ edge.phiInput(phi, inp) and
+ phibound.getAVariable() = phi and
+ ssaModulus(inp, edge, phibound, v, m) and
+ mod = m.gcd(v) and
+ mod != 1
+ )
+ }
+
+ /**
+ * Holds if `b + val` modulo `mod` is a candidate congruence class for `phi`.
+ */
+ private predicate phiModulusInit(SemSsaPhiNode phi, SemBound b, int val, int mod) {
+ exists(SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge |
+ edge.phiInput(phi, inp) and
+ ssaModulus(inp, edge, b, val, mod)
+ )
+ }
+
+ /**
+ * Holds if all inputs to `phi` numbered `1` to `rix` are equal to `b + val` modulo `mod`.
+ */
+ pragma[nomagic]
+ private predicate phiModulusRankStep(SemSsaPhiNode phi, SemBound b, int val, int mod, int rix) {
/*
- * Recursive case. If `inp` = `b + v2` mod `m2`, we combine that with the preceding potential
- * congruence class `b + v1` mod `m1`. The result will be the congruence class of `v1` modulo
- * the greatest common denominator of `m1`, `m2`, and `v1 - v2`.
+ * base case. If any phi input is equal to `b + val` modulo `mod`, that's a potential congruence
+ * class for the phi node.
*/
- exists(int v2, int m2 |
- rankedPhiInput(pragma[only_bind_out](phi), inp, edge, rix) and
- phiModulusRankStep(phi, b, v1, m1, rix - 1) and
- ssaModulus(inp, edge, b, v2, m2) and
- mod = m1.gcd(m2).gcd(v1 - v2)
+ rix = 0 and
+ phiModulusInit(phi, b, val, mod)
+ or
+ exists(SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge, int v1, int m1 |
+ mod != 1 and
+ val = remainder(v1, mod)
+ |
+ /*
+ * Recursive case. If `inp` = `b + v2` mod `m2`, we combine that with the preceding potential
+ * congruence class `b + v1` mod `m1`. The result will be the congruence class of `v1` modulo
+ * the greatest common denominator of `m1`, `m2`, and `v1 - v2`.
+ */
+
+ exists(int v2, int m2 |
+ rankedPhiInput(pragma[only_bind_out](phi), inp, edge, rix) and
+ phiModulusRankStep(phi, b, v1, m1, rix - 1) and
+ ssaModulus(inp, edge, b, v2, m2) and
+ mod = m1.gcd(m2).gcd(v1 - v2)
+ )
+ or
+ /*
+ * Recursive case. If `inp` = `phi` mod `m2`, we combine that with the preceding potential
+ * congruence class `b + v1` mod `m1`. The result will be a congruence class modulo the greatest
+ * common denominator of `m1` and `m2`.
+ */
+
+ exists(int m2 |
+ rankedPhiInput(phi, inp, edge, rix) and
+ phiModulusRankStep(phi, b, v1, m1, rix - 1) and
+ phiSelfModulus(phi, inp, edge, m2) and
+ mod = m1.gcd(m2)
+ )
)
- or
- /*
- * Recursive case. If `inp` = `phi` mod `m2`, we combine that with the preceding potential
- * congruence class `b + v1` mod `m1`. The result will be a congruence class modulo the greatest
- * common denominator of `m1` and `m2`.
- */
+ }
- exists(int m2 |
- rankedPhiInput(phi, inp, edge, rix) and
- phiModulusRankStep(phi, b, v1, m1, rix - 1) and
- phiSelfModulus(phi, inp, edge, m2) and
- mod = m1.gcd(m2)
+ /**
+ * Holds if `phi` is equal to `b + val` modulo `mod`.
+ */
+ private predicate phiModulus(SemSsaPhiNode phi, SemBound b, int val, int mod) {
+ exists(int r |
+ maxPhiInputRank(phi, r) and
+ phiModulusRankStep(phi, b, val, mod, r)
)
- )
-}
+ }
-/**
- * Holds if `phi` is equal to `b + val` modulo `mod`.
- */
-private predicate phiModulus(SemSsaPhiNode phi, SemBound b, int val, int mod) {
- exists(int r |
- maxPhiInputRank(phi, r) and
- phiModulusRankStep(phi, b, val, mod, r)
- )
-}
-
-/**
- * Holds if `v` at `pos` is equal to `b + val` modulo `mod`.
- */
-private predicate ssaModulus(SemSsaVariable v, SemSsaReadPosition pos, SemBound b, int val, int mod) {
- phiModulus(v, b, val, mod) and pos.hasReadOfVar(v)
- or
- b.(SemSsaBound).getAVariable() = v and pos.hasReadOfVar(v) and val = 0 and mod = 0
- or
- exists(SemExpr e, int val0, int delta |
- semExprModulus(e, b, val0, mod) and
- valueFlowStepSsa(v, pos, e, delta) and
- val = remainder(val0 + delta, mod)
- )
- or
- moduloGuardedRead(v, pos, val, mod) and b instanceof SemZeroBound
-}
-
-/**
- * Holds if `e` is equal to `b + val` modulo `mod`.
- *
- * There are two cases for the modulus:
- * - `mod = 0`: The equality `e = b + val` is an ordinary equality.
- * - `mod > 1`: `val` lies within the range `[0 .. mod-1]`.
- */
-cached
-predicate semExprModulus(SemExpr e, SemBound b, int val, int mod) {
- not ignoreExprModulus(e) and
- (
- e = b.getExpr(val) and mod = 0
+ /**
+ * Holds if `v` at `pos` is equal to `b + val` modulo `mod`.
+ */
+ private predicate ssaModulus(
+ SemSsaVariable v, SemSsaReadPosition pos, SemBound b, int val, int mod
+ ) {
+ phiModulus(v, b, val, mod) and pos.hasReadOfVar(v)
or
- evenlyDivisibleExpr(e, mod) and
- val = 0 and
- b instanceof SemZeroBound
+ b.(SemSsaBound).getAVariable() = v and pos.hasReadOfVar(v) and val = 0 and mod = 0
or
- exists(SemSsaVariable v, SemSsaReadPositionBlock bb |
- ssaModulus(v, bb, b, val, mod) and
- e = v.getAUse() and
- bb.getAnExpr() = e
- )
- or
- exists(SemExpr mid, int val0, int delta |
- semExprModulus(mid, b, val0, mod) and
- semValueFlowStep(e, mid, delta) and
+ exists(SemExpr e, int val0, int delta |
+ semExprModulus(e, b, val0, mod) and
+ valueFlowStepSsa(v, pos, e, delta) and
val = remainder(val0 + delta, mod)
)
or
- exists(SemConditionalExpr cond, int v1, int v2, int m1, int m2 |
- cond = e and
- condExprBranchModulus(cond, true, b, v1, m1) and
- condExprBranchModulus(cond, false, b, v2, m2) and
- mod = m1.gcd(m2).gcd(v1 - v2) and
- mod != 1 and
- val = remainder(v1, mod)
- )
- or
- exists(SemBound b1, SemBound b2, int v1, int v2, int m1, int m2 |
- addModulus(e, true, b1, v1, m1) and
- addModulus(e, false, b2, v2, m2) and
- mod = m1.gcd(m2) and
- mod != 1 and
- val = remainder(v1 + v2, mod)
- |
- b = b1 and b2 instanceof SemZeroBound
+ moduloGuardedRead(v, pos, val, mod) and b instanceof SemZeroBound
+ }
+
+ /**
+ * Holds if `e` is equal to `b + val` modulo `mod`.
+ *
+ * There are two cases for the modulus:
+ * - `mod = 0`: The equality `e = b + val` is an ordinary equality.
+ * - `mod > 1`: `val` lies within the range `[0 .. mod-1]`.
+ */
+ cached
+ predicate semExprModulus(SemExpr e, SemBound b, int val, int mod) {
+ not ignoreExprModulus(e) and
+ (
+ e = b.getExpr(val) and mod = 0
or
- b = b2 and b1 instanceof SemZeroBound
+ evenlyDivisibleExpr(e, mod) and
+ val = 0 and
+ b instanceof SemZeroBound
+ or
+ exists(SemSsaVariable v, SemSsaReadPositionBlock bb |
+ ssaModulus(v, bb, b, val, mod) and
+ e = v.getAUse() and
+ bb.getAnExpr() = e
+ )
+ or
+ exists(SemExpr mid, int val0, int delta |
+ semExprModulus(mid, b, val0, mod) and
+ U::semValueFlowStep(e, mid, D::fromInt(delta)) and
+ val = remainder(val0 + delta, mod)
+ )
+ or
+ exists(SemConditionalExpr cond, int v1, int v2, int m1, int m2 |
+ cond = e and
+ condExprBranchModulus(cond, true, b, v1, m1) and
+ condExprBranchModulus(cond, false, b, v2, m2) and
+ mod = m1.gcd(m2).gcd(v1 - v2) and
+ mod != 1 and
+ val = remainder(v1, mod)
+ )
+ or
+ exists(SemBound b1, SemBound b2, int v1, int v2, int m1, int m2 |
+ addModulus(e, true, b1, v1, m1) and
+ addModulus(e, false, b2, v2, m2) and
+ mod = m1.gcd(m2) and
+ mod != 1 and
+ val = remainder(v1 + v2, mod)
+ |
+ b = b1 and b2 instanceof SemZeroBound
+ or
+ b = b2 and b1 instanceof SemZeroBound
+ )
+ or
+ exists(int v1, int v2, int m1, int m2 |
+ subModulus(e, true, b, v1, m1) and
+ subModulus(e, false, any(SemZeroBound zb), v2, m2) and
+ mod = m1.gcd(m2) and
+ mod != 1 and
+ val = remainder(v1 - v2, mod)
+ )
)
- or
- exists(int v1, int v2, int m1, int m2 |
- subModulus(e, true, b, v1, m1) and
- subModulus(e, false, any(SemZeroBound zb), v2, m2) and
- mod = m1.gcd(m2) and
- mod != 1 and
- val = remainder(v1 - v2, mod)
+ }
+
+ private predicate condExprBranchModulus(
+ SemConditionalExpr cond, boolean branch, SemBound b, int val, int mod
+ ) {
+ semExprModulus(cond.getBranchExpr(branch), b, val, mod)
+ }
+
+ private predicate addModulus(SemExpr add, boolean isLeft, SemBound b, int val, int mod) {
+ exists(SemExpr larg, SemExpr rarg | nonConstAddition(add, larg, rarg) |
+ semExprModulus(larg, b, val, mod) and isLeft = true
+ or
+ semExprModulus(rarg, b, val, mod) and isLeft = false
)
- )
-}
+ }
-private predicate condExprBranchModulus(
- SemConditionalExpr cond, boolean branch, SemBound b, int val, int mod
-) {
- semExprModulus(cond.getBranchExpr(branch), b, val, mod)
-}
-
-private predicate addModulus(SemExpr add, boolean isLeft, SemBound b, int val, int mod) {
- exists(SemExpr larg, SemExpr rarg | nonConstAddition(add, larg, rarg) |
- semExprModulus(larg, b, val, mod) and isLeft = true
- or
- semExprModulus(rarg, b, val, mod) and isLeft = false
- )
-}
-
-private predicate subModulus(SemExpr sub, boolean isLeft, SemBound b, int val, int mod) {
- exists(SemExpr larg, SemExpr rarg | nonConstSubtraction(sub, larg, rarg) |
- semExprModulus(larg, b, val, mod) and isLeft = true
- or
- semExprModulus(rarg, b, val, mod) and isLeft = false
- )
-}
-
-/**
- * Holds if `inp` is an input to `phi` along `edge` and this input has index `r`
- * in an arbitrary 1-based numbering of the input edges to `phi`.
- */
-private predicate rankedPhiInput(
- SemSsaPhiNode phi, SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge, int r
-) {
- edge.phiInput(phi, inp) and
- edge =
- rank[r](SemSsaReadPositionPhiInputEdge e |
- e.phiInput(phi, _)
- |
- e order by e.getOrigBlock().getUniqueId()
+ private predicate subModulus(SemExpr sub, boolean isLeft, SemBound b, int val, int mod) {
+ exists(SemExpr larg, SemExpr rarg | nonConstSubtraction(sub, larg, rarg) |
+ semExprModulus(larg, b, val, mod) and isLeft = true
+ or
+ semExprModulus(rarg, b, val, mod) and isLeft = false
)
+ }
+
+ /**
+ * Holds if `inp` is an input to `phi` along `edge` and this input has index `r`
+ * in an arbitrary 1-based numbering of the input edges to `phi`.
+ */
+ private predicate rankedPhiInput(
+ SemSsaPhiNode phi, SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge, int r
+ ) {
+ edge.phiInput(phi, inp) and
+ edge =
+ rank[r](SemSsaReadPositionPhiInputEdge e |
+ e.phiInput(phi, _)
+ |
+ e order by e.getOrigBlock().getUniqueId()
+ )
+ }
}
diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysis.qll b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysis.qll
new file mode 100644
index 00000000000..6d7ba2e9ff1
--- /dev/null
+++ b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysis.qll
@@ -0,0 +1,6 @@
+private import RangeAnalysisStage
+private import RangeAnalysisSpecific
+private import FloatDelta
+private import RangeUtils
+
+module CppRangeAnalysis = RangeStage>;
\ No newline at end of file
diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisSpecific.qll b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisSpecific.qll
index 5918b56e50e..769538fc4cf 100644
--- a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisSpecific.qll
+++ b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisSpecific.qll
@@ -3,86 +3,90 @@
*/
private import experimental.semmle.code.cpp.semantic.Semantic
+private import RangeAnalysisStage
+private import FloatDelta
-/**
- * Holds if the specified expression should be excluded from the result of `ssaRead()`.
- *
- * This predicate is to keep the results identical to the original Java implementation. It should be
- * removed once we have the new implementation matching the old results exactly.
- */
-predicate ignoreSsaReadCopy(SemExpr e) { none() }
+module CppLangImpl implements LangSig {
+ /**
+ * Holds if the specified expression should be excluded from the result of `ssaRead()`.
+ *
+ * This predicate is to keep the results identical to the original Java implementation. It should be
+ * removed once we have the new implementation matching the old results exactly.
+ */
+ predicate ignoreSsaReadCopy(SemExpr e) { none() }
-/**
- * Ignore the bound on this expression.
- *
- * This predicate is to keep the results identical to the original Java implementation. It should be
- * removed once we have the new implementation matching the old results exactly.
- */
-predicate ignoreExprBound(SemExpr e) { none() }
+ /**
+ * Ignore the bound on this expression.
+ *
+ * This predicate is to keep the results identical to the original Java implementation. It should be
+ * removed once we have the new implementation matching the old results exactly.
+ */
+ predicate ignoreExprBound(SemExpr e) { none() }
-/**
- * Ignore any inferred zero lower bound on this expression.
- *
- * This predicate is to keep the results identical to the original Java implementation. It should be
- * removed once we have the new implementation matching the old results exactly.
- */
-predicate ignoreZeroLowerBound(SemExpr e) { none() }
+ /**
+ * Ignore any inferred zero lower bound on this expression.
+ *
+ * This predicate is to keep the results identical to the original Java implementation. It should be
+ * removed once we have the new implementation matching the old results exactly.
+ */
+ predicate ignoreZeroLowerBound(SemExpr e) { none() }
-/**
- * Holds if the specified expression should be excluded from the result of `ssaRead()`.
- *
- * This predicate is to keep the results identical to the original Java implementation. It should be
- * removed once we have the new implementation matching the old results exactly.
- */
-predicate ignoreSsaReadArithmeticExpr(SemExpr e) { none() }
+ /**
+ * Holds if the specified expression should be excluded from the result of `ssaRead()`.
+ *
+ * This predicate is to keep the results identical to the original Java implementation. It should be
+ * removed once we have the new implementation matching the old results exactly.
+ */
+ predicate ignoreSsaReadArithmeticExpr(SemExpr e) { none() }
-/**
- * Holds if the specified variable should be excluded from the result of `ssaRead()`.
- *
- * This predicate is to keep the results identical to the original Java implementation. It should be
- * removed once we have the new implementation matching the old results exactly.
- */
-predicate ignoreSsaReadAssignment(SemSsaVariable v) { none() }
+ /**
+ * Holds if the specified variable should be excluded from the result of `ssaRead()`.
+ *
+ * This predicate is to keep the results identical to the original Java implementation. It should be
+ * removed once we have the new implementation matching the old results exactly.
+ */
+ predicate ignoreSsaReadAssignment(SemSsaVariable v) { none() }
-/**
- * Adds additional results to `ssaRead()` that are specific to Java.
- *
- * This predicate handles propagation of offsets for post-increment and post-decrement expressions
- * in exactly the same way as the old Java implementation. Once the new implementation matches the
- * old one, we should remove this predicate and propagate deltas for all similar patterns, whether
- * or not they come from a post-increment/decrement expression.
- */
-SemExpr specificSsaRead(SemSsaVariable v, int delta) { none() }
+ /**
+ * Adds additional results to `ssaRead()` that are specific to Java.
+ *
+ * This predicate handles propagation of offsets for post-increment and post-decrement expressions
+ * in exactly the same way as the old Java implementation. Once the new implementation matches the
+ * old one, we should remove this predicate and propagate deltas for all similar patterns, whether
+ * or not they come from a post-increment/decrement expression.
+ */
+ SemExpr specificSsaRead(SemSsaVariable v, float delta) { none() }
-/**
- * Holds if `e >= bound` (if `upper = false`) or `e <= bound` (if `upper = true`).
- */
-predicate hasConstantBound(SemExpr e, int bound, boolean upper) { none() }
+ /**
+ * Holds if `e >= bound` (if `upper = false`) or `e <= bound` (if `upper = true`).
+ */
+ predicate hasConstantBound(SemExpr e, float bound, boolean upper) { none() }
-/**
- * Holds if `e >= bound + delta` (if `upper = false`) or `e <= bound + delta` (if `upper = true`).
- */
-predicate hasBound(SemExpr e, SemExpr bound, int delta, boolean upper) { none() }
+ /**
+ * Holds if `e >= bound + delta` (if `upper = false`) or `e <= bound + delta` (if `upper = true`).
+ */
+ predicate hasBound(SemExpr e, SemExpr bound, float delta, boolean upper) { none() }
-/**
- * Holds if the value of `dest` is known to be `src + delta`.
- */
-predicate additionalValueFlowStep(SemExpr dest, SemExpr src, int delta) { none() }
+ /**
+ * Holds if the value of `dest` is known to be `src + delta`.
+ */
+ predicate additionalValueFlowStep(SemExpr dest, SemExpr src, float delta) { none() }
-/**
- * Gets the type that range analysis should use to track the result of the specified expression,
- * if a type other than the original type of the expression is to be used.
- *
- * This predicate is commonly used in languages that support immutable "boxed" types that are
- * actually references but whose values can be tracked as the type contained in the box.
- */
-SemType getAlternateType(SemExpr e) { none() }
+ /**
+ * Gets the type that range analysis should use to track the result of the specified expression,
+ * if a type other than the original type of the expression is to be used.
+ *
+ * This predicate is commonly used in languages that support immutable "boxed" types that are
+ * actually references but whose values can be tracked as the type contained in the box.
+ */
+ SemType getAlternateType(SemExpr e) { none() }
-/**
- * Gets the type that range analysis should use to track the result of the specified source
- * variable, if a type other than the original type of the expression is to be used.
- *
- * This predicate is commonly used in languages that support immutable "boxed" types that are
- * actually references but whose values can be tracked as the type contained in the box.
- */
-SemType getAlternateTypeForSsaVariable(SemSsaVariable var) { none() }
+ /**
+ * Gets the type that range analysis should use to track the result of the specified source
+ * variable, if a type other than the original type of the expression is to be used.
+ *
+ * This predicate is commonly used in languages that support immutable "boxed" types that are
+ * actually references but whose values can be tracked as the type contained in the box.
+ */
+ SemType getAlternateTypeForSsaVariable(SemSsaVariable var) { none() }
+}
\ No newline at end of file
diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisStage.qll b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisStage.qll
index 3e5d4ec853c..0da8dc570d4 100644
--- a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisStage.qll
+++ b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisStage.qll
@@ -69,29 +69,6 @@ private import ModulusAnalysis
private import experimental.semmle.code.cpp.semantic.Semantic
private import ConstantAnalysis
-/**
- * An expression that does conversion, boxing, or unboxing
- */
-private class ConvertOrBoxExpr extends SemUnaryExpr {
- ConvertOrBoxExpr() {
- this instanceof SemConvertExpr
- or
- this instanceof SemBoxExpr
- or
- this instanceof SemUnboxExpr
- }
-}
-
-/**
- * A cast that can be ignored for the purpose of range analysis.
- */
-private class SafeCastExpr extends ConvertOrBoxExpr {
- SafeCastExpr() {
- conversionCannotOverflow(Utils::getTrackedType(pragma[only_bind_into](getOperand())),
- Utils::getTrackedType(this))
- }
-}
-
/**
* Holds if `typ` is a small integral type with the given lower and upper bounds.
*/
@@ -111,54 +88,45 @@ private predicate typeBound(SemIntegerType typ, int lowerbound, int upperbound)
)
}
-/**
- * A cast to a small integral type that may overflow or underflow.
- */
-private class NarrowingCastExpr extends ConvertOrBoxExpr {
- NarrowingCastExpr() {
- not this instanceof SafeCastExpr and
- typeBound(Utils::getTrackedType(this), _, _)
- }
-
- /** Gets the lower bound of the resulting type. */
- int getLowerBound() { typeBound(Utils::getTrackedType(this), result, _) }
-
- /** Gets the upper bound of the resulting type. */
- int getUpperBound() { typeBound(Utils::getTrackedType(this), _, result) }
-}
-
signature module DeltaSig {
+ bindingset[this]
class Delta;
+ bindingset[d]
+ bindingset[result]
float toFloat(Delta d);
+ bindingset[d]
+ bindingset[result]
int toInt(Delta d);
+ bindingset[n]
+ bindingset[result]
Delta fromInt(int n);
+ bindingset[f]
+ bindingset[result]
Delta fromFloat(float f);
}
-signature module UtilSig {
- SemExpr semSsaRead(SemSsaVariable v, DeltaParam::Delta delta);
-
- SemGuard semEqFlowCond(
- SemSsaVariable v, SemExpr e, DeltaParam::Delta delta, boolean isEq, boolean testIsTrue
- );
-
- predicate semSsaUpdateStep(SemSsaExplicitUpdate v, SemExpr e, DeltaParam::Delta delta);
-
- predicate semValueFlowStep(SemExpr e2, SemExpr e1, DeltaParam::Delta delta);
+signature module LangSig {
+ /**
+ * Holds if the specified expression should be excluded from the result of `ssaRead()`.
+ *
+ * This predicate is to keep the results identical to the original Java implementation. It should be
+ * removed once we have the new implementation matching the old results exactly.
+ */
+ predicate ignoreSsaReadCopy(SemExpr e);
/**
* Holds if `e >= bound` (if `upper = false`) or `e <= bound` (if `upper = true`).
*/
- predicate hasConstantBound(SemExpr e, int bound, boolean upper);
+ predicate hasConstantBound(SemExpr e, D::Delta bound, boolean upper);
/**
* Holds if `e >= bound + delta` (if `upper = false`) or `e <= bound + delta` (if `upper = true`).
*/
- predicate hasBound(SemExpr e, SemExpr bound, int delta, boolean upper);
+ predicate hasBound(SemExpr e, SemExpr bound, D::Delta delta, boolean upper);
/**
* Ignore the bound on this expression.
@@ -175,9 +143,137 @@ signature module UtilSig {
* removed once we have the new implementation matching the old results exactly.
*/
predicate ignoreZeroLowerBound(SemExpr e);
+
+ /**
+ * Holds if the specified expression should be excluded from the result of `ssaRead()`.
+ *
+ * This predicate is to keep the results identical to the original Java implementation. It should be
+ * removed once we have the new implementation matching the old results exactly.
+ */
+ predicate ignoreSsaReadArithmeticExpr(SemExpr e);
+
+ /**
+ * Holds if the specified variable should be excluded from the result of `ssaRead()`.
+ *
+ * This predicate is to keep the results identical to the original Java implementation. It should be
+ * removed once we have the new implementation matching the old results exactly.
+ */
+ predicate ignoreSsaReadAssignment(SemSsaVariable v);
+
+ /**
+ * Adds additional results to `ssaRead()` that are specific to Java.
+ *
+ * This predicate handles propagation of offsets for post-increment and post-decrement expressions
+ * in exactly the same way as the old Java implementation. Once the new implementation matches the
+ * old one, we should remove this predicate and propagate deltas for all similar patterns, whether
+ * or not they come from a post-increment/decrement expression.
+ */
+ SemExpr specificSsaRead(SemSsaVariable v, D::Delta delta);
+
+ /**
+ * Holds if the value of `dest` is known to be `src + delta`.
+ */
+ predicate additionalValueFlowStep(SemExpr dest, SemExpr src, D::Delta delta);
+
+ /**
+ * Gets the type that range analysis should use to track the result of the specified expression,
+ * if a type other than the original type of the expression is to be used.
+ *
+ * This predicate is commonly used in languages that support immutable "boxed" types that are
+ * actually references but whose values can be tracked as the type contained in the box.
+ */
+ SemType getAlternateType(SemExpr e);
+
+ /**
+ * Gets the type that range analysis should use to track the result of the specified source
+ * variable, if a type other than the original type of the expression is to be used.
+ *
+ * This predicate is commonly used in languages that support immutable "boxed" types that are
+ * actually references but whose values can be tracked as the type contained in the box.
+ */
+ SemType getAlternateTypeForSsaVariable(SemSsaVariable var);
}
-module RangeStage LangParam> {
+signature module UtilSig {
+ SemExpr semSsaRead(SemSsaVariable v, DeltaParam::Delta delta);
+
+ SemGuard semEqFlowCond(
+ SemSsaVariable v, SemExpr e, DeltaParam::Delta delta, boolean isEq, boolean testIsTrue
+ );
+
+ predicate semSsaUpdateStep(SemSsaExplicitUpdate v, SemExpr e, DeltaParam::Delta delta);
+
+ predicate semValueFlowStep(SemExpr e2, SemExpr e1, DeltaParam::Delta delta);
+
+ /**
+ * Gets the type used to track the specified source variable's range information.
+ *
+ * Usually, this just `e.getType()`, but the language can override this to track immutable boxed
+ * primitive types as the underlying primitive type.
+ */
+ SemType getTrackedTypeForSsaVariable(SemSsaVariable var);
+
+ /**
+ * Gets the type used to track the specified expression's range information.
+ *
+ * Usually, this just `e.getSemType()`, but the language can override this to track immutable boxed
+ * primitive types as the underlying primitive type.
+ */
+ SemType getTrackedType(SemExpr e);
+}
+
+module RangeStage LangParam, UtilSig UtilParam> {
+ /**
+ * An expression that does conversion, boxing, or unboxing
+ */
+ private class ConvertOrBoxExpr instanceof SemUnaryExpr {
+ ConvertOrBoxExpr() {
+ this instanceof SemConvertExpr
+ or
+ this instanceof SemBoxExpr
+ or
+ this instanceof SemUnboxExpr
+ }
+
+ string toString() { result = super.toString() }
+
+ SemExpr getOperand() { result = super.getOperand() }
+ }
+
+ /**
+ * A cast that can be ignored for the purpose of range analysis.
+ */
+ private class SafeCastExpr extends ConvertOrBoxExpr {
+ SafeCastExpr() {
+ conversionCannotOverflow(UtilParam::getTrackedType(pragma[only_bind_into](getOperand())),
+ UtilParam::getTrackedType(this))
+ }
+ }
+
+ /**
+ * A cast to a small integral type that may overflow or underflow.
+ */
+ private class NarrowingCastExpr extends ConvertOrBoxExpr {
+ NarrowingCastExpr() {
+ not this instanceof SafeCastExpr and
+ typeBound(UtilParam::getTrackedType(this), _, _)
+ }
+
+ /** Gets the lower bound of the resulting type. */
+ int getLowerBound() { typeBound(UtilParam::getTrackedType(this), result, _) }
+
+ /** Gets the upper bound of the resulting type. */
+ int getUpperBound() { typeBound(UtilParam::getTrackedType(this), _, result) }
+ }
+
+ private module SignAnalysisInstantiated = SignAnalysis; // TODO: will this cause reevaluation if it's instantiated with the same DeltaSig and UtilParam multiple times?
+
+ private import SignAnalysisInstantiated
+
+ private module ModulusAnalysisInstantiated = ModulusAnalysis; // TODO: will this cause reevaluation if it's instantiated with the same DeltaSig and UtilParam multiple times?
+
+ private import ModulusAnalysisInstantiated
+
cached
private module RangeAnalysisCache {
cached
@@ -203,7 +299,7 @@ module RangeStage LangParam> {
*/
cached
predicate possibleReason(SemGuard guard) {
- guard = boundFlowCond(_, _, _, _, _) or guard = LangParam::semEqFlowCond(_, _, _, _, _)
+ guard = boundFlowCond(_, _, _, _, _) or guard = UtilParam::semEqFlowCond(_, _, _, _, _)
}
}
@@ -231,11 +327,11 @@ module RangeStage LangParam> {
private predicate boundCondition(
SemRelationalExpr comp, SemSsaVariable v, SemExpr e, float delta, boolean upper
) {
- comp.getLesserOperand() = LangParam::semSsaRead(v, D::fromFloat(delta)) and
+ comp.getLesserOperand() = UtilParam::semSsaRead(v, D::fromFloat(delta)) and
e = comp.getGreaterOperand() and
upper = true
or
- comp.getGreaterOperand() = LangParam::semSsaRead(v, D::fromFloat(delta)) and
+ comp.getGreaterOperand() = UtilParam::semSsaRead(v, D::fromFloat(delta)) and
e = comp.getLesserOperand() and
upper = false
or
@@ -243,7 +339,7 @@ module RangeStage LangParam> {
// (v - d) - e < c
comp.getLesserOperand() = sub and
comp.getGreaterOperand() = c and
- sub.getLeftOperand() = LangParam::semSsaRead(v, D::fromFloat(d)) and
+ sub.getLeftOperand() = UtilParam::semSsaRead(v, D::fromFloat(d)) and
sub.getRightOperand() = e and
upper = true and
delta = d + c.getIntValue()
@@ -251,7 +347,7 @@ module RangeStage LangParam> {
// (v - d) - e > c
comp.getGreaterOperand() = sub and
comp.getLesserOperand() = c and
- sub.getLeftOperand() = LangParam::semSsaRead(v, D::fromFloat(d)) and
+ sub.getLeftOperand() = UtilParam::semSsaRead(v, D::fromFloat(d)) and
sub.getRightOperand() = e and
upper = false and
delta = d + c.getIntValue()
@@ -260,7 +356,7 @@ module RangeStage LangParam> {
comp.getLesserOperand() = sub and
comp.getGreaterOperand() = c and
sub.getLeftOperand() = e and
- sub.getRightOperand() = LangParam::semSsaRead(v, D::fromFloat(d)) and
+ sub.getRightOperand() = UtilParam::semSsaRead(v, D::fromFloat(d)) and
upper = false and
delta = d - c.getIntValue()
or
@@ -268,7 +364,7 @@ module RangeStage LangParam> {
comp.getGreaterOperand() = sub and
comp.getLesserOperand() = c and
sub.getLeftOperand() = e and
- sub.getRightOperand() = LangParam::semSsaRead(v, D::fromFloat(d)) and
+ sub.getRightOperand() = UtilParam::semSsaRead(v, D::fromFloat(d)) and
upper = true and
delta = d - c.getIntValue()
)
@@ -338,8 +434,8 @@ module RangeStage LangParam> {
) and
(
if
- Utils::getTrackedTypeForSsaVariable(v) instanceof SemIntegerType or
- Utils::getTrackedTypeForSsaVariable(v) instanceof SemAddressType
+ UtilParam::getTrackedTypeForSsaVariable(v) instanceof SemIntegerType or
+ UtilParam::getTrackedTypeForSsaVariable(v) instanceof SemAddressType
then
upper = true and strengthen = -1
or
@@ -364,7 +460,7 @@ module RangeStage LangParam> {
semImplies_v2(result, testIsTrue, boundFlowCond(v, e, delta, upper, testIsTrue0), testIsTrue0)
)
or
- result = LangParam::semEqFlowCond(v, e, D::fromFloat(delta), true, testIsTrue) and
+ result = UtilParam::semEqFlowCond(v, e, D::fromFloat(delta), true, testIsTrue) and
(upper = true or upper = false)
or
// guard that tests whether `v2` is bounded by `e + delta + d1 - d2` and
@@ -373,7 +469,7 @@ module RangeStage LangParam> {
SemSsaVariable v2, SemGuard guardEq, boolean eqIsTrue, float d1, float d2, float oldDelta
|
guardEq =
- LangParam::semEqFlowCond(v, LangParam::semSsaRead(v2, D::fromFloat(d1)), D::fromFloat(d2),
+ UtilParam::semEqFlowCond(v, UtilParam::semSsaRead(v2, D::fromFloat(d1)), D::fromFloat(d2),
true, eqIsTrue) and
result = boundFlowCond(v2, e, oldDelta, upper, testIsTrue) and
// guardEq needs to control guard
@@ -421,7 +517,7 @@ module RangeStage LangParam> {
SemSsaVariable v, SemSsaReadPosition pos, SemExpr e, float delta, boolean upper,
SemReason reason
) {
- LangParam::semSsaUpdateStep(v, e, D::fromFloat(delta)) and
+ UtilParam::semSsaUpdateStep(v, e, D::fromFloat(delta)) and
pos.hasReadOfVar(v) and
(upper = true or upper = false) and
reason = TSemNoReason()
@@ -438,10 +534,10 @@ module RangeStage LangParam> {
private predicate unequalFlowStepIntegralSsa(
SemSsaVariable v, SemSsaReadPosition pos, SemExpr e, float delta, SemReason reason
) {
- Utils::getTrackedTypeForSsaVariable(v) instanceof SemIntegerType and
+ UtilParam::getTrackedTypeForSsaVariable(v) instanceof SemIntegerType and
exists(SemGuard guard, boolean testIsTrue |
pos.hasReadOfVar(v) and
- guard = LangParam::semEqFlowCond(v, e, D::fromFloat(delta), false, testIsTrue) and
+ guard = UtilParam::semEqFlowCond(v, e, D::fromFloat(delta), false, testIsTrue) and
semGuardDirectlyControlsSsaRead(guard, pos, testIsTrue) and
reason = TSemCondReason(guard)
)
@@ -449,12 +545,12 @@ module RangeStage LangParam> {
/** Holds if `e >= 1` as determined by sign analysis. */
private predicate strictlyPositiveIntegralExpr(SemExpr e) {
- semStrictlyPositive(e) and Utils::getTrackedType(e) instanceof SemIntegerType
+ semStrictlyPositive(e) and UtilParam::getTrackedType(e) instanceof SemIntegerType
}
/** Holds if `e <= -1` as determined by sign analysis. */
private predicate strictlyNegativeIntegralExpr(SemExpr e) {
- semStrictlyNegative(e) and Utils::getTrackedType(e) instanceof SemIntegerType
+ semStrictlyNegative(e) and UtilParam::getTrackedType(e) instanceof SemIntegerType
}
/**
@@ -463,7 +559,7 @@ module RangeStage LangParam> {
* - `upper = false` : `e2 >= e1 + delta`
*/
private predicate boundFlowStep(SemExpr e2, SemExpr e1, float delta, boolean upper) {
- LangParam::semValueFlowStep(e2, e1, D::fromFloat(delta)) and
+ UtilParam::semValueFlowStep(e2, e1, D::fromFloat(delta)) and
(upper = true or upper = false)
or
e2.(SafeCastExpr).getOperand() = e1 and
@@ -526,7 +622,7 @@ module RangeStage LangParam> {
delta = 0 and
upper = false
or
- LangParam::hasBound(e2, e1, delta, upper)
+ LangParam::hasBound(e2, e1, D::fromFloat(delta), upper)
}
/** Holds if `e2 = e1 * factor` and `factor > 0`. */
@@ -768,7 +864,7 @@ module RangeStage LangParam> {
* (for `upper = false`) bound of `b`.
*/
private predicate baseBound(SemExpr e, float b, boolean upper) {
- LangParam::hasConstantBound(e, b, upper)
+ LangParam::hasConstantBound(e, D::fromFloat(b), upper)
or
upper = false and
b = 0 and
diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeUtils.qll b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeUtils.qll
index 0bd7a407f1e..bc10fe156be 100644
--- a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeUtils.qll
+++ b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeUtils.qll
@@ -3,133 +3,136 @@
*/
private import experimental.semmle.code.cpp.semantic.Semantic
-private import RangeAnalysisSpecific as Specific
+private import RangeAnalysisSpecific
+private import RangeAnalysisStage as Range
private import ConstantAnalysis
-/**
- * Gets an expression that equals `v - d`.
- */
-SemExpr semSsaRead(SemSsaVariable v, int delta) {
- // There are various language-specific extension points that can be removed once we no longer
- // expect to match the original Java implementation's results exactly.
- result = v.getAUse() and delta = 0
- or
- exists(int d1, SemConstantIntegerExpr c |
- result.(SemAddExpr).hasOperands(semSsaRead(v, d1), c) and
- delta = d1 - c.getIntValue() and
- not Specific::ignoreSsaReadArithmeticExpr(result)
- )
- or
- exists(SemSubExpr sub, int d1, SemConstantIntegerExpr c |
- result = sub and
- sub.getLeftOperand() = semSsaRead(v, d1) and
- sub.getRightOperand() = c and
- delta = d1 + c.getIntValue() and
- not Specific::ignoreSsaReadArithmeticExpr(result)
- )
- or
- result = v.(SemSsaExplicitUpdate).getSourceExpr() and
- delta = 0 and
- not Specific::ignoreSsaReadAssignment(v)
- or
- result = Specific::specificSsaRead(v, delta)
- or
- result.(SemCopyValueExpr).getOperand() = semSsaRead(v, delta) and
- not Specific::ignoreSsaReadCopy(result)
- or
- result.(SemStoreExpr).getOperand() = semSsaRead(v, delta)
-}
-
-/**
- * Gets a condition that tests whether `v` equals `e + delta`.
- *
- * If the condition evaluates to `testIsTrue`:
- * - `isEq = true` : `v == e + delta`
- * - `isEq = false` : `v != e + delta`
- */
-SemGuard semEqFlowCond(SemSsaVariable v, SemExpr e, int delta, boolean isEq, boolean testIsTrue) {
- exists(boolean eqpolarity |
- result.isEquality(semSsaRead(v, delta), e, eqpolarity) and
- (testIsTrue = true or testIsTrue = false) and
- eqpolarity.booleanXor(testIsTrue).booleanNot() = isEq
- )
- or
- exists(boolean testIsTrue0 |
- semImplies_v2(result, testIsTrue, semEqFlowCond(v, e, delta, isEq, testIsTrue0), testIsTrue0)
- )
-}
-
-/**
- * Holds if `v` is an `SsaExplicitUpdate` that equals `e + delta`.
- */
-predicate semSsaUpdateStep(SemSsaExplicitUpdate v, SemExpr e, int delta) {
- exists(SemExpr defExpr | defExpr = v.getSourceExpr() |
- defExpr.(SemCopyValueExpr).getOperand() = e and delta = 0
+module RangeUtil Lang> implements Range::UtilSig {
+ /**
+ * Gets an expression that equals `v - d`.
+ */
+ SemExpr semSsaRead(SemSsaVariable v, D::Delta delta) {
+ // There are various language-specific extension points that can be removed once we no longer
+ // expect to match the original Java implementation's results exactly.
+ result = v.getAUse() and delta = D::fromInt(0)
or
- defExpr.(SemStoreExpr).getOperand() = e and delta = 0
+ exists(D::Delta d1, SemConstantIntegerExpr c |
+ result.(SemAddExpr).hasOperands(semSsaRead(v, d1), c) and
+ delta = D::fromFloat(D::toFloat(d1) - c.getIntValue()) and
+ not Lang::ignoreSsaReadArithmeticExpr(result)
+ )
or
- defExpr.(SemAddOneExpr).getOperand() = e and delta = 1
+ exists(SemSubExpr sub, float d1, SemConstantIntegerExpr c |
+ result = sub and
+ sub.getLeftOperand() = semSsaRead(v, D::fromFloat(d1)) and
+ sub.getRightOperand() = c and
+ delta = D::fromFloat(d1 + c.getIntValue()) and
+ not Lang::ignoreSsaReadArithmeticExpr(result)
+ )
or
- defExpr.(SemSubOneExpr).getOperand() = e and delta = -1
+ result = v.(SemSsaExplicitUpdate).getSourceExpr() and
+ delta = D::fromFloat(0) and
+ not Lang::ignoreSsaReadAssignment(v)
or
- e = defExpr and
- not (
- defExpr instanceof SemCopyValueExpr or
- defExpr instanceof SemStoreExpr or
- defExpr instanceof SemAddOneExpr or
- defExpr instanceof SemSubOneExpr
- ) and
- delta = 0
- )
-}
+ result = Lang::specificSsaRead(v, delta)
+ or
+ result.(SemCopyValueExpr).getOperand() = semSsaRead(v, delta) and
+ not Lang::ignoreSsaReadCopy(result)
+ or
+ result.(SemStoreExpr).getOperand() = semSsaRead(v, delta)
+ }
-/**
- * Holds if `e1 + delta` equals `e2`.
- */
-predicate semValueFlowStep(SemExpr e2, SemExpr e1, int delta) {
- e2.(SemCopyValueExpr).getOperand() = e1 and delta = 0
- or
- e2.(SemStoreExpr).getOperand() = e1 and delta = 0
- or
- e2.(SemAddOneExpr).getOperand() = e1 and delta = 1
- or
- e2.(SemSubOneExpr).getOperand() = e1 and delta = -1
- or
- Specific::additionalValueFlowStep(e2, e1, delta)
- or
- exists(SemExpr x | e2.(SemAddExpr).hasOperands(e1, x) |
- x.(SemConstantIntegerExpr).getIntValue() = delta
- )
- or
- exists(SemExpr x, SemSubExpr sub |
- e2 = sub and
- sub.getLeftOperand() = e1 and
- sub.getRightOperand() = x
- |
- x.(SemConstantIntegerExpr).getIntValue() = -delta
- )
-}
+ /**
+ * Gets a condition that tests whether `v` equals `e + delta`.
+ *
+ * If the condition evaluates to `testIsTrue`:
+ * - `isEq = true` : `v == e + delta`
+ * - `isEq = false` : `v != e + delta`
+ */
+ SemGuard semEqFlowCond(SemSsaVariable v, SemExpr e, D::Delta delta, boolean isEq, boolean testIsTrue) {
+ exists(boolean eqpolarity |
+ result.isEquality(semSsaRead(v, delta), e, eqpolarity) and
+ (testIsTrue = true or testIsTrue = false) and
+ eqpolarity.booleanXor(testIsTrue).booleanNot() = isEq
+ )
+ or
+ exists(boolean testIsTrue0 |
+ semImplies_v2(result, testIsTrue, semEqFlowCond(v, e, delta, isEq, testIsTrue0), testIsTrue0)
+ )
+ }
-/**
- * Gets the type used to track the specified expression's range information.
- *
- * Usually, this just `e.getSemType()`, but the language can override this to track immutable boxed
- * primitive types as the underlying primitive type.
- */
-SemType getTrackedType(SemExpr e) {
- result = Specific::getAlternateType(e)
- or
- not exists(Specific::getAlternateType(e)) and result = e.getSemType()
-}
+ /**
+ * Holds if `v` is an `SsaExplicitUpdate` that equals `e + delta`.
+ */
+ predicate semSsaUpdateStep(SemSsaExplicitUpdate v, SemExpr e, D::Delta delta) {
+ exists(SemExpr defExpr | defExpr = v.getSourceExpr() |
+ defExpr.(SemCopyValueExpr).getOperand() = e and delta = D::fromFloat(0)
+ or
+ defExpr.(SemStoreExpr).getOperand() = e and delta = D::fromFloat(0)
+ or
+ defExpr.(SemAddOneExpr).getOperand() = e and delta = D::fromFloat(1)
+ or
+ defExpr.(SemSubOneExpr).getOperand() = e and delta = D::fromFloat(-1)
+ or
+ e = defExpr and
+ not (
+ defExpr instanceof SemCopyValueExpr or
+ defExpr instanceof SemStoreExpr or
+ defExpr instanceof SemAddOneExpr or
+ defExpr instanceof SemSubOneExpr
+ ) and
+ delta = D::fromFloat(0)
+ )
+ }
-/**
- * Gets the type used to track the specified source variable's range information.
- *
- * Usually, this just `e.getType()`, but the language can override this to track immutable boxed
- * primitive types as the underlying primitive type.
- */
-SemType getTrackedTypeForSsaVariable(SemSsaVariable var) {
- result = Specific::getAlternateTypeForSsaVariable(var)
- or
- not exists(Specific::getAlternateTypeForSsaVariable(var)) and result = var.getType()
+ /**
+ * Holds if `e1 + delta` equals `e2`.
+ */
+ predicate semValueFlowStep(SemExpr e2, SemExpr e1, D::Delta delta) {
+ e2.(SemCopyValueExpr).getOperand() = e1 and delta = D::fromFloat(0)
+ or
+ e2.(SemStoreExpr).getOperand() = e1 and delta = D::fromFloat(0)
+ or
+ e2.(SemAddOneExpr).getOperand() = e1 and delta = D::fromFloat(1)
+ or
+ e2.(SemSubOneExpr).getOperand() = e1 and delta = D::fromFloat(-1)
+ or
+ Lang::additionalValueFlowStep(e2, e1, delta)
+ or
+ exists(SemExpr x | e2.(SemAddExpr).hasOperands(e1, x) |
+ D::fromInt(x.(SemConstantIntegerExpr).getIntValue()) = delta
+ )
+ or
+ exists(SemExpr x, SemSubExpr sub |
+ e2 = sub and
+ sub.getLeftOperand() = e1 and
+ sub.getRightOperand() = x
+ |
+ D::fromInt(-x.(SemConstantIntegerExpr).getIntValue()) = delta
+ )
+ }
+
+ /**
+ * Gets the type used to track the specified expression's range information.
+ *
+ * Usually, this just `e.getSemType()`, but the language can override this to track immutable boxed
+ * primitive types as the underlying primitive type.
+ */
+ SemType getTrackedType(SemExpr e) {
+ result = Lang::getAlternateType(e)
+ or
+ not exists(Lang::getAlternateType(e)) and result = e.getSemType()
+ }
+
+ /**
+ * Gets the type used to track the specified source variable's range information.
+ *
+ * Usually, this just `e.getType()`, but the language can override this to track immutable boxed
+ * primitive types as the underlying primitive type.
+ */
+ SemType getTrackedTypeForSsaVariable(SemSsaVariable var) {
+ result = Lang::getAlternateTypeForSsaVariable(var)
+ or
+ not exists(Lang::getAlternateTypeForSsaVariable(var)) and result = var.getType()
+ }
}
diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/SignAnalysisCommon.qll b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/SignAnalysisCommon.qll
index 970a6c4e5a9..94ef40e83fa 100644
--- a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/SignAnalysisCommon.qll
+++ b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/SignAnalysisCommon.qll
@@ -6,488 +6,494 @@
* three-valued domain `{negative, zero, positive}`.
*/
+private import RangeAnalysisStage
private import SignAnalysisSpecific as Specific
private import experimental.semmle.code.cpp.semantic.Semantic
private import ConstantAnalysis
private import RangeUtils
private import Sign
-/**
- * An SSA definition for which the analysis can compute the sign.
- *
- * The actual computation of the sign is done in an override of the `getSign()` predicate. The
- * charpred of any subclass must _not_ invoke `getSign()`, directly or indirectly. This ensures
- * that the charpred does not introduce negative recursion. The `getSign()` predicate may be
- * recursive.
- */
-abstract private class SignDef instanceof SemSsaVariable {
- final string toString() { result = super.toString() }
+module SignAnalysis Utils> {
+ /**
+ * An SSA definition for which the analysis can compute the sign.
+ *
+ * The actual computation of the sign is done in an override of the `getSign()` predicate. The
+ * charpred of any subclass must _not_ invoke `getSign()`, directly or indirectly. This ensures
+ * that the charpred does not introduce negative recursion. The `getSign()` predicate may be
+ * recursive.
+ */
+ abstract private class SignDef instanceof SemSsaVariable {
+ final string toString() { result = super.toString() }
- /** Gets the possible signs of this SSA definition. */
- abstract Sign getSign();
-}
-
-/** An SSA definition whose sign is computed based on standard flow. */
-abstract private class FlowSignDef extends SignDef {
- abstract override Sign getSign();
-}
-
-/** An SSA definition whose sign is determined by the sign of that definitions source expression. */
-private class ExplicitSignDef extends FlowSignDef instanceof SemSsaExplicitUpdate {
- final override Sign getSign() { result = semExprSign(super.getSourceExpr()) }
-}
-
-/** An SSA Phi definition, whose sign is the union of the signs of its inputs. */
-private class PhiSignDef extends FlowSignDef instanceof SemSsaPhiNode {
- final override Sign getSign() {
- exists(SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge |
- edge.phiInput(this, inp) and
- result = semSsaSign(inp, edge)
- )
- }
-}
-
-/** An SSA definition whose sign is computed by a language-specific implementation. */
-abstract class CustomSignDef extends SignDef {
- abstract override Sign getSign();
-}
-
-/**
- * An expression for which the analysis can compute the sign.
- *
- * The actual computation of the sign is done in an override of the `getSign()` predicate. The
- * charpred of any subclass must _not_ invoke `getSign()`, directly or indirectly. This ensures
- * that the charpred does not introduce negative recursion. The `getSign()` predicate may be
- * recursive.
- *
- * Concrete implementations extend one of the following subclasses:
- * - `ConstantSignExpr`, for expressions with a compile-time constant value.
- * - `FlowSignExpr`, for expressions whose sign can be computed from the signs of their operands.
- * - `CustomsignExpr`, for expressions whose sign can be computed by a language-specific
- * implementation.
- *
- * If the same expression matches more than one of the above subclasses, the sign is computed as
- * follows:
- * - The sign of a `ConstantSignExpr` is computed solely from `ConstantSignExpr.getSign()`,
- * regardless of any other subclasses.
- * - If a non-`ConstantSignExpr` expression matches exactly one of `FlowSignExpr` or
- * `CustomSignExpr`, the sign is computed by that class' `getSign()` predicate.
- * - If a non-`ConstantSignExpr` expression matches both `FlowSignExpr` and `CustomSignExpr`, the
- * sign is the _intersection_ of the signs of those two classes' `getSign()` predicates. Thus,
- * both classes have the opportunity to _restrict_ the set of possible signs, not to generate new
- * possible signs.
- * - If an expression does not match any of the three subclasses, then it can have any sign.
- *
- * Note that the `getSign()` predicate is introduced only in subclasses of `SignExpr`.
- */
-abstract class SignExpr instanceof SemExpr {
- SignExpr() { not Specific::ignoreExprSign(this) }
-
- final string toString() { result = super.toString() }
-
- abstract Sign getSign();
-}
-
-/** An expression whose sign is determined by its constant numeric value. */
-private class ConstantSignExpr extends SignExpr {
- ConstantSignExpr() {
- this instanceof SemConstantIntegerExpr or
- exists(this.(SemNumericLiteralExpr).getApproximateFloatValue())
+ /** Gets the possible signs of this SSA definition. */
+ abstract Sign getSign();
}
- final override Sign getSign() {
- exists(int i | this.(SemConstantIntegerExpr).getIntValue() = i |
- i < 0 and result = TNeg()
+ /** An SSA definition whose sign is computed based on standard flow. */
+ abstract private class FlowSignDef extends SignDef {
+ abstract override Sign getSign();
+ }
+
+ /** An SSA definition whose sign is determined by the sign of that definitions source expression. */
+ private class ExplicitSignDef extends FlowSignDef instanceof SemSsaExplicitUpdate {
+ final override Sign getSign() { result = semExprSign(super.getSourceExpr()) }
+ }
+
+ /** An SSA Phi definition, whose sign is the union of the signs of its inputs. */
+ private class PhiSignDef extends FlowSignDef instanceof SemSsaPhiNode {
+ final override Sign getSign() {
+ exists(SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge |
+ edge.phiInput(this, inp) and
+ result = semSsaSign(inp, edge)
+ )
+ }
+ }
+
+ /** An SSA definition whose sign is computed by a language-specific implementation. */
+ abstract class CustomSignDef extends SignDef {
+ abstract override Sign getSign();
+ }
+
+ /**
+ * An expression for which the analysis can compute the sign.
+ *
+ * The actual computation of the sign is done in an override of the `getSign()` predicate. The
+ * charpred of any subclass must _not_ invoke `getSign()`, directly or indirectly. This ensures
+ * that the charpred does not introduce negative recursion. The `getSign()` predicate may be
+ * recursive.
+ *
+ * Concrete implementations extend one of the following subclasses:
+ * - `ConstantSignExpr`, for expressions with a compile-time constant value.
+ * - `FlowSignExpr`, for expressions whose sign can be computed from the signs of their operands.
+ * - `CustomsignExpr`, for expressions whose sign can be computed by a language-specific
+ * implementation.
+ *
+ * If the same expression matches more than one of the above subclasses, the sign is computed as
+ * follows:
+ * - The sign of a `ConstantSignExpr` is computed solely from `ConstantSignExpr.getSign()`,
+ * regardless of any other subclasses.
+ * - If a non-`ConstantSignExpr` expression matches exactly one of `FlowSignExpr` or
+ * `CustomSignExpr`, the sign is computed by that class' `getSign()` predicate.
+ * - If a non-`ConstantSignExpr` expression matches both `FlowSignExpr` and `CustomSignExpr`, the
+ * sign is the _intersection_ of the signs of those two classes' `getSign()` predicates. Thus,
+ * both classes have the opportunity to _restrict_ the set of possible signs, not to generate new
+ * possible signs.
+ * - If an expression does not match any of the three subclasses, then it can have any sign.
+ *
+ * Note that the `getSign()` predicate is introduced only in subclasses of `SignExpr`.
+ */
+ abstract class SignExpr instanceof SemExpr {
+ SignExpr() { not Specific::ignoreExprSign(this) }
+
+ final string toString() { result = super.toString() }
+
+ abstract Sign getSign();
+ }
+
+ /** An expression whose sign is determined by its constant numeric value. */
+ private class ConstantSignExpr extends SignExpr {
+ ConstantSignExpr() {
+ this instanceof SemConstantIntegerExpr or
+ exists(this.(SemNumericLiteralExpr).getApproximateFloatValue())
+ }
+
+ final override Sign getSign() {
+ exists(int i | this.(SemConstantIntegerExpr).getIntValue() = i |
+ i < 0 and result = TNeg()
+ or
+ i = 0 and result = TZero()
+ or
+ i > 0 and result = TPos()
+ )
or
- i = 0 and result = TZero()
- or
- i > 0 and result = TPos()
- )
- or
- not exists(this.(SemConstantIntegerExpr).getIntValue()) and
- exists(float f | f = this.(SemNumericLiteralExpr).getApproximateFloatValue() |
- f < 0 and result = TNeg()
- or
- f = 0 and result = TZero()
- or
- f > 0 and result = TPos()
- )
- }
-}
-
-abstract private class NonConstantSignExpr extends SignExpr {
- NonConstantSignExpr() { not this instanceof ConstantSignExpr }
-
- final override Sign getSign() {
- // The result is the _intersection_ of the signs computed from flow and by the language.
- (result = this.(FlowSignExpr).getSignRestriction() or not this instanceof FlowSignExpr) and
- (result = this.(CustomSignExpr).getSignRestriction() or not this instanceof CustomSignExpr)
- }
-}
-
-/** An expression whose sign is computed from the signs of its operands. */
-abstract private class FlowSignExpr extends NonConstantSignExpr {
- abstract Sign getSignRestriction();
-}
-
-/** An expression whose sign is computed by a language-specific implementation. */
-abstract class CustomSignExpr extends NonConstantSignExpr {
- abstract Sign getSignRestriction();
-}
-
-/** An expression whose sign is unknown. */
-private class UnknownSignExpr extends SignExpr {
- UnknownSignExpr() {
- not this instanceof FlowSignExpr and
- not this instanceof CustomSignExpr and
- not this instanceof ConstantSignExpr and
- (
- // Only track numeric types.
- getTrackedType(this) instanceof SemNumericType
- or
- // Unless the language says to track this expression anyway.
- Specific::trackUnknownNonNumericExpr(this)
- )
+ not exists(this.(SemConstantIntegerExpr).getIntValue()) and
+ exists(float f | f = this.(SemNumericLiteralExpr).getApproximateFloatValue() |
+ f < 0 and result = TNeg()
+ or
+ f = 0 and result = TZero()
+ or
+ f > 0 and result = TPos()
+ )
+ }
}
- final override Sign getSign() { semAnySign(result) }
-}
+ abstract private class NonConstantSignExpr extends SignExpr {
+ NonConstantSignExpr() { not this instanceof ConstantSignExpr }
-/**
- * A `Load` expression whose sign is computed from the sign of its SSA definition, restricted by
- * inference from any intervening guards.
- */
-class UseSignExpr extends FlowSignExpr {
- SemSsaVariable v;
-
- UseSignExpr() { v.getAUse() = this }
-
- override Sign getSignRestriction() {
- // Propagate via SSA
- // Propagate the sign from the def of `v`, incorporating any inference from guards.
- result = semSsaSign(v, any(SemSsaReadPositionBlock bb | bb.getAnExpr() = this))
- or
- // No block for this read. Just use the sign of the def.
- // REVIEW: How can this happen?
- not exists(SemSsaReadPositionBlock bb | bb.getAnExpr() = this) and
- result = semSsaDefSign(v)
+ final override Sign getSign() {
+ // The result is the _intersection_ of the signs computed from flow and by the language.
+ (result = this.(FlowSignExpr).getSignRestriction() or not this instanceof FlowSignExpr) and
+ (result = this.(CustomSignExpr).getSignRestriction() or not this instanceof CustomSignExpr)
+ }
}
-}
-/** A binary expression whose sign is computed from the signs of its operands. */
-private class BinarySignExpr extends FlowSignExpr {
- SemBinaryExpr binary;
+ /** An expression whose sign is computed from the signs of its operands. */
+ abstract private class FlowSignExpr extends NonConstantSignExpr {
+ abstract Sign getSignRestriction();
+ }
- BinarySignExpr() { binary = this }
+ /** An expression whose sign is computed by a language-specific implementation. */
+ abstract class CustomSignExpr extends NonConstantSignExpr {
+ abstract Sign getSignRestriction();
+ }
- override Sign getSignRestriction() {
- exists(SemExpr left, SemExpr right |
- binaryExprOperands(binary, left, right) and
+ /** An expression whose sign is unknown. */
+ private class UnknownSignExpr extends SignExpr {
+ UnknownSignExpr() {
+ not this instanceof FlowSignExpr and
+ not this instanceof CustomSignExpr and
+ not this instanceof ConstantSignExpr and
+ (
+ // Only track numeric types.
+ Utils::getTrackedType(this) instanceof SemNumericType
+ or
+ // Unless the language says to track this expression anyway.
+ Specific::trackUnknownNonNumericExpr(this)
+ )
+ }
+
+ final override Sign getSign() { semAnySign(result) }
+ }
+
+ /**
+ * A `Load` expression whose sign is computed from the sign of its SSA definition, restricted by
+ * inference from any intervening guards.
+ */
+ class UseSignExpr extends FlowSignExpr {
+ SemSsaVariable v;
+
+ UseSignExpr() { v.getAUse() = this }
+
+ override Sign getSignRestriction() {
+ // Propagate via SSA
+ // Propagate the sign from the def of `v`, incorporating any inference from guards.
+ result = semSsaSign(v, any(SemSsaReadPositionBlock bb | bb.getAnExpr() = this))
+ or
+ // No block for this read. Just use the sign of the def.
+ // REVIEW: How can this happen?
+ not exists(SemSsaReadPositionBlock bb | bb.getAnExpr() = this) and
+ result = semSsaDefSign(v)
+ }
+ }
+
+ /** A binary expression whose sign is computed from the signs of its operands. */
+ private class BinarySignExpr extends FlowSignExpr {
+ SemBinaryExpr binary;
+
+ BinarySignExpr() { binary = this }
+
+ override Sign getSignRestriction() {
+ exists(SemExpr left, SemExpr right |
+ binaryExprOperands(binary, left, right) and
+ result =
+ semExprSign(pragma[only_bind_out](left))
+ .applyBinaryOp(semExprSign(pragma[only_bind_out](right)), binary.getOpcode())
+ )
+ or
+ exists(SemDivExpr div | div = binary |
+ result = semExprSign(div.getLeftOperand()) and
+ result != TZero() and
+ div.getRightOperand().(SemFloatingPointLiteralExpr).getFloatValue() = 0
+ )
+ }
+ }
+
+ pragma[nomagic]
+ private predicate binaryExprOperands(SemBinaryExpr binary, SemExpr left, SemExpr right) {
+ binary.getLeftOperand() = left and binary.getRightOperand() = right
+ }
+
+ /**
+ * A `Convert`, `Box`, or `Unbox` expression.
+ */
+ private class SemCastExpr instanceof SemUnaryExpr {
+ string toString() { result = super.toString() }
+
+ SemCastExpr() {
+ this instanceof SemConvertExpr
+ or
+ this instanceof SemBoxExpr
+ or
+ this instanceof SemUnboxExpr
+ }
+ }
+
+ /** A unary expression whose sign is computed from the sign of its operand. */
+ private class UnarySignExpr extends FlowSignExpr {
+ SemUnaryExpr unary;
+
+ UnarySignExpr() { unary = this and not this instanceof SemCastExpr }
+
+ override Sign getSignRestriction() {
result =
- semExprSign(pragma[only_bind_out](left))
- .applyBinaryOp(semExprSign(pragma[only_bind_out](right)), binary.getOpcode())
- )
- or
- exists(SemDivExpr div | div = binary |
- result = semExprSign(div.getLeftOperand()) and
- result != TZero() and
- div.getRightOperand().(SemFloatingPointLiteralExpr).getFloatValue() = 0
+ semExprSign(pragma[only_bind_out](unary.getOperand())).applyUnaryOp(unary.getOpcode())
+ }
+ }
+
+ /**
+ * A `Convert`, `Box`, or `Unbox` expression, whose sign is computed based on
+ * the sign of its operand and the source and destination types.
+ */
+ abstract private class CastSignExpr extends FlowSignExpr {
+ SemUnaryExpr cast;
+
+ CastSignExpr() { cast = this and cast instanceof SemCastExpr }
+
+ override Sign getSignRestriction() { result = semExprSign(cast.getOperand()) }
+ }
+
+ /**
+ * A `Convert` expression.
+ */
+ private class ConvertSignExpr extends CastSignExpr {
+ override SemConvertExpr cast;
+ }
+
+ /**
+ * A `Box` expression.
+ */
+ private class BoxSignExpr extends CastSignExpr {
+ override SemBoxExpr cast;
+ }
+
+ /**
+ * An `Unbox` expression.
+ */
+ private class UnboxSignExpr extends CastSignExpr {
+ override SemUnboxExpr cast;
+
+ UnboxSignExpr() {
+ exists(SemType fromType | fromType = Utils::getTrackedType(cast.getOperand()) |
+ // Only numeric source types are handled here.
+ fromType instanceof SemNumericType
+ )
+ }
+ }
+
+ private predicate unknownSign(SemExpr e) { e instanceof UnknownSignExpr }
+
+ /**
+ * Holds if `lowerbound` is a lower bound for `v` at `pos`. This is restricted
+ * to only include bounds for which we might determine a sign.
+ */
+ private predicate lowerBound(
+ SemExpr lowerbound, SemSsaVariable v, SemSsaReadPosition pos, boolean isStrict
+ ) {
+ exists(boolean testIsTrue, SemRelationalExpr comp |
+ pos.hasReadOfVar(v) and
+ semGuardControlsSsaRead(semGetComparisonGuard(comp), pos, testIsTrue) and
+ not unknownSign(lowerbound)
+ |
+ testIsTrue = true and
+ comp.getLesserOperand() = lowerbound and
+ comp.getGreaterOperand() = Utils::semSsaRead(v, D::fromInt(0)) and
+ (if comp.isStrict() then isStrict = true else isStrict = false)
+ or
+ testIsTrue = false and
+ comp.getGreaterOperand() = lowerbound and
+ comp.getLesserOperand() = Utils::semSsaRead(v, D::fromInt(0)) and
+ (if comp.isStrict() then isStrict = false else isStrict = true)
)
}
-}
-pragma[nomagic]
-private predicate binaryExprOperands(SemBinaryExpr binary, SemExpr left, SemExpr right) {
- binary.getLeftOperand() = left and binary.getRightOperand() = right
-}
-
-/**
- * A `Convert`, `Box`, or `Unbox` expression.
- */
-private class SemCastExpr extends SemUnaryExpr {
- SemCastExpr() {
- this instanceof SemConvertExpr
- or
- this instanceof SemBoxExpr
- or
- this instanceof SemUnboxExpr
- }
-}
-
-/** A unary expression whose sign is computed from the sign of its operand. */
-private class UnarySignExpr extends FlowSignExpr {
- SemUnaryExpr unary;
-
- UnarySignExpr() { unary = this and not this instanceof SemCastExpr }
-
- override Sign getSignRestriction() {
- result = semExprSign(pragma[only_bind_out](unary.getOperand())).applyUnaryOp(unary.getOpcode())
- }
-}
-
-/**
- * A `Convert`, `Box`, or `Unbox` expression, whose sign is computed based on
- * the sign of its operand and the source and destination types.
- */
-abstract private class CastSignExpr extends FlowSignExpr {
- SemUnaryExpr cast;
-
- CastSignExpr() { cast = this and cast instanceof SemCastExpr }
-
- override Sign getSignRestriction() { result = semExprSign(cast.getOperand()) }
-}
-
-/**
- * A `Convert` expression.
- */
-private class ConvertSignExpr extends CastSignExpr {
- override SemConvertExpr cast;
-}
-
-/**
- * A `Box` expression.
- */
-private class BoxSignExpr extends CastSignExpr {
- override SemBoxExpr cast;
-}
-
-/**
- * An `Unbox` expression.
- */
-private class UnboxSignExpr extends CastSignExpr {
- override SemUnboxExpr cast;
-
- UnboxSignExpr() {
- exists(SemType fromType | fromType = getTrackedType(cast.getOperand()) |
- // Only numeric source types are handled here.
- fromType instanceof SemNumericType
+ /**
+ * Holds if `upperbound` is an upper bound for `v` at `pos`. This is restricted
+ * to only include bounds for which we might determine a sign.
+ */
+ private predicate upperBound(
+ SemExpr upperbound, SemSsaVariable v, SemSsaReadPosition pos, boolean isStrict
+ ) {
+ exists(boolean testIsTrue, SemRelationalExpr comp |
+ pos.hasReadOfVar(v) and
+ semGuardControlsSsaRead(semGetComparisonGuard(comp), pos, testIsTrue) and
+ not unknownSign(upperbound)
+ |
+ testIsTrue = true and
+ comp.getGreaterOperand() = upperbound and
+ comp.getLesserOperand() = Utils::semSsaRead(v, D::fromInt(0)) and
+ (if comp.isStrict() then isStrict = true else isStrict = false)
+ or
+ testIsTrue = false and
+ comp.getLesserOperand() = upperbound and
+ comp.getGreaterOperand() = Utils::semSsaRead(v, D::fromInt(0)) and
+ (if comp.isStrict() then isStrict = false else isStrict = true)
)
}
-}
-private predicate unknownSign(SemExpr e) { e instanceof UnknownSignExpr }
+ /**
+ * Holds if `eqbound` is an equality/inequality for `v` at `pos`. This is
+ * restricted to only include bounds for which we might determine a sign. The
+ * boolean `isEq` gives the polarity:
+ * - `isEq = true` : `v = eqbound`
+ * - `isEq = false` : `v != eqbound`
+ */
+ private predicate eqBound(SemExpr eqbound, SemSsaVariable v, SemSsaReadPosition pos, boolean isEq) {
+ exists(SemGuard guard, boolean testIsTrue, boolean polarity |
+ pos.hasReadOfVar(v) and
+ semGuardControlsSsaRead(guard, pos, testIsTrue) and
+ guard.isEquality(eqbound, Utils::semSsaRead(v, D::fromInt(0)), polarity) and
+ isEq = polarity.booleanXor(testIsTrue).booleanNot() and
+ not unknownSign(eqbound)
+ )
+ }
-/**
- * Holds if `lowerbound` is a lower bound for `v` at `pos`. This is restricted
- * to only include bounds for which we might determine a sign.
- */
-private predicate lowerBound(
- SemExpr lowerbound, SemSsaVariable v, SemSsaReadPosition pos, boolean isStrict
-) {
- exists(boolean testIsTrue, SemRelationalExpr comp |
- pos.hasReadOfVar(v) and
- semGuardControlsSsaRead(semGetComparisonGuard(comp), pos, testIsTrue) and
- not unknownSign(lowerbound)
- |
- testIsTrue = true and
- comp.getLesserOperand() = lowerbound and
- comp.getGreaterOperand() = semSsaRead(v, 0) and
- (if comp.isStrict() then isStrict = true else isStrict = false)
+ /**
+ * Holds if `bound` is a bound for `v` at `pos` that needs to be positive in
+ * order for `v` to be positive.
+ */
+ private predicate posBound(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) {
+ upperBound(bound, v, pos, _) or
+ eqBound(bound, v, pos, true)
+ }
+
+ /**
+ * Holds if `bound` is a bound for `v` at `pos` that needs to be negative in
+ * order for `v` to be negative.
+ */
+ private predicate negBound(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) {
+ lowerBound(bound, v, pos, _) or
+ eqBound(bound, v, pos, true)
+ }
+
+ /**
+ * Holds if `bound` is a bound for `v` at `pos` that can restrict whether `v`
+ * can be zero.
+ */
+ private predicate zeroBound(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) {
+ lowerBound(bound, v, pos, _) or
+ upperBound(bound, v, pos, _) or
+ eqBound(bound, v, pos, _)
+ }
+
+ /** Holds if `bound` allows `v` to be positive at `pos`. */
+ private predicate posBoundOk(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) {
+ posBound(bound, v, pos) and TPos() = semExprSign(bound)
+ }
+
+ /** Holds if `bound` allows `v` to be negative at `pos`. */
+ private predicate negBoundOk(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) {
+ negBound(bound, v, pos) and TNeg() = semExprSign(bound)
+ }
+
+ /** Holds if `bound` allows `v` to be zero at `pos`. */
+ private predicate zeroBoundOk(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) {
+ lowerBound(bound, v, pos, _) and TNeg() = semExprSign(bound)
or
- testIsTrue = false and
- comp.getGreaterOperand() = lowerbound and
- comp.getLesserOperand() = semSsaRead(v, 0) and
- (if comp.isStrict() then isStrict = false else isStrict = true)
- )
-}
-
-/**
- * Holds if `upperbound` is an upper bound for `v` at `pos`. This is restricted
- * to only include bounds for which we might determine a sign.
- */
-private predicate upperBound(
- SemExpr upperbound, SemSsaVariable v, SemSsaReadPosition pos, boolean isStrict
-) {
- exists(boolean testIsTrue, SemRelationalExpr comp |
- pos.hasReadOfVar(v) and
- semGuardControlsSsaRead(semGetComparisonGuard(comp), pos, testIsTrue) and
- not unknownSign(upperbound)
- |
- testIsTrue = true and
- comp.getGreaterOperand() = upperbound and
- comp.getLesserOperand() = semSsaRead(v, 0) and
- (if comp.isStrict() then isStrict = true else isStrict = false)
+ lowerBound(bound, v, pos, false) and TZero() = semExprSign(bound)
or
- testIsTrue = false and
- comp.getLesserOperand() = upperbound and
- comp.getGreaterOperand() = semSsaRead(v, 0) and
- (if comp.isStrict() then isStrict = false else isStrict = true)
- )
-}
+ upperBound(bound, v, pos, _) and TPos() = semExprSign(bound)
+ or
+ upperBound(bound, v, pos, false) and TZero() = semExprSign(bound)
+ or
+ eqBound(bound, v, pos, true) and TZero() = semExprSign(bound)
+ or
+ eqBound(bound, v, pos, false) and TZero() != semExprSign(bound)
+ }
-/**
- * Holds if `eqbound` is an equality/inequality for `v` at `pos`. This is
- * restricted to only include bounds for which we might determine a sign. The
- * boolean `isEq` gives the polarity:
- * - `isEq = true` : `v = eqbound`
- * - `isEq = false` : `v != eqbound`
- */
-private predicate eqBound(SemExpr eqbound, SemSsaVariable v, SemSsaReadPosition pos, boolean isEq) {
- exists(SemGuard guard, boolean testIsTrue, boolean polarity |
+ /**
+ * Holds if there is a bound that might restrict whether `v` has the sign `s`
+ * at `pos`.
+ */
+ private predicate hasGuard(SemSsaVariable v, SemSsaReadPosition pos, Sign s) {
+ s = TPos() and posBound(_, v, pos)
+ or
+ s = TNeg() and negBound(_, v, pos)
+ or
+ s = TZero() and zeroBound(_, v, pos)
+ }
+
+ /**
+ * Gets a possible sign of `v` at `pos` based on its definition, where the sign
+ * might be ruled out by a guard.
+ */
+ pragma[noinline]
+ private Sign guardedSsaSign(SemSsaVariable v, SemSsaReadPosition pos) {
+ result = semSsaDefSign(v) and
pos.hasReadOfVar(v) and
- semGuardControlsSsaRead(guard, pos, testIsTrue) and
- guard.isEquality(eqbound, semSsaRead(v, 0), polarity) and
- isEq = polarity.booleanXor(testIsTrue).booleanNot() and
- not unknownSign(eqbound)
- )
-}
-
-/**
- * Holds if `bound` is a bound for `v` at `pos` that needs to be positive in
- * order for `v` to be positive.
- */
-private predicate posBound(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) {
- upperBound(bound, v, pos, _) or
- eqBound(bound, v, pos, true)
-}
-
-/**
- * Holds if `bound` is a bound for `v` at `pos` that needs to be negative in
- * order for `v` to be negative.
- */
-private predicate negBound(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) {
- lowerBound(bound, v, pos, _) or
- eqBound(bound, v, pos, true)
-}
-
-/**
- * Holds if `bound` is a bound for `v` at `pos` that can restrict whether `v`
- * can be zero.
- */
-private predicate zeroBound(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) {
- lowerBound(bound, v, pos, _) or
- upperBound(bound, v, pos, _) or
- eqBound(bound, v, pos, _)
-}
-
-/** Holds if `bound` allows `v` to be positive at `pos`. */
-private predicate posBoundOk(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) {
- posBound(bound, v, pos) and TPos() = semExprSign(bound)
-}
-
-/** Holds if `bound` allows `v` to be negative at `pos`. */
-private predicate negBoundOk(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) {
- negBound(bound, v, pos) and TNeg() = semExprSign(bound)
-}
-
-/** Holds if `bound` allows `v` to be zero at `pos`. */
-private predicate zeroBoundOk(SemExpr bound, SemSsaVariable v, SemSsaReadPosition pos) {
- lowerBound(bound, v, pos, _) and TNeg() = semExprSign(bound)
- or
- lowerBound(bound, v, pos, false) and TZero() = semExprSign(bound)
- or
- upperBound(bound, v, pos, _) and TPos() = semExprSign(bound)
- or
- upperBound(bound, v, pos, false) and TZero() = semExprSign(bound)
- or
- eqBound(bound, v, pos, true) and TZero() = semExprSign(bound)
- or
- eqBound(bound, v, pos, false) and TZero() != semExprSign(bound)
-}
-
-/**
- * Holds if there is a bound that might restrict whether `v` has the sign `s`
- * at `pos`.
- */
-private predicate hasGuard(SemSsaVariable v, SemSsaReadPosition pos, Sign s) {
- s = TPos() and posBound(_, v, pos)
- or
- s = TNeg() and negBound(_, v, pos)
- or
- s = TZero() and zeroBound(_, v, pos)
-}
-
-/**
- * Gets a possible sign of `v` at `pos` based on its definition, where the sign
- * might be ruled out by a guard.
- */
-pragma[noinline]
-private Sign guardedSsaSign(SemSsaVariable v, SemSsaReadPosition pos) {
- result = semSsaDefSign(v) and
- pos.hasReadOfVar(v) and
- hasGuard(v, pos, result)
-}
-
-/**
- * Gets a possible sign of `v` at `pos` based on its definition, where no guard
- * can rule it out.
- */
-pragma[noinline]
-private Sign unguardedSsaSign(SemSsaVariable v, SemSsaReadPosition pos) {
- result = semSsaDefSign(v) and
- pos.hasReadOfVar(v) and
- not hasGuard(v, pos, result)
-}
-
-/**
- * Gets a possible sign of `v` at read position `pos`, where a guard could have
- * ruled out the sign but does not.
- * This does not check that the definition of `v` also allows the sign.
- */
-private Sign guardedSsaSignOk(SemSsaVariable v, SemSsaReadPosition pos) {
- result = TPos() and
- forex(SemExpr bound | posBound(bound, v, pos) | posBoundOk(bound, v, pos))
- or
- result = TNeg() and
- forex(SemExpr bound | negBound(bound, v, pos) | negBoundOk(bound, v, pos))
- or
- result = TZero() and
- forex(SemExpr bound | zeroBound(bound, v, pos) | zeroBoundOk(bound, v, pos))
-}
-
-/** Gets a possible sign for `v` at `pos`. */
-private Sign semSsaSign(SemSsaVariable v, SemSsaReadPosition pos) {
- result = unguardedSsaSign(v, pos)
- or
- result = guardedSsaSign(v, pos) and
- result = guardedSsaSignOk(v, pos)
-}
-
-/** Gets a possible sign for `v`. */
-pragma[nomagic]
-Sign semSsaDefSign(SemSsaVariable v) { result = v.(SignDef).getSign() }
-
-/** Gets a possible sign for `e`. */
-cached
-Sign semExprSign(SemExpr e) {
- exists(Sign s | s = e.(SignExpr).getSign() |
- if
- getTrackedType(e) instanceof SemUnsignedIntegerType and
- s = TNeg() and
- not Specific::ignoreTypeRestrictions(e)
- then result = TPos()
- else result = s
- )
-}
-
-/**
- * Dummy predicate that holds for any sign. This is added to improve readability
- * of cases where the sign is unrestricted.
- */
-predicate semAnySign(Sign s) { any() }
-
-/** Holds if `e` can be positive and cannot be negative. */
-predicate semPositive(SemExpr e) {
- semExprSign(e) = TPos() and
- not semExprSign(e) = TNeg()
-}
-
-/** Holds if `e` can be negative and cannot be positive. */
-predicate semNegative(SemExpr e) {
- semExprSign(e) = TNeg() and
- not semExprSign(e) = TPos()
-}
-
-/** Holds if `e` is strictly positive. */
-predicate semStrictlyPositive(SemExpr e) {
- semExprSign(e) = TPos() and
- not semExprSign(e) = TNeg() and
- not semExprSign(e) = TZero()
-}
-
-/** Holds if `e` is strictly negative. */
-predicate semStrictlyNegative(SemExpr e) {
- semExprSign(e) = TNeg() and
- not semExprSign(e) = TPos() and
- not semExprSign(e) = TZero()
+ hasGuard(v, pos, result)
+ }
+
+ /**
+ * Gets a possible sign of `v` at `pos` based on its definition, where no guard
+ * can rule it out.
+ */
+ pragma[noinline]
+ private Sign unguardedSsaSign(SemSsaVariable v, SemSsaReadPosition pos) {
+ result = semSsaDefSign(v) and
+ pos.hasReadOfVar(v) and
+ not hasGuard(v, pos, result)
+ }
+
+ /**
+ * Gets a possible sign of `v` at read position `pos`, where a guard could have
+ * ruled out the sign but does not.
+ * This does not check that the definition of `v` also allows the sign.
+ */
+ private Sign guardedSsaSignOk(SemSsaVariable v, SemSsaReadPosition pos) {
+ result = TPos() and
+ forex(SemExpr bound | posBound(bound, v, pos) | posBoundOk(bound, v, pos))
+ or
+ result = TNeg() and
+ forex(SemExpr bound | negBound(bound, v, pos) | negBoundOk(bound, v, pos))
+ or
+ result = TZero() and
+ forex(SemExpr bound | zeroBound(bound, v, pos) | zeroBoundOk(bound, v, pos))
+ }
+
+ /** Gets a possible sign for `v` at `pos`. */
+ private Sign semSsaSign(SemSsaVariable v, SemSsaReadPosition pos) {
+ result = unguardedSsaSign(v, pos)
+ or
+ result = guardedSsaSign(v, pos) and
+ result = guardedSsaSignOk(v, pos)
+ }
+
+ /** Gets a possible sign for `v`. */
+ pragma[nomagic]
+ Sign semSsaDefSign(SemSsaVariable v) { result = v.(SignDef).getSign() }
+
+ /** Gets a possible sign for `e`. */
+ cached
+ Sign semExprSign(SemExpr e) {
+ exists(Sign s | s = e.(SignExpr).getSign() |
+ if
+ Utils::getTrackedType(e) instanceof SemUnsignedIntegerType and
+ s = TNeg() and
+ not Specific::ignoreTypeRestrictions(e)
+ then result = TPos()
+ else result = s
+ )
+ }
+
+ /**
+ * Dummy predicate that holds for any sign. This is added to improve readability
+ * of cases where the sign is unrestricted.
+ */
+ predicate semAnySign(Sign s) { any() }
+
+ /** Holds if `e` can be positive and cannot be negative. */
+ predicate semPositive(SemExpr e) {
+ semExprSign(e) = TPos() and
+ not semExprSign(e) = TNeg()
+ }
+
+ /** Holds if `e` can be negative and cannot be positive. */
+ predicate semNegative(SemExpr e) {
+ semExprSign(e) = TNeg() and
+ not semExprSign(e) = TPos()
+ }
+
+ /** Holds if `e` is strictly positive. */
+ predicate semStrictlyPositive(SemExpr e) {
+ semExprSign(e) = TPos() and
+ not semExprSign(e) = TNeg() and
+ not semExprSign(e) = TZero()
+ }
+
+ /** Holds if `e` is strictly negative. */
+ predicate semStrictlyNegative(SemExpr e) {
+ semExprSign(e) = TNeg() and
+ not semExprSign(e) = TPos() and
+ not semExprSign(e) = TZero()
+ }
}
From 71b93d125e5310c948d2715a1f132f69673ac27a Mon Sep 17 00:00:00 2001
From: Robert Marsh
Date: Fri, 16 Dec 2022 16:01:40 -0500
Subject: [PATCH 250/381] C++: Make RangeAnalysis.qll expose the old API
---
.../semmle/code/cpp/semantic/analysis/RangeAnalysis.qll | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysis.qll b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysis.qll
index 6d7ba2e9ff1..378bdd2dfc6 100644
--- a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysis.qll
+++ b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysis.qll
@@ -3,4 +3,5 @@ private import RangeAnalysisSpecific
private import FloatDelta
private import RangeUtils
-module CppRangeAnalysis = RangeStage>;
\ No newline at end of file
+private module CppRangeAnalysis = RangeStage>;
+import CppRangeAnalysis
\ No newline at end of file
From 02f1957919c513d132787ed1050cab276983ae2a Mon Sep 17 00:00:00 2001
From: Robert Marsh
Date: Mon, 19 Dec 2022 12:13:47 -0500
Subject: [PATCH 251/381] C++: make SemBound a RangeAnalysis parameter
---
.../cpp/semantic/analysis/ModulusAnalysis.qll | 36 +++++++++----------
.../cpp/semantic/analysis/RangeAnalysis.qll | 21 +++++++++--
.../analysis/RangeAnalysisSpecific.qll | 2 +-
.../semantic/analysis/RangeAnalysisStage.qll | 25 ++++++++++---
4 files changed, 59 insertions(+), 25 deletions(-)
diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/ModulusAnalysis.qll b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/ModulusAnalysis.qll
index 852dd40aad0..562e60db408 100644
--- a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/ModulusAnalysis.qll
+++ b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/ModulusAnalysis.qll
@@ -16,7 +16,7 @@ private import ConstantAnalysis
private import RangeUtils
private import RangeAnalysisStage
-module ModulusAnalysis U> {
+module ModulusAnalysis Bounds, UtilSig U> {
/**
* Holds if `e + delta` equals `v` at `pos`.
*/
@@ -146,7 +146,7 @@ module ModulusAnalysis U> {
private predicate phiSelfModulus(
SemSsaPhiNode phi, SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge, int mod
) {
- exists(SemSsaBound phibound, int v, int m |
+ exists(Bounds::SemSsaBound phibound, int v, int m |
edge.phiInput(phi, inp) and
phibound.getAVariable() = phi and
ssaModulus(inp, edge, phibound, v, m) and
@@ -158,7 +158,7 @@ module ModulusAnalysis U> {
/**
* Holds if `b + val` modulo `mod` is a candidate congruence class for `phi`.
*/
- private predicate phiModulusInit(SemSsaPhiNode phi, SemBound b, int val, int mod) {
+ private predicate phiModulusInit(SemSsaPhiNode phi, Bounds::SemBound b, int val, int mod) {
exists(SemSsaVariable inp, SemSsaReadPositionPhiInputEdge edge |
edge.phiInput(phi, inp) and
ssaModulus(inp, edge, b, val, mod)
@@ -169,7 +169,7 @@ module ModulusAnalysis U> {
* Holds if all inputs to `phi` numbered `1` to `rix` are equal to `b + val` modulo `mod`.
*/
pragma[nomagic]
- private predicate phiModulusRankStep(SemSsaPhiNode phi, SemBound b, int val, int mod, int rix) {
+ private predicate phiModulusRankStep(SemSsaPhiNode phi, Bounds::SemBound b, int val, int mod, int rix) {
/*
* base case. If any phi input is equal to `b + val` modulo `mod`, that's a potential congruence
* class for the phi node.
@@ -213,7 +213,7 @@ module ModulusAnalysis U> {
/**
* Holds if `phi` is equal to `b + val` modulo `mod`.
*/
- private predicate phiModulus(SemSsaPhiNode phi, SemBound b, int val, int mod) {
+ private predicate phiModulus(SemSsaPhiNode phi, Bounds::SemBound b, int val, int mod) {
exists(int r |
maxPhiInputRank(phi, r) and
phiModulusRankStep(phi, b, val, mod, r)
@@ -224,11 +224,11 @@ module ModulusAnalysis U> {
* Holds if `v` at `pos` is equal to `b + val` modulo `mod`.
*/
private predicate ssaModulus(
- SemSsaVariable v, SemSsaReadPosition pos, SemBound b, int val, int mod
+ SemSsaVariable v, SemSsaReadPosition pos, Bounds::SemBound b, int val, int mod
) {
phiModulus(v, b, val, mod) and pos.hasReadOfVar(v)
or
- b.(SemSsaBound).getAVariable() = v and pos.hasReadOfVar(v) and val = 0 and mod = 0
+ b.(Bounds::SemSsaBound).getAVariable() = v and pos.hasReadOfVar(v) and val = 0 and mod = 0
or
exists(SemExpr e, int val0, int delta |
semExprModulus(e, b, val0, mod) and
@@ -236,7 +236,7 @@ module ModulusAnalysis U> {
val = remainder(val0 + delta, mod)
)
or
- moduloGuardedRead(v, pos, val, mod) and b instanceof SemZeroBound
+ moduloGuardedRead(v, pos, val, mod) and b instanceof Bounds::SemZeroBound
}
/**
@@ -247,14 +247,14 @@ module ModulusAnalysis U> {
* - `mod > 1`: `val` lies within the range `[0 .. mod-1]`.
*/
cached
- predicate semExprModulus(SemExpr e, SemBound b, int val, int mod) {
+ predicate semExprModulus(SemExpr e, Bounds::SemBound b, int val, int mod) {
not ignoreExprModulus(e) and
(
- e = b.getExpr(val) and mod = 0
+ e = b.getExpr(D::fromInt(val)) and mod = 0
or
evenlyDivisibleExpr(e, mod) and
val = 0 and
- b instanceof SemZeroBound
+ b instanceof Bounds::SemZeroBound
or
exists(SemSsaVariable v, SemSsaReadPositionBlock bb |
ssaModulus(v, bb, b, val, mod) and
@@ -277,21 +277,21 @@ module ModulusAnalysis U> {
val = remainder(v1, mod)
)
or
- exists(SemBound b1, SemBound b2, int v1, int v2, int m1, int m2 |
+ exists(Bounds::SemBound b1, Bounds::SemBound b2, int v1, int v2, int m1, int m2 |
addModulus(e, true, b1, v1, m1) and
addModulus(e, false, b2, v2, m2) and
mod = m1.gcd(m2) and
mod != 1 and
val = remainder(v1 + v2, mod)
|
- b = b1 and b2 instanceof SemZeroBound
+ b = b1 and b2 instanceof Bounds::SemZeroBound
or
- b = b2 and b1 instanceof SemZeroBound
+ b = b2 and b1 instanceof Bounds::SemZeroBound
)
or
exists(int v1, int v2, int m1, int m2 |
subModulus(e, true, b, v1, m1) and
- subModulus(e, false, any(SemZeroBound zb), v2, m2) and
+ subModulus(e, false, any(Bounds::SemZeroBound zb), v2, m2) and
mod = m1.gcd(m2) and
mod != 1 and
val = remainder(v1 - v2, mod)
@@ -300,12 +300,12 @@ module ModulusAnalysis U> {
}
private predicate condExprBranchModulus(
- SemConditionalExpr cond, boolean branch, SemBound b, int val, int mod
+ SemConditionalExpr cond, boolean branch, Bounds::SemBound b, int val, int mod
) {
semExprModulus(cond.getBranchExpr(branch), b, val, mod)
}
- private predicate addModulus(SemExpr add, boolean isLeft, SemBound b, int val, int mod) {
+ private predicate addModulus(SemExpr add, boolean isLeft, Bounds::SemBound b, int val, int mod) {
exists(SemExpr larg, SemExpr rarg | nonConstAddition(add, larg, rarg) |
semExprModulus(larg, b, val, mod) and isLeft = true
or
@@ -313,7 +313,7 @@ module ModulusAnalysis U> {
)
}
- private predicate subModulus(SemExpr sub, boolean isLeft, SemBound b, int val, int mod) {
+ private predicate subModulus(SemExpr sub, boolean isLeft, Bounds::SemBound b, int val, int mod) {
exists(SemExpr larg, SemExpr rarg | nonConstSubtraction(sub, larg, rarg) |
semExprModulus(larg, b, val, mod) and isLeft = true
or
diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysis.qll b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysis.qll
index 378bdd2dfc6..6a4b209bb4b 100644
--- a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysis.qll
+++ b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysis.qll
@@ -2,6 +2,23 @@ private import RangeAnalysisStage
private import RangeAnalysisSpecific
private import FloatDelta
private import RangeUtils
+private import experimental.semmle.code.cpp.semantic.SemanticBound as SemanticBound
-private module CppRangeAnalysis = RangeStage>;
-import CppRangeAnalysis
\ No newline at end of file
+module Bounds implements BoundSig {
+ class SemBound instanceof SemanticBound::SemBound {
+ string toString() { result = super.toString() }
+
+ SemExpr getExpr(float delta) { result = super.getExpr(delta) }
+ }
+
+ class SemZeroBound extends SemBound instanceof SemanticBound::SemZeroBound { }
+
+ class SemSsaBound extends SemBound instanceof SemanticBound::SemSsaBound {
+ SemSsaVariable getAVariable() { result = this.(SemanticBound::SemSsaBound).getAVariable() }
+ }
+}
+
+private module CppRangeAnalysis =
+ RangeStage>;
+
+import CppRangeAnalysis
diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisSpecific.qll b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisSpecific.qll
index 769538fc4cf..8f64d891de2 100644
--- a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisSpecific.qll
+++ b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisSpecific.qll
@@ -89,4 +89,4 @@ module CppLangImpl implements LangSig {
* actually references but whose values can be tracked as the type contained in the box.
*/
SemType getAlternateTypeForSsaVariable(SemSsaVariable var) { none() }
-}
\ No newline at end of file
+}
diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisStage.qll b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisStage.qll
index 0da8dc570d4..56afe92f3cc 100644
--- a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisStage.qll
+++ b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisStage.qll
@@ -66,7 +66,12 @@
private import RangeUtils as Utils
private import SignAnalysisCommon
private import ModulusAnalysis
-private import experimental.semmle.code.cpp.semantic.Semantic
+import experimental.semmle.code.cpp.semantic.SemanticExpr
+import experimental.semmle.code.cpp.semantic.SemanticSSA
+import experimental.semmle.code.cpp.semantic.SemanticGuard
+import experimental.semmle.code.cpp.semantic.SemanticCFG
+import experimental.semmle.code.cpp.semantic.SemanticType
+import experimental.semmle.code.cpp.semantic.SemanticOpcode
private import ConstantAnalysis
/**
@@ -222,7 +227,19 @@ signature module UtilSig {
SemType getTrackedType(SemExpr e);
}
-module RangeStage LangParam, UtilSig UtilParam> {
+signature module BoundSig {
+ class SemBound {
+ SemExpr getExpr(D::Delta delta);
+ }
+ class SemZeroBound extends SemBound;
+ class SemSsaBound extends SemBound {
+ SemSsaVariable getAVariable();
+ }
+}
+
+module RangeStage Bounds, LangSig LangParam, UtilSig UtilParam> {
+ import Bounds // TODO: remove this import?
+
/**
* An expression that does conversion, boxing, or unboxing
*/
@@ -270,7 +287,7 @@ module RangeStage LangParam, UtilSig UtilParam> {
private import SignAnalysisInstantiated
- private module ModulusAnalysisInstantiated = ModulusAnalysis; // TODO: will this cause reevaluation if it's instantiated with the same DeltaSig and UtilParam multiple times?
+ private module ModulusAnalysisInstantiated = ModulusAnalysis; // TODO: will this cause reevaluation if it's instantiated with the same DeltaSig and UtilParam multiple times?
private import ModulusAnalysisInstantiated
@@ -906,7 +923,7 @@ module RangeStage LangParam, UtilSig UtilParam> {
) {
not Specific::ignoreExprBound(e) and
(
- e = b.getExpr(delta) and
+ e = b.getExpr(D::fromFloat(delta)) and
(upper = true or upper = false) and
fromBackEdge = false and
origdelta = delta and
From 6db728190ef4b08ef4fac94f456bda2677922e38 Mon Sep 17 00:00:00 2001
From: Robert Marsh
Date: Mon, 19 Dec 2022 12:38:57 -0500
Subject: [PATCH 252/381] C++: autoformat
---
.../code/cpp/semantic/analysis/FloatDelta.qll | 37 +++++++++----------
.../cpp/semantic/analysis/ModulusAnalysis.qll | 4 +-
.../semantic/analysis/RangeAnalysisStage.qll | 2 +
.../code/cpp/semantic/analysis/RangeUtils.qll | 4 +-
4 files changed, 26 insertions(+), 21 deletions(-)
diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/FloatDelta.qll b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/FloatDelta.qll
index 1fe1f59eef8..7011f52a1b0 100644
--- a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/FloatDelta.qll
+++ b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/FloatDelta.qll
@@ -1,22 +1,21 @@
private import RangeAnalysisStage
module FloatDelta implements DeltaSig {
- class Delta = float;
-
- bindingset[d]
- bindingset[result]
- float toFloat(Delta d) {result = d}
-
- bindingset[d]
- bindingset[result]
- int toInt(Delta d) {result = d}
-
-
- bindingset[n]
- bindingset[result] Delta fromInt(int n) {result = n}
-
-
- bindingset[f]
- bindingset[result] Delta fromFloat(float f) {result = f}
- }
-
\ No newline at end of file
+ class Delta = float;
+
+ bindingset[d]
+ bindingset[result]
+ float toFloat(Delta d) { result = d }
+
+ bindingset[d]
+ bindingset[result]
+ int toInt(Delta d) { result = d }
+
+ bindingset[n]
+ bindingset[result]
+ Delta fromInt(int n) { result = n }
+
+ bindingset[f]
+ bindingset[result]
+ Delta fromFloat(float f) { result = f }
+}
diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/ModulusAnalysis.qll b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/ModulusAnalysis.qll
index 562e60db408..acb5436e9c9 100644
--- a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/ModulusAnalysis.qll
+++ b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/ModulusAnalysis.qll
@@ -169,7 +169,9 @@ module ModulusAnalysis Bounds, UtilSig U> {
* Holds if all inputs to `phi` numbered `1` to `rix` are equal to `b + val` modulo `mod`.
*/
pragma[nomagic]
- private predicate phiModulusRankStep(SemSsaPhiNode phi, Bounds::SemBound b, int val, int mod, int rix) {
+ private predicate phiModulusRankStep(
+ SemSsaPhiNode phi, Bounds::SemBound b, int val, int mod, int rix
+ ) {
/*
* base case. If any phi input is equal to `b + val` modulo `mod`, that's a potential congruence
* class for the phi node.
diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisStage.qll b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisStage.qll
index 56afe92f3cc..7fd051aed7e 100644
--- a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisStage.qll
+++ b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisStage.qll
@@ -231,7 +231,9 @@ signature module BoundSig {
class SemBound {
SemExpr getExpr(D::Delta delta);
}
+
class SemZeroBound extends SemBound;
+
class SemSsaBound extends SemBound {
SemSsaVariable getAVariable();
}
diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeUtils.qll b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeUtils.qll
index bc10fe156be..a2d10cdab30 100644
--- a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeUtils.qll
+++ b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeUtils.qll
@@ -49,7 +49,9 @@ module RangeUtil Lang> implements Range::Ut
* - `isEq = true` : `v == e + delta`
* - `isEq = false` : `v != e + delta`
*/
- SemGuard semEqFlowCond(SemSsaVariable v, SemExpr e, D::Delta delta, boolean isEq, boolean testIsTrue) {
+ SemGuard semEqFlowCond(
+ SemSsaVariable v, SemExpr e, D::Delta delta, boolean isEq, boolean testIsTrue
+ ) {
exists(boolean eqpolarity |
result.isEquality(semSsaRead(v, delta), e, eqpolarity) and
(testIsTrue = true or testIsTrue = false) and
From 23281410e3acfc095b8500f5a906ab340cbeab98 Mon Sep 17 00:00:00 2001
From: Robert Marsh
Date: Tue, 20 Dec 2022 10:13:48 -0500
Subject: [PATCH 253/381] C++: Make bounds import private to preserve API
---
.../semmle/code/cpp/semantic/analysis/RangeAnalysisStage.qll | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisStage.qll b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisStage.qll
index 7fd051aed7e..7a2a3f6efbf 100644
--- a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisStage.qll
+++ b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisStage.qll
@@ -240,7 +240,7 @@ signature module BoundSig {
}
module RangeStage Bounds, LangSig LangParam, UtilSig UtilParam> {
- import Bounds // TODO: remove this import?
+ private import Bounds // TODO: remove this import?
/**
* An expression that does conversion, boxing, or unboxing
From 488368ecde435bb84881c85650e5f077017d8228 Mon Sep 17 00:00:00 2001
From: Robert Marsh
Date: Tue, 3 Jan 2023 12:35:40 -0500
Subject: [PATCH 254/381] C++: private import for module params
---
.../semantic/analysis/RangeAnalysisStage.qll | 61 ++++++++++---------
1 file changed, 31 insertions(+), 30 deletions(-)
diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisStage.qll b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisStage.qll
index 7a2a3f6efbf..1fa1f76bc63 100644
--- a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisStage.qll
+++ b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisStage.qll
@@ -240,7 +240,10 @@ signature module BoundSig {
}
module RangeStage Bounds, LangSig LangParam, UtilSig UtilParam> {
- private import Bounds // TODO: remove this import?
+ private import Bounds
+ private import LangParam
+ private import UtilParam
+ private import D
/**
* An expression that does conversion, boxing, or unboxing
@@ -264,8 +267,8 @@ module RangeStage Bounds, LangSig LangParam, UtilSig<
*/
private class SafeCastExpr extends ConvertOrBoxExpr {
SafeCastExpr() {
- conversionCannotOverflow(UtilParam::getTrackedType(pragma[only_bind_into](getOperand())),
- UtilParam::getTrackedType(this))
+ conversionCannotOverflow(getTrackedType(pragma[only_bind_into](getOperand())),
+ getTrackedType(this))
}
}
@@ -275,14 +278,14 @@ module RangeStage Bounds, LangSig LangParam, UtilSig<
private class NarrowingCastExpr extends ConvertOrBoxExpr {
NarrowingCastExpr() {
not this instanceof SafeCastExpr and
- typeBound(UtilParam::getTrackedType(this), _, _)
+ typeBound(getTrackedType(this), _, _)
}
/** Gets the lower bound of the resulting type. */
- int getLowerBound() { typeBound(UtilParam::getTrackedType(this), result, _) }
+ int getLowerBound() { typeBound(getTrackedType(this), result, _) }
/** Gets the upper bound of the resulting type. */
- int getUpperBound() { typeBound(UtilParam::getTrackedType(this), _, result) }
+ int getUpperBound() { typeBound(getTrackedType(this), _, result) }
}
private module SignAnalysisInstantiated = SignAnalysis; // TODO: will this cause reevaluation if it's instantiated with the same DeltaSig and UtilParam multiple times?
@@ -318,7 +321,7 @@ module RangeStage Bounds, LangSig LangParam, UtilSig<
*/
cached
predicate possibleReason(SemGuard guard) {
- guard = boundFlowCond(_, _, _, _, _) or guard = UtilParam::semEqFlowCond(_, _, _, _, _)
+ guard = boundFlowCond(_, _, _, _, _) or guard = semEqFlowCond(_, _, _, _, _)
}
}
@@ -346,11 +349,11 @@ module RangeStage Bounds, LangSig LangParam, UtilSig<
private predicate boundCondition(
SemRelationalExpr comp, SemSsaVariable v, SemExpr e, float delta, boolean upper
) {
- comp.getLesserOperand() = UtilParam::semSsaRead(v, D::fromFloat(delta)) and
+ comp.getLesserOperand() = semSsaRead(v, fromFloat(delta)) and
e = comp.getGreaterOperand() and
upper = true
or
- comp.getGreaterOperand() = UtilParam::semSsaRead(v, D::fromFloat(delta)) and
+ comp.getGreaterOperand() = semSsaRead(v, fromFloat(delta)) and
e = comp.getLesserOperand() and
upper = false
or
@@ -358,7 +361,7 @@ module RangeStage Bounds, LangSig LangParam, UtilSig<
// (v - d) - e < c
comp.getLesserOperand() = sub and
comp.getGreaterOperand() = c and
- sub.getLeftOperand() = UtilParam::semSsaRead(v, D::fromFloat(d)) and
+ sub.getLeftOperand() = semSsaRead(v, fromFloat(d)) and
sub.getRightOperand() = e and
upper = true and
delta = d + c.getIntValue()
@@ -366,7 +369,7 @@ module RangeStage Bounds, LangSig LangParam, UtilSig<
// (v - d) - e > c
comp.getGreaterOperand() = sub and
comp.getLesserOperand() = c and
- sub.getLeftOperand() = UtilParam::semSsaRead(v, D::fromFloat(d)) and
+ sub.getLeftOperand() = semSsaRead(v, fromFloat(d)) and
sub.getRightOperand() = e and
upper = false and
delta = d + c.getIntValue()
@@ -375,7 +378,7 @@ module RangeStage Bounds, LangSig LangParam, UtilSig<
comp.getLesserOperand() = sub and
comp.getGreaterOperand() = c and
sub.getLeftOperand() = e and
- sub.getRightOperand() = UtilParam::semSsaRead(v, D::fromFloat(d)) and
+ sub.getRightOperand() = semSsaRead(v, fromFloat(d)) and
upper = false and
delta = d - c.getIntValue()
or
@@ -383,7 +386,7 @@ module RangeStage Bounds, LangSig LangParam, UtilSig<
comp.getGreaterOperand() = sub and
comp.getLesserOperand() = c and
sub.getLeftOperand() = e and
- sub.getRightOperand() = UtilParam::semSsaRead(v, D::fromFloat(d)) and
+ sub.getRightOperand() = semSsaRead(v, fromFloat(d)) and
upper = true and
delta = d - c.getIntValue()
)
@@ -453,8 +456,8 @@ module RangeStage Bounds, LangSig LangParam, UtilSig<
) and
(
if
- UtilParam::getTrackedTypeForSsaVariable(v) instanceof SemIntegerType or
- UtilParam::getTrackedTypeForSsaVariable(v) instanceof SemAddressType
+ getTrackedTypeForSsaVariable(v) instanceof SemIntegerType or
+ getTrackedTypeForSsaVariable(v) instanceof SemAddressType
then
upper = true and strengthen = -1
or
@@ -479,7 +482,7 @@ module RangeStage Bounds, LangSig LangParam, UtilSig<
semImplies_v2(result, testIsTrue, boundFlowCond(v, e, delta, upper, testIsTrue0), testIsTrue0)
)
or
- result = UtilParam::semEqFlowCond(v, e, D::fromFloat(delta), true, testIsTrue) and
+ result = semEqFlowCond(v, e, fromFloat(delta), true, testIsTrue) and
(upper = true or upper = false)
or
// guard that tests whether `v2` is bounded by `e + delta + d1 - d2` and
@@ -487,9 +490,7 @@ module RangeStage Bounds, LangSig LangParam, UtilSig<
exists(
SemSsaVariable v2, SemGuard guardEq, boolean eqIsTrue, float d1, float d2, float oldDelta
|
- guardEq =
- UtilParam::semEqFlowCond(v, UtilParam::semSsaRead(v2, D::fromFloat(d1)), D::fromFloat(d2),
- true, eqIsTrue) and
+ guardEq = semEqFlowCond(v, semSsaRead(v2, fromFloat(d1)), fromFloat(d2), true, eqIsTrue) and
result = boundFlowCond(v2, e, oldDelta, upper, testIsTrue) and
// guardEq needs to control guard
guardEq.directlyControls(result.getBasicBlock(), eqIsTrue) and
@@ -536,7 +537,7 @@ module RangeStage Bounds, LangSig LangParam, UtilSig<
SemSsaVariable v, SemSsaReadPosition pos, SemExpr e, float delta, boolean upper,
SemReason reason
) {
- UtilParam::semSsaUpdateStep(v, e, D::fromFloat(delta)) and
+ semSsaUpdateStep(v, e, fromFloat(delta)) and
pos.hasReadOfVar(v) and
(upper = true or upper = false) and
reason = TSemNoReason()
@@ -553,10 +554,10 @@ module RangeStage Bounds, LangSig LangParam, UtilSig<
private predicate unequalFlowStepIntegralSsa(
SemSsaVariable v, SemSsaReadPosition pos, SemExpr e, float delta, SemReason reason
) {
- UtilParam::getTrackedTypeForSsaVariable(v) instanceof SemIntegerType and
+ getTrackedTypeForSsaVariable(v) instanceof SemIntegerType and
exists(SemGuard guard, boolean testIsTrue |
pos.hasReadOfVar(v) and
- guard = UtilParam::semEqFlowCond(v, e, D::fromFloat(delta), false, testIsTrue) and
+ guard = semEqFlowCond(v, e, fromFloat(delta), false, testIsTrue) and
semGuardDirectlyControlsSsaRead(guard, pos, testIsTrue) and
reason = TSemCondReason(guard)
)
@@ -564,12 +565,12 @@ module RangeStage Bounds, LangSig LangParam, UtilSig<
/** Holds if `e >= 1` as determined by sign analysis. */
private predicate strictlyPositiveIntegralExpr(SemExpr e) {
- semStrictlyPositive(e) and UtilParam::getTrackedType(e) instanceof SemIntegerType
+ semStrictlyPositive(e) and getTrackedType(e) instanceof SemIntegerType
}
/** Holds if `e <= -1` as determined by sign analysis. */
private predicate strictlyNegativeIntegralExpr(SemExpr e) {
- semStrictlyNegative(e) and UtilParam::getTrackedType(e) instanceof SemIntegerType
+ semStrictlyNegative(e) and getTrackedType(e) instanceof SemIntegerType
}
/**
@@ -578,7 +579,7 @@ module RangeStage Bounds, LangSig LangParam, UtilSig<
* - `upper = false` : `e2 >= e1 + delta`
*/
private predicate boundFlowStep(SemExpr e2, SemExpr e1, float delta, boolean upper) {
- UtilParam::semValueFlowStep(e2, e1, D::fromFloat(delta)) and
+ semValueFlowStep(e2, e1, fromFloat(delta)) and
(upper = true or upper = false)
or
e2.(SafeCastExpr).getOperand() = e1 and
@@ -641,7 +642,7 @@ module RangeStage Bounds, LangSig LangParam, UtilSig<
delta = 0 and
upper = false
or
- LangParam::hasBound(e2, e1, D::fromFloat(delta), upper)
+ hasBound(e2, e1, fromFloat(delta), upper)
}
/** Holds if `e2 = e1 * factor` and `factor > 0`. */
@@ -883,13 +884,13 @@ module RangeStage Bounds, LangSig LangParam, UtilSig<
* (for `upper = false`) bound of `b`.
*/
private predicate baseBound(SemExpr e, float b, boolean upper) {
- LangParam::hasConstantBound(e, D::fromFloat(b), upper)
+ hasConstantBound(e, fromFloat(b), upper)
or
upper = false and
b = 0 and
semPositive(e.(SemBitAndExpr).getAnOperand()) and
// REVIEW: We let the language opt out here to preserve original results.
- not LangParam::ignoreZeroLowerBound(e)
+ not ignoreZeroLowerBound(e)
}
/**
@@ -923,9 +924,9 @@ module RangeStage Bounds, LangSig LangParam, UtilSig<
SemExpr e, SemBound b, float delta, boolean upper, boolean fromBackEdge, float origdelta,
SemReason reason
) {
- not Specific::ignoreExprBound(e) and
+ not ignoreExprBound(e) and
(
- e = b.getExpr(D::fromFloat(delta)) and
+ e = b.getExpr(fromFloat(delta)) and
(upper = true or upper = false) and
fromBackEdge = false and
origdelta = delta and
From 7586762b103a942a0e93aa603e3d597717f4f8fb Mon Sep 17 00:00:00 2001
From: Robert Marsh
Date: Tue, 3 Jan 2023 17:55:12 -0500
Subject: [PATCH 255/381] C++: fix ambiguous import warnings
---
.../semmle/code/cpp/semantic/analysis/RangeAnalysis.qll | 2 +-
.../semmle/code/cpp/semantic/analysis/RangeAnalysisSpecific.qll | 2 +-
.../semmle/code/cpp/semantic/analysis/RangeAnalysisStage.qll | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysis.qll b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysis.qll
index 6a4b209bb4b..50d604dee97 100644
--- a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysis.qll
+++ b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysis.qll
@@ -1,6 +1,6 @@
private import RangeAnalysisStage
private import RangeAnalysisSpecific
-private import FloatDelta
+private import experimental.semmle.code.cpp.semantic.analysis.FloatDelta
private import RangeUtils
private import experimental.semmle.code.cpp.semantic.SemanticBound as SemanticBound
diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisSpecific.qll b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisSpecific.qll
index 8f64d891de2..34d5bca116b 100644
--- a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisSpecific.qll
+++ b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisSpecific.qll
@@ -4,7 +4,7 @@
private import experimental.semmle.code.cpp.semantic.Semantic
private import RangeAnalysisStage
-private import FloatDelta
+private import experimental.semmle.code.cpp.semantic.analysis.FloatDelta
module CppLangImpl implements LangSig {
/**
diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisStage.qll b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisStage.qll
index 1fa1f76bc63..6458fb6a8dc 100644
--- a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisStage.qll
+++ b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisStage.qll
@@ -65,7 +65,7 @@
private import RangeUtils as Utils
private import SignAnalysisCommon
-private import ModulusAnalysis
+private import experimental.semmle.code.cpp.semantic.analysis.ModulusAnalysis
import experimental.semmle.code.cpp.semantic.SemanticExpr
import experimental.semmle.code.cpp.semantic.SemanticSSA
import experimental.semmle.code.cpp.semantic.SemanticGuard
From 938176c9dab3bfbb05becb872aeb60f48daf48ab Mon Sep 17 00:00:00 2001
From: Robert Marsh
Date: Wed, 4 Jan 2023 15:19:33 -0500
Subject: [PATCH 256/381] C++: update test QL for modulus and sign analysis
These now instantiate their respective parameterized modules. No
results change.
---
.../library-tests/ir/modulus-analysis/ModulusAnalysis.ql | 9 ++++++++-
.../test/library-tests/ir/sign-analysis/SignAnalysis.ql | 9 ++++++++-
2 files changed, 16 insertions(+), 2 deletions(-)
diff --git a/cpp/ql/test/library-tests/ir/modulus-analysis/ModulusAnalysis.ql b/cpp/ql/test/library-tests/ir/modulus-analysis/ModulusAnalysis.ql
index 794dbed9628..bb335a0b30f 100644
--- a/cpp/ql/test/library-tests/ir/modulus-analysis/ModulusAnalysis.ql
+++ b/cpp/ql/test/library-tests/ir/modulus-analysis/ModulusAnalysis.ql
@@ -1,9 +1,16 @@
import cpp
import experimental.semmle.code.cpp.semantic.analysis.ModulusAnalysis
import experimental.semmle.code.cpp.semantic.Semantic
+import experimental.semmle.code.cpp.semantic.analysis.RangeUtils
+import experimental.semmle.code.cpp.semantic.analysis.FloatDelta
+import experimental.semmle.code.cpp.semantic.analysis.RangeAnalysisSpecific
+import experimental.semmle.code.cpp.semantic.analysis.RangeAnalysis
import semmle.code.cpp.ir.IR as IR
import TestUtilities.InlineExpectationsTest
+module ModulusAnalysisInstantiated =
+ ModulusAnalysis>;
+
class ModulusAnalysisTest extends InlineExpectationsTest {
ModulusAnalysisTest() { this = "ModulusAnalysisTest" }
@@ -23,7 +30,7 @@ class ModulusAnalysisTest extends InlineExpectationsTest {
private string getAModString(SemExpr e) {
exists(SemBound b, int delta, int mod |
- semExprModulus(e, b, delta, mod) and
+ ModulusAnalysisInstantiated::semExprModulus(e, b, delta, mod) and
result = b.toString() + "," + delta.toString() + "," + mod.toString() and
not (delta = 0 and mod = 0)
)
diff --git a/cpp/ql/test/library-tests/ir/sign-analysis/SignAnalysis.ql b/cpp/ql/test/library-tests/ir/sign-analysis/SignAnalysis.ql
index c41ed2cb200..d4f499fdc61 100644
--- a/cpp/ql/test/library-tests/ir/sign-analysis/SignAnalysis.ql
+++ b/cpp/ql/test/library-tests/ir/sign-analysis/SignAnalysis.ql
@@ -1,9 +1,14 @@
import cpp
import experimental.semmle.code.cpp.semantic.analysis.SignAnalysisCommon
import experimental.semmle.code.cpp.semantic.Semantic
+import experimental.semmle.code.cpp.semantic.analysis.RangeUtils
+import experimental.semmle.code.cpp.semantic.analysis.FloatDelta
+import experimental.semmle.code.cpp.semantic.analysis.RangeAnalysisSpecific
import semmle.code.cpp.ir.IR as IR
import TestUtilities.InlineExpectationsTest
+module SignAnalysisInstantiated = SignAnalysis>;
+
class SignAnalysisTest extends InlineExpectationsTest {
SignAnalysisTest() { this = "SignAnalysisTest" }
@@ -21,4 +26,6 @@ class SignAnalysisTest extends InlineExpectationsTest {
}
}
-private string getASignString(SemExpr e) { result = strictconcat(semExprSign(e).toString(), "") }
+private string getASignString(SemExpr e) {
+ result = strictconcat(SignAnalysisInstantiated::semExprSign(e).toString(), "")
+}
From 31b61b1aa630ae1243443a927685345e2f4486de Mon Sep 17 00:00:00 2001
From: Robert Marsh
Date: Mon, 9 Jan 2023 13:56:24 -0500
Subject: [PATCH 257/381] C++: fix a join order in range analysis
---
.../semmle/code/cpp/semantic/analysis/RangeAnalysisStage.qll | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisStage.qll b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisStage.qll
index 6458fb6a8dc..2cf224ac785 100644
--- a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisStage.qll
+++ b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisStage.qll
@@ -268,7 +268,7 @@ module RangeStage Bounds, LangSig LangParam, UtilSig<
private class SafeCastExpr extends ConvertOrBoxExpr {
SafeCastExpr() {
conversionCannotOverflow(getTrackedType(pragma[only_bind_into](getOperand())),
- getTrackedType(this))
+ pragma[only_bind_out](getTrackedType(this)))
}
}
From b2b45237c63ec3235958e35e83447ad9566b041c Mon Sep 17 00:00:00 2001
From: Robert Marsh
Date: Tue, 10 Jan 2023 14:01:32 -0500
Subject: [PATCH 258/381] C++: use rounding to prevent float wobble in range
analysis
---
.../code/cpp/semantic/analysis/FloatDelta.qll | 3 +-
.../analysis/RangeAnalysisSpecific.qll | 1 +
.../semantic/analysis/RangeAnalysisStage.qll | 240 ++++++++++--------
.../code/cpp/semantic/analysis/RangeUtils.qll | 6 +-
4 files changed, 137 insertions(+), 113 deletions(-)
diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/FloatDelta.qll b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/FloatDelta.qll
index 7011f52a1b0..52863821782 100644
--- a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/FloatDelta.qll
+++ b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/FloatDelta.qll
@@ -16,6 +16,5 @@ module FloatDelta implements DeltaSig {
Delta fromInt(int n) { result = n }
bindingset[f]
- bindingset[result]
- Delta fromFloat(float f) { result = f }
+ Delta fromFloat(float f) { result = min(float diff, float res | diff = (res - f).abs() and res = f.ceil() or diff = (f - res).abs() and res = f.floor() | res order by diff )}
}
diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisSpecific.qll b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisSpecific.qll
index 34d5bca116b..1450ea7b528 100644
--- a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisSpecific.qll
+++ b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisSpecific.qll
@@ -5,6 +5,7 @@
private import experimental.semmle.code.cpp.semantic.Semantic
private import RangeAnalysisStage
private import experimental.semmle.code.cpp.semantic.analysis.FloatDelta
+private import experimental.semmle.code.cpp.semantic.analysis.IntDelta
module CppLangImpl implements LangSig {
/**
diff --git a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisStage.qll b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisStage.qll
index 2cf224ac785..e782a0bbda5 100644
--- a/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisStage.qll
+++ b/cpp/ql/lib/experimental/semmle/code/cpp/semantic/analysis/RangeAnalysisStage.qll
@@ -110,7 +110,7 @@ signature module DeltaSig {
Delta fromInt(int n);
bindingset[f]
- bindingset[result]
+ //bindingset[result]
Delta fromFloat(float f);
}
@@ -268,7 +268,7 @@ module RangeStage Bounds, LangSig LangParam, UtilSig<
private class SafeCastExpr extends ConvertOrBoxExpr {
SafeCastExpr() {
conversionCannotOverflow(getTrackedType(pragma[only_bind_into](getOperand())),
- pragma[only_bind_out](getTrackedType(this)))
+ pragma[only_bind_out](getTrackedType(this)))
}
}
@@ -310,7 +310,7 @@ module RangeStage Bounds, LangSig LangParam, UtilSig<
* condition.
*/
cached
- predicate semBounded(SemExpr e, SemBound b, float delta, boolean upper, SemReason reason) {
+ predicate semBounded(SemExpr e, SemBound b, D::Delta delta, boolean upper, SemReason reason) {
bounded(e, b, delta, upper, _, _, reason) and
bestBound(e, b, delta, upper)
}
@@ -333,11 +333,11 @@ module RangeStage Bounds, LangSig LangParam, UtilSig<
* - `upper = true` : `e <= b + delta`
* - `upper = false` : `e >= b + delta`
*/
- private predicate bestBound(SemExpr e, SemBound b, float delta, boolean upper) {
- delta = min(float d | bounded(e, b, d, upper, _, _, _)) and
+ private predicate bestBound(SemExpr e, SemBound b, D::Delta delta, boolean upper) {
+ delta = min(D::Delta d | bounded(e, b, d, upper, _, _, _) | d order by D::toFloat(d)) and
upper = true
or
- delta = max(float d | bounded(e, b, d, upper, _, _, _)) and
+ delta = max(D::Delta d | bounded(e, b, d, upper, _, _, _) | d order by D::toFloat(d)) and
upper = false
}
@@ -347,48 +347,48 @@ module RangeStage Bounds, LangSig LangParam, UtilSig<
* - `upper = false` : `v >= e + delta` or `v > e + delta`
*/
private predicate boundCondition(
- SemRelationalExpr comp, SemSsaVariable v, SemExpr e, float delta, boolean upper
+ SemRelationalExpr comp, SemSsaVariable v, SemExpr e, D::Delta delta, boolean upper
) {
- comp.getLesserOperand() = semSsaRead(v, fromFloat(delta)) and
+ comp.getLesserOperand() = semSsaRead(v, delta) and
e = comp.getGreaterOperand() and
upper = true
or
- comp.getGreaterOperand() = semSsaRead(v, fromFloat(delta)) and
+ comp.getGreaterOperand() = semSsaRead(v, delta) and
e = comp.getLesserOperand() and
upper = false
or
- exists(SemSubExpr sub, SemConstantIntegerExpr c, float d |
+ exists(SemSubExpr sub, SemConstantIntegerExpr c, D::Delta d |
// (v - d) - e < c
comp.getLesserOperand() = sub and
comp.getGreaterOperand() = c and
- sub.getLeftOperand() = semSsaRead(v, fromFloat(d)) and
+ sub.getLeftOperand() = semSsaRead(v, d) and
sub.getRightOperand() = e and
upper = true and
- delta = d + c.getIntValue()
+ delta = D::fromFloat(D::toFloat(d) + c.getIntValue())
or
// (v - d) - e > c
comp.getGreaterOperand() = sub and
comp.getLesserOperand() = c and
- sub.getLeftOperand() = semSsaRead(v, fromFloat(d)) and
+ sub.getLeftOperand() = semSsaRead(v, d) and
sub.getRightOperand() = e and
upper = false and
- delta = d + c.getIntValue()
+ delta = D::fromFloat(D::toFloat(d) + c.getIntValue())
or
// e - (v - d) < c
comp.getLesserOperand() = sub and
comp.getGreaterOperand() = c and
sub.getLeftOperand() = e and
- sub.getRightOperand() = semSsaRead(v, fromFloat(d)) and
+ sub.getRightOperand() = semSsaRead(v, d) and
upper = false and
- delta = d - c.getIntValue()
+ delta = D::fromFloat(D::toFloat(d) - c.getIntValue())
or
// e - (v - d) > c
comp.getGreaterOperand() = sub and
comp.getLesserOperand() = c and
sub.getLeftOperand() = e and
- sub.getRightOperand() = semSsaRead(v, fromFloat(d)) and
+ sub.getRightOperand() = semSsaRead(v, d) and
upper = true and
- delta = d - c.getIntValue()
+ delta = D::fromFloat(D::toFloat(d) - c.getIntValue())
)
}
@@ -439,10 +439,10 @@ module RangeStage Bounds, LangSig LangParam, UtilSig<
* - `upper = false` : `v >= e + delta`
*/
private SemGuard boundFlowCond(
- SemSsaVariable v, SemExpr e, float delta, boolean upper, boolean testIsTrue
+ SemSsaVariable v, SemExpr e, D::Delta delta, boolean upper, boolean testIsTrue
) {
exists(
- SemRelationalExpr comp, float d1, float d2, float d3, int strengthen, boolean compIsUpper,
+ SemRelationalExpr comp, D::Delta d1, float d2, float d3, int strengthen, boolean compIsUpper,
boolean resultIsStrict
|
comp = result.asExpr() and
@@ -475,26 +475,27 @@ module RangeStage Bounds, LangSig LangParam, UtilSig<
or
resultIsStrict = false and d3 = 0
) and
- delta = d1 + d2 + d3
+ delta = D::fromFloat(D::toFloat(d1) + d2 + d3)
)
or
exists(boolean testIsTrue0 |
semImplies_v2(result, testIsTrue, boundFlowCond(v, e, delta, upper, testIsTrue0), testIsTrue0)
)
or
- result = semEqFlowCond(v, e, fromFloat(delta), true, testIsTrue) and
+ result = semEqFlowCond(v, e, delta, true, testIsTrue) and
(upper = true or upper = false)
or
// guard that tests whether `v2` is bounded by `e + delta + d1 - d2` and
// exists a guard `guardEq` such that `v = v2 - d1 + d2`.
exists(
- SemSsaVariable v2, SemGuard guardEq, boolean eqIsTrue, float d1, float d2, float oldDelta
+ SemSsaVariable v2, SemGuard guardEq, boolean eqIsTrue, D::Delta d1, D::Delta d2,
+ D::Delta oldDelta
|
- guardEq = semEqFlowCond(v, semSsaRead(v2, fromFloat(d1)), fromFloat(d2), true, eqIsTrue) and
+ guardEq = semEqFlowCond(v, semSsaRead(v2, d1), d2, true, eqIsTrue) and
result = boundFlowCond(v2, e, oldDelta, upper, testIsTrue) and
// guardEq needs to control guard
guardEq.directlyControls(result.getBasicBlock(), eqIsTrue) and
- delta = oldDelta - d1 + d2
+ delta = D::fromFloat(D::toFloat(oldDelta) - D::toFloat(d1) + D::toFloat(d2))
)
}
@@ -534,10 +535,10 @@ module RangeStage Bounds, LangSig LangParam, UtilSig<
* - `upper = false` : `v >= e + delta`
*/
private predicate boundFlowStepSsa(
- SemSsaVariable v, SemSsaReadPosition pos, SemExpr e, float delta, boolean upper,
+ SemSsaVariable v, SemSsaReadPosition pos, SemExpr e, D::Delta delta, boolean upper,
SemReason reason
) {
- semSsaUpdateStep(v, e, fromFloat(delta)) and
+ semSsaUpdateStep(v, e, delta) and
pos.hasReadOfVar(v) and
(upper = true or upper = false) and
reason = TSemNoReason()
@@ -552,12 +553,12 @@ module RangeStage Bounds, LangSig LangParam, UtilSig<
/** Holds if `v != e + delta` at `pos` and `v` is of integral type. */
private predicate unequalFlowStepIntegralSsa(
- SemSsaVariable v, SemSsaReadPosition pos, SemExpr e, float delta, SemReason reason
+ SemSsaVariable v, SemSsaReadPosition pos, SemExpr e, D::Delta delta, SemReason reason
) {
getTrackedTypeForSsaVariable(v) instanceof SemIntegerType and
exists(SemGuard guard, boolean testIsTrue |
pos.hasReadOfVar(v) and
- guard = semEqFlowCond(v, e, fromFloat(delta), false, testIsTrue) and
+ guard = semEqFlowCond(v, e, delta, false, testIsTrue) and
semGuardDirectlyControlsSsaRead(guard, pos, testIsTrue) and
reason = TSemCondReason(guard)
)
@@ -578,12 +579,12 @@ module RangeStage Bounds, LangSig LangParam, UtilSig<
* - `upper = true` : `e2 <= e1 + delta`
* - `upper = false` : `e2 >= e1 + delta`
*/
- private predicate boundFlowStep(SemExpr e2, SemExpr e1, float delta, boolean upper) {
- semValueFlowStep(e2, e1, fromFloat(delta)) and
+ private predicate boundFlowStep(SemExpr e2, SemExpr e1, D::Delta delta, boolean upper) {
+ semValueFlowStep(e2, e1, delta) and
(upper = true or upper = false)
or
e2.(SafeCastExpr).getOperand() = e1 and
- delta = 0 and
+ delta = D::fromInt(0) and
(upper = true or upper = false)
or
exists(SemExpr x | e2.(SemAddExpr).hasOperands(e1, x) |
@@ -591,16 +592,16 @@ module RangeStage Bounds, LangSig LangParam, UtilSig<
not x instanceof SemConstantIntegerExpr and
not e1 instanceof SemConstantIntegerExpr and
if strictlyPositiveIntegralExpr(x)
- then upper = false and delta = 1
+ then upper = false and delta = D::fromInt(1)
else
if semPositive(x)
- then upper = false and delta = 0
+ then upper = false and delta = D::fromInt(0)
else
if strictlyNegativeIntegralExpr(x)
- then upper = true and delta = -1
+ then upper = true and delta = D::fromInt(-1)
else
if semNegative(x)
- then upper = true and delta = 0
+ then upper = true and delta = D::fromInt(0)
else none()
)
or
@@ -612,46 +613,52 @@ module RangeStage Bounds, LangSig LangParam, UtilSig<
// `x instanceof ConstantIntegerExpr` is covered by valueFlowStep
not x instanceof SemConstantIntegerExpr and
if strictlyPositiveIntegralExpr(x)
- then upper = true and delta = -1
+ then upper = true and delta = D::fromInt(-1)
else
if semPositive(x)
- then upper = true and delta = 0
+ then upper = true and delta = D::fromInt(0)
else
if strictlyNegativeIntegralExpr(x)
- then upper = false and delta = 1
+ then upper = false and delta = D::fromInt(1)
else
if semNegative(x)
- then upper = false and delta = 0
+ then upper = false and delta = D::fromInt(0)
else none()
)
or
e2.(SemRemExpr).getRightOperand() = e1 and
semPositive(e1) and
- delta = -1 and
+ delta = D::fromInt(-1) and
upper = true
or
- e2.(SemRemExpr).getLeftOperand() = e1 and semPositive(e1) and delta = 0 and upper = true
+ e2.(SemRemExpr).getLeftOperand() = e1 and
+ semPositive(e1) and
+ delta = D::fromInt(0) and
+ upper = true
or
e2.(SemBitAndExpr).getAnOperand() = e1 and
semPositive(e1) and
- delta = 0 and
+ delta = D::fromInt(0) and
upper = true
or
e2.(SemBitOrExpr).getAnOperand() = e1 and
semPositive(e2) and
- delta = 0 and
+ delta = D::fromInt(0) and
upper = false
or
- hasBound(e2, e1, fromFloat(delta), upper)
+ hasBound(e2, e1, delta, upper)
}
/** Holds if `e2 = e1 * factor` and `factor > 0`. */
- private predicate boundFlowStepMul(SemExpr e2, SemExpr e1, float factor) {
+ private predicate boundFlowStepMul(SemExpr e2, SemExpr e1, D::Delta factor) {
exists(SemConstantIntegerExpr c, int k | k = c.getIntValue() and k > 0 |
- e2.(SemMulExpr).hasOperands(e1, c) and factor = k
+ e2.(SemMulExpr).hasOperands(e1, c) and factor = D::fromInt(k)
or
exists(SemShiftLeftExpr e |
- e = e2 and e.getLeftOperand() = e1 and e.getRightOperand() = c and factor = 2.pow(k)
+ e = e2 and
+ e.getLeftOperand() = e1 and
+ e.getRightOperand() = c and
+ factor = D::fromInt(2.pow(k))
)
)
}
@@ -662,18 +669,26 @@ module RangeStage Bounds, LangSig LangParam, UtilSig<
* This conflates division, right shift, and unsigned right shift and is
* therefore only valid for non-negative numbers.
*/
- private predicate boundFlowStepDiv(SemExpr e2, SemExpr e1, float factor) {
- exists(SemConstantIntegerExpr c, float k | k = c.getIntValue() and k > 0 |
+ private predicate boundFlowStepDiv(SemExpr e2, SemExpr e1, D::Delta factor) {
+ exists(SemConstantIntegerExpr c, D::Delta k |
+ k = D::fromInt(c.getIntValue()) and D::toFloat(k) > 0
+ |
exists(SemDivExpr e |
e = e2 and e.getLeftOperand() = e1 and e.getRightOperand() = c and factor = k
)
or
exists(SemShiftRightExpr e |
- e = e2 and e.getLeftOperand() = e1 and e.getRightOperand() = c and factor = 2.pow(k)
+ e = e2 and
+ e.getLeftOperand() = e1 and
+ e.getRightOperand() = c and
+ factor = D::fromInt(2.pow(D::toInt(k)))
)
or
exists(SemShiftRightUnsignedExpr e |
- e = e2 and e.getLeftOperand() = e1 and e.getRightOperand() = c and factor = 2.pow(k)
+ e = e2 and
+ e.getLeftOperand() = e1 and
+ e.getRightOperand() = c and
+ factor = D::fromInt(2.pow(D::toInt(k)))
)
)
}
@@ -684,27 +699,27 @@ module RangeStage Bounds, LangSig LangParam, UtilSig<
* - `upper = false` : `v >= b + delta`
*/
private predicate boundedSsa(
- SemSsaVariable v, SemSsaReadPosition pos, SemBound b, float delta, boolean upper,
- boolean fromBackEdge, float origdelta, SemReason reason
+ SemSsaVariable v, SemSsaReadPosition pos, SemBound b, D::Delta delta, boolean upper,
+ boolean fromBackEdge, D::Delta origdelta, SemReason reason
) {
- exists(SemExpr mid, float d1, float d2, SemReason r1, SemReason r2 |
+ exists(SemExpr mid, D::Delta d1, D::Delta d2, SemReason r1, SemReason r2 |
boundFlowStepSsa(v, pos, mid, d1, upper, r1) and
bounded(mid, b, d2, upper, fromBackEdge, origdelta, r2) and
// upper = true: v <= mid + d1 <= b + d1 + d2 = b + delta
// upper = false: v >= mid + d1 >= b + d1 + d2 = b + delta
- delta = d1 + d2 and
+ delta = D::fromFloat(D::toFloat(d1) + D::toFloat(d2)) and
(if r1 instanceof SemNoReason then reason = r2 else reason = r1)
)
or
- exists(float d, SemReason r1, SemReason r2 |
+ exists(D::Delta d, SemReason r1, SemReason r2 |
boundedSsa(v, pos, b, d, upper, fromBackEdge, origdelta, r2) or
boundedPhi(v, b, d, upper, fromBackEdge, origdelta, r2)
|
unequalIntegralSsa(v, pos, b, d, r1) and
(
- upper = true and delta = d - 1
+ upper = true and delta = D::fromFloat(D::toFloat(d) - 1)
or
- upper = false and delta = d + 1
+ upper = false and delta = D::fromFloat(D::toFloat(d) + 1)
) and
(
reason = r1
@@ -718,13 +733,13 @@ module RangeStage Bounds, LangSig LangParam, UtilSig<
* Holds if `v != b + delta` at `pos` and `v` is of integral type.
*/
private predicate unequalIntegralSsa(
- SemSsaVariable v, SemSsaReadPosition pos, SemBound b, float delta, SemReason reason
+ SemSsaVariable v, SemSsaReadPosition pos, SemBound b, D::Delta delta, SemReason reason
) {
- exists(SemExpr e, float d1, float d2 |
+ exists(SemExpr e, D::Delta d1, D::Delta d2 |
unequalFlowStepIntegralSsa(v, pos, e, d1, reason) and
boundedUpper(e, b, d1) and
boundedLower(e, b, d2) and
- delta = d2 + d1
+ delta = D::fromFloat(D::toFloat(d1) + D::toFloat(d2))
)
}
@@ -734,7 +749,7 @@ module RangeStage Bounds, LangSig